1use alloc::sync::Arc;
2use alloc::vec;
3use core::sync::atomic::Ordering;
4
5use arrayvec::ArrayVec;
6use glow::HasContext;
7
8use super::{conv::is_layered_target, lock, Command as C, PrivateCapabilities};
9
10const DEBUG_ID: u32 = 0;
11
12fn extract_marker<'a>(data: &'a [u8], range: &core::ops::Range<u32>) -> &'a str {
13 core::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap()
14}
15
16fn get_2d_target(target: u32, array_layer: u32) -> u32 {
17 const CUBEMAP_FACES: [u32; 6] = [
18 glow::TEXTURE_CUBE_MAP_POSITIVE_X,
19 glow::TEXTURE_CUBE_MAP_NEGATIVE_X,
20 glow::TEXTURE_CUBE_MAP_POSITIVE_Y,
21 glow::TEXTURE_CUBE_MAP_NEGATIVE_Y,
22 glow::TEXTURE_CUBE_MAP_POSITIVE_Z,
23 glow::TEXTURE_CUBE_MAP_NEGATIVE_Z,
24 ];
25
26 match target {
27 glow::TEXTURE_2D => target,
28 glow::TEXTURE_CUBE_MAP => CUBEMAP_FACES[array_layer as usize],
29 _ => unreachable!(),
30 }
31}
32
33fn get_z_offset(target: u32, base: &crate::TextureCopyBase) -> u32 {
34 match target {
35 glow::TEXTURE_2D_ARRAY | glow::TEXTURE_CUBE_MAP_ARRAY => base.array_layer,
36 glow::TEXTURE_3D => base.origin.z,
37 _ => unreachable!(),
38 }
39}
40
41impl super::Queue {
42 unsafe fn perform_shader_clear(&self, gl: &glow::Context, draw_buffer: u32, color: [f32; 4]) {
44 let shader_clear = self
45 .shader_clear_program
46 .as_ref()
47 .expect("shader_clear_program should always be set if the workaround is enabled");
48 unsafe { gl.use_program(Some(shader_clear.program)) };
49 unsafe {
50 gl.uniform_4_f32(
51 Some(&shader_clear.color_uniform_location),
52 color[0],
53 color[1],
54 color[2],
55 color[3],
56 )
57 };
58 unsafe { gl.disable(glow::DEPTH_TEST) };
59 unsafe { gl.disable(glow::STENCIL_TEST) };
60 unsafe { gl.disable(glow::SCISSOR_TEST) };
61 unsafe { gl.disable(glow::BLEND) };
62 unsafe { gl.disable(glow::CULL_FACE) };
63 unsafe { gl.draw_buffers(&[glow::COLOR_ATTACHMENT0 + draw_buffer]) };
64 unsafe { gl.draw_arrays(glow::TRIANGLES, 0, 3) };
65
66 let draw_buffer_count = self.draw_buffer_count.load(Ordering::Relaxed);
67 if draw_buffer_count != 0 {
68 let indices = (0..draw_buffer_count as u32)
70 .map(|i| glow::COLOR_ATTACHMENT0 + i)
71 .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
72 unsafe { gl.draw_buffers(&indices) };
73 }
74 }
75
76 unsafe fn reset_state(&self, gl: &glow::Context) {
77 unsafe { gl.use_program(None) };
78 unsafe { gl.bind_framebuffer(glow::FRAMEBUFFER, None) };
79 unsafe { gl.disable(glow::DEPTH_TEST) };
80 unsafe { gl.disable(glow::STENCIL_TEST) };
81 unsafe { gl.disable(glow::SCISSOR_TEST) };
82 unsafe { gl.disable(glow::BLEND) };
83 unsafe { gl.disable(glow::CULL_FACE) };
84 unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
85 unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
86 if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
87 unsafe { gl.disable(glow::DEPTH_CLAMP) };
88 }
89
90 unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None) };
91 let mut current_index_buffer = self.current_index_buffer.lock();
92 *current_index_buffer = None;
93 }
94
95 unsafe fn set_attachment(
96 &self,
97 gl: &glow::Context,
98 fbo_target: u32,
99 attachment: u32,
100 view: &super::TextureView,
101 ) {
102 match view.inner {
103 super::TextureInner::Renderbuffer { raw } => {
104 unsafe {
105 gl.framebuffer_renderbuffer(
106 fbo_target,
107 attachment,
108 glow::RENDERBUFFER,
109 Some(raw),
110 )
111 };
112 }
113 super::TextureInner::DefaultRenderbuffer => panic!("Unexpected default RBO"),
114 super::TextureInner::Texture { raw, target } => {
115 let num_layers = view.array_layers.end - view.array_layers.start;
116 if num_layers > 1 {
117 #[cfg(webgl)]
118 unsafe {
119 gl.framebuffer_texture_multiview_ovr(
120 fbo_target,
121 attachment,
122 Some(raw),
123 view.mip_levels.start as i32,
124 view.array_layers.start as i32,
125 num_layers as i32,
126 )
127 };
128 } else if is_layered_target(target) {
129 unsafe {
130 gl.framebuffer_texture_layer(
131 fbo_target,
132 attachment,
133 Some(raw),
134 view.mip_levels.start as i32,
135 view.array_layers.start as i32,
136 )
137 };
138 } else {
139 unsafe {
140 assert_eq!(view.mip_levels.len(), 1);
141 gl.framebuffer_texture_2d(
142 fbo_target,
143 attachment,
144 get_2d_target(target, view.array_layers.start),
145 Some(raw),
146 view.mip_levels.start as i32,
147 )
148 };
149 }
150 }
151 #[cfg(webgl)]
152 super::TextureInner::ExternalFramebuffer { ref inner } => unsafe {
153 gl.bind_external_framebuffer(glow::FRAMEBUFFER, inner);
154 },
155 }
156 }
157
158 unsafe fn process(
159 &self,
160 gl: &glow::Context,
161 command: &C,
162 #[cfg_attr(target_arch = "wasm32", allow(unused))] data_bytes: &[u8],
163 queries: &[glow::Query],
164 ) {
165 match *command {
166 C::Draw {
167 topology,
168 first_vertex,
169 vertex_count,
170 instance_count,
171 first_instance,
172 ref first_instance_location,
173 } => {
174 let supports_full_instancing = self
175 .shared
176 .private_caps
177 .contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING);
178
179 if supports_full_instancing {
180 unsafe {
181 gl.draw_arrays_instanced_base_instance(
182 topology,
183 first_vertex as i32,
184 vertex_count as i32,
185 instance_count as i32,
186 first_instance,
187 )
188 }
189 } else {
190 unsafe {
191 gl.uniform_1_u32(first_instance_location.as_ref(), first_instance);
192 }
193
194 unsafe {
198 gl.draw_arrays_instanced(
199 topology,
200 first_vertex as i32,
201 vertex_count as i32,
202 instance_count as i32,
203 )
204 }
205 };
206 }
207 C::DrawIndexed {
208 topology,
209 index_type,
210 index_count,
211 index_offset,
212 base_vertex,
213 first_instance,
214 instance_count,
215 ref first_instance_location,
216 } => {
217 let supports_full_instancing = self
218 .shared
219 .private_caps
220 .contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING);
221
222 if supports_full_instancing {
223 unsafe {
224 gl.draw_elements_instanced_base_vertex_base_instance(
225 topology,
226 index_count as i32,
227 index_type,
228 index_offset as i32,
229 instance_count as i32,
230 base_vertex,
231 first_instance,
232 )
233 }
234 } else {
235 unsafe { gl.uniform_1_u32(first_instance_location.as_ref(), first_instance) };
236
237 if base_vertex == 0 {
238 unsafe {
239 gl.draw_elements_instanced(
243 topology,
244 index_count as i32,
245 index_type,
246 index_offset as i32,
247 instance_count as i32,
248 )
249 }
250 } else {
251 unsafe {
253 gl.draw_elements_instanced_base_vertex(
254 topology,
255 index_count as _,
256 index_type,
257 index_offset as i32,
258 instance_count as i32,
259 base_vertex,
260 )
261 }
262 }
263 }
264 }
265 C::DrawIndirect {
266 topology,
267 indirect_buf,
268 indirect_offset,
269 ref first_instance_location,
270 } => {
271 unsafe { gl.uniform_1_u32(first_instance_location.as_ref(), 0) };
272
273 unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)) };
274 unsafe { gl.draw_arrays_indirect_offset(topology, indirect_offset as i32) };
275 }
276 C::DrawIndexedIndirect {
277 topology,
278 index_type,
279 indirect_buf,
280 indirect_offset,
281 ref first_instance_location,
282 } => {
283 unsafe { gl.uniform_1_u32(first_instance_location.as_ref(), 0) };
284
285 unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)) };
286 unsafe {
287 gl.draw_elements_indirect_offset(topology, index_type, indirect_offset as i32)
288 };
289 }
290 C::Dispatch(group_counts) => {
291 unsafe { gl.dispatch_compute(group_counts[0], group_counts[1], group_counts[2]) };
292 }
293 C::DispatchIndirect {
294 indirect_buf,
295 indirect_offset,
296 } => {
297 unsafe { gl.bind_buffer(glow::DISPATCH_INDIRECT_BUFFER, Some(indirect_buf)) };
298 unsafe { gl.dispatch_compute_indirect(indirect_offset as i32) };
299 }
300 C::ClearBuffer {
301 ref dst,
302 dst_target,
303 ref range,
304 } => match dst.raw {
305 Some(buffer) => {
306 let can_use_zero_buffer = self
315 .shared
316 .private_caps
317 .contains(PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
318 || dst_target != glow::ELEMENT_ARRAY_BUFFER;
319
320 if can_use_zero_buffer {
321 unsafe { gl.bind_buffer(glow::COPY_READ_BUFFER, Some(self.zero_buffer)) };
322 unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
323 let mut dst_offset = range.start;
324 while dst_offset < range.end {
325 let size = (range.end - dst_offset).min(super::ZERO_BUFFER_SIZE as u64);
326 unsafe {
327 gl.copy_buffer_sub_data(
328 glow::COPY_READ_BUFFER,
329 dst_target,
330 0,
331 dst_offset as i32,
332 size as i32,
333 )
334 };
335 dst_offset += size;
336 }
337 } else {
338 unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
339 let zeroes = vec![0u8; (range.end - range.start) as usize];
340 unsafe {
341 gl.buffer_sub_data_u8_slice(dst_target, range.start as i32, &zeroes)
342 };
343 }
344 }
345 None => {
346 lock(dst.data.as_ref().unwrap()).as_mut_slice()
347 [range.start as usize..range.end as usize]
348 .fill(0);
349 }
350 },
351 C::CopyBufferToBuffer {
352 ref src,
353 src_target,
354 ref dst,
355 dst_target,
356 copy,
357 } => {
358 let copy_src_target = glow::COPY_READ_BUFFER;
359 let is_index_buffer_only_element_dst = !self
360 .shared
361 .private_caps
362 .contains(PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
363 && dst_target == glow::ELEMENT_ARRAY_BUFFER
364 || src_target == glow::ELEMENT_ARRAY_BUFFER;
365
366 let copy_dst_target = if is_index_buffer_only_element_dst {
368 glow::ELEMENT_ARRAY_BUFFER
369 } else {
370 glow::COPY_WRITE_BUFFER
371 };
372 let size = copy.size.get() as usize;
373 match (src.raw, dst.raw) {
374 (Some(ref src), Some(ref dst)) => {
375 unsafe { gl.bind_buffer(copy_src_target, Some(*src)) };
376 unsafe { gl.bind_buffer(copy_dst_target, Some(*dst)) };
377 unsafe {
378 gl.copy_buffer_sub_data(
379 copy_src_target,
380 copy_dst_target,
381 copy.src_offset as _,
382 copy.dst_offset as _,
383 copy.size.get() as _,
384 )
385 };
386 }
387 (Some(src), None) => {
388 let mut data = lock(dst.data.as_ref().unwrap());
389 let dst_data = &mut data.as_mut_slice()
390 [copy.dst_offset as usize..copy.dst_offset as usize + size];
391
392 unsafe { gl.bind_buffer(copy_src_target, Some(src)) };
393 unsafe {
394 self.shared.get_buffer_sub_data(
395 gl,
396 copy_src_target,
397 copy.src_offset as i32,
398 dst_data,
399 )
400 };
401 }
402 (None, Some(dst)) => {
403 let data = lock(src.data.as_ref().unwrap());
404 let src_data = &data.as_slice()
405 [copy.src_offset as usize..copy.src_offset as usize + size];
406 unsafe { gl.bind_buffer(copy_dst_target, Some(dst)) };
407 unsafe {
408 gl.buffer_sub_data_u8_slice(
409 copy_dst_target,
410 copy.dst_offset as i32,
411 src_data,
412 )
413 };
414 }
415 (None, None) => {
416 todo!()
417 }
418 }
419 unsafe { gl.bind_buffer(copy_src_target, None) };
420 if is_index_buffer_only_element_dst {
421 unsafe {
422 gl.bind_buffer(
423 glow::ELEMENT_ARRAY_BUFFER,
424 *self.current_index_buffer.lock(),
425 )
426 };
427 } else {
428 unsafe { gl.bind_buffer(copy_dst_target, None) };
429 }
430 }
431 #[cfg(webgl)]
432 C::CopyExternalImageToTexture {
433 ref src,
434 dst,
435 dst_target,
436 dst_format,
437 dst_premultiplication,
438 ref copy,
439 } => {
440 const UNPACK_FLIP_Y_WEBGL: u32 =
441 web_sys::WebGl2RenderingContext::UNPACK_FLIP_Y_WEBGL;
442 const UNPACK_PREMULTIPLY_ALPHA_WEBGL: u32 =
443 web_sys::WebGl2RenderingContext::UNPACK_PREMULTIPLY_ALPHA_WEBGL;
444
445 unsafe {
446 if src.flip_y {
447 gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, true);
448 }
449 if dst_premultiplication {
450 gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
451 }
452 }
453
454 unsafe { gl.bind_texture(dst_target, Some(dst)) };
455 let format_desc = self.shared.describe_texture_format(dst_format);
456 if is_layered_target(dst_target) {
457 let z_offset = get_z_offset(dst_target, ©.dst_base);
458
459 match src.source {
460 wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
461 gl.tex_sub_image_3d_with_image_bitmap(
462 dst_target,
463 copy.dst_base.mip_level as i32,
464 copy.dst_base.origin.x as i32,
465 copy.dst_base.origin.y as i32,
466 z_offset as i32,
467 copy.size.width as i32,
468 copy.size.height as i32,
469 copy.size.depth as i32,
470 format_desc.external,
471 format_desc.data_type,
472 b,
473 );
474 },
475 wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
476 gl.tex_sub_image_3d_with_html_image_element(
477 dst_target,
478 copy.dst_base.mip_level as i32,
479 copy.dst_base.origin.x as i32,
480 copy.dst_base.origin.y as i32,
481 z_offset as i32,
482 copy.size.width as i32,
483 copy.size.height as i32,
484 copy.size.depth as i32,
485 format_desc.external,
486 format_desc.data_type,
487 i,
488 );
489 },
490 wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
491 gl.tex_sub_image_3d_with_html_video_element(
492 dst_target,
493 copy.dst_base.mip_level as i32,
494 copy.dst_base.origin.x as i32,
495 copy.dst_base.origin.y as i32,
496 z_offset as i32,
497 copy.size.width as i32,
498 copy.size.height as i32,
499 copy.size.depth as i32,
500 format_desc.external,
501 format_desc.data_type,
502 v,
503 );
504 },
505 #[cfg(web_sys_unstable_apis)]
506 wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
507 gl.tex_sub_image_3d_with_video_frame(
508 dst_target,
509 copy.dst_base.mip_level as i32,
510 copy.dst_base.origin.x as i32,
511 copy.dst_base.origin.y as i32,
512 z_offset as i32,
513 copy.size.width as i32,
514 copy.size.height as i32,
515 copy.size.depth as i32,
516 format_desc.external,
517 format_desc.data_type,
518 v,
519 )
520 },
521 wgt::ExternalImageSource::ImageData(ref i) => unsafe {
522 gl.tex_sub_image_3d_with_image_data(
523 dst_target,
524 copy.dst_base.mip_level as i32,
525 copy.dst_base.origin.x as i32,
526 copy.dst_base.origin.y as i32,
527 z_offset as i32,
528 copy.size.width as i32,
529 copy.size.height as i32,
530 copy.size.depth as i32,
531 format_desc.external,
532 format_desc.data_type,
533 i,
534 );
535 },
536 wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
537 gl.tex_sub_image_3d_with_html_canvas_element(
538 dst_target,
539 copy.dst_base.mip_level as i32,
540 copy.dst_base.origin.x as i32,
541 copy.dst_base.origin.y as i32,
542 z_offset as i32,
543 copy.size.width as i32,
544 copy.size.height as i32,
545 copy.size.depth as i32,
546 format_desc.external,
547 format_desc.data_type,
548 c,
549 );
550 },
551 wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
552 }
553 } else {
554 let dst_target = get_2d_target(dst_target, copy.dst_base.array_layer);
555
556 match src.source {
557 wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
558 gl.tex_sub_image_2d_with_image_bitmap_and_width_and_height(
559 dst_target,
560 copy.dst_base.mip_level as i32,
561 copy.dst_base.origin.x as i32,
562 copy.dst_base.origin.y as i32,
563 copy.size.width as i32,
564 copy.size.height as i32,
565 format_desc.external,
566 format_desc.data_type,
567 b,
568 );
569 },
570 wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
571 gl.tex_sub_image_2d_with_html_image_and_width_and_height(
572 dst_target,
573 copy.dst_base.mip_level as i32,
574 copy.dst_base.origin.x as i32,
575 copy.dst_base.origin.y as i32,
576 copy.size.width as i32,
577 copy.size.height as i32,
578 format_desc.external,
579 format_desc.data_type,
580 i,
581 )
582 },
583 wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
584 gl.tex_sub_image_2d_with_html_video_and_width_and_height(
585 dst_target,
586 copy.dst_base.mip_level as i32,
587 copy.dst_base.origin.x as i32,
588 copy.dst_base.origin.y as i32,
589 copy.size.width as i32,
590 copy.size.height as i32,
591 format_desc.external,
592 format_desc.data_type,
593 v,
594 )
595 },
596 #[cfg(web_sys_unstable_apis)]
597 wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
598 gl.tex_sub_image_2d_with_video_frame_and_width_and_height(
599 dst_target,
600 copy.dst_base.mip_level as i32,
601 copy.dst_base.origin.x as i32,
602 copy.dst_base.origin.y as i32,
603 copy.size.width as i32,
604 copy.size.height as i32,
605 format_desc.external,
606 format_desc.data_type,
607 v,
608 )
609 },
610 wgt::ExternalImageSource::ImageData(ref i) => unsafe {
611 gl.tex_sub_image_2d_with_image_data_and_width_and_height(
612 dst_target,
613 copy.dst_base.mip_level as i32,
614 copy.dst_base.origin.x as i32,
615 copy.dst_base.origin.y as i32,
616 copy.size.width as i32,
617 copy.size.height as i32,
618 format_desc.external,
619 format_desc.data_type,
620 i,
621 );
622 },
623 wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
624 gl.tex_sub_image_2d_with_html_canvas_and_width_and_height(
625 dst_target,
626 copy.dst_base.mip_level as i32,
627 copy.dst_base.origin.x as i32,
628 copy.dst_base.origin.y as i32,
629 copy.size.width as i32,
630 copy.size.height as i32,
631 format_desc.external,
632 format_desc.data_type,
633 c,
634 )
635 },
636 wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
637 }
638 }
639
640 unsafe {
641 if src.flip_y {
642 gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, false);
643 }
644 if dst_premultiplication {
645 gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
646 }
647 }
648 }
649 C::CopyTextureToTexture {
650 src,
651 src_target,
652 dst,
653 dst_target,
654 ref copy,
655 } => {
656 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
658 if is_layered_target(src_target) {
659 unsafe {
661 gl.framebuffer_texture_layer(
662 glow::READ_FRAMEBUFFER,
663 glow::COLOR_ATTACHMENT0,
664 Some(src),
665 copy.src_base.mip_level as i32,
666 copy.src_base.array_layer as i32,
667 )
668 };
669 } else {
670 unsafe {
671 gl.framebuffer_texture_2d(
672 glow::READ_FRAMEBUFFER,
673 glow::COLOR_ATTACHMENT0,
674 src_target,
675 Some(src),
676 copy.src_base.mip_level as i32,
677 )
678 };
679 }
680
681 unsafe { gl.bind_texture(dst_target, Some(dst)) };
682 if is_layered_target(dst_target) {
683 unsafe {
684 gl.copy_tex_sub_image_3d(
685 dst_target,
686 copy.dst_base.mip_level as i32,
687 copy.dst_base.origin.x as i32,
688 copy.dst_base.origin.y as i32,
689 get_z_offset(dst_target, ©.dst_base) as i32,
690 copy.src_base.origin.x as i32,
691 copy.src_base.origin.y as i32,
692 copy.size.width as i32,
693 copy.size.height as i32,
694 )
695 };
696 } else {
697 unsafe {
698 gl.copy_tex_sub_image_2d(
699 get_2d_target(dst_target, copy.dst_base.array_layer),
700 copy.dst_base.mip_level as i32,
701 copy.dst_base.origin.x as i32,
702 copy.dst_base.origin.y as i32,
703 copy.src_base.origin.x as i32,
704 copy.src_base.origin.y as i32,
705 copy.size.width as i32,
706 copy.size.height as i32,
707 )
708 };
709 }
710 }
711 C::CopyBufferToTexture {
712 ref src,
713 src_target: _,
714 dst,
715 dst_target,
716 dst_format,
717 ref copy,
718 } => {
719 let (block_width, block_height) = dst_format.block_dimensions();
720 let block_size = dst_format.block_copy_size(None).unwrap();
721 let format_desc = self.shared.describe_texture_format(dst_format);
722 let row_texels = copy
723 .buffer_layout
724 .bytes_per_row
725 .map_or(0, |bpr| block_width * bpr / block_size);
726 let column_texels = copy
727 .buffer_layout
728 .rows_per_image
729 .map_or(0, |rpi| block_height * rpi);
730
731 unsafe { gl.bind_texture(dst_target, Some(dst)) };
732 unsafe { gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32) };
733 unsafe { gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32) };
734 let mut unbind_unpack_buffer = false;
735 if !dst_format.is_compressed() {
736 let buffer_data;
737 let unpack_data = match src.raw {
738 Some(buffer) => {
739 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
740 unbind_unpack_buffer = true;
741 glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32)
742 }
743 None => {
744 buffer_data = lock(src.data.as_ref().unwrap());
745 let src_data =
746 &buffer_data.as_slice()[copy.buffer_layout.offset as usize..];
747 glow::PixelUnpackData::Slice(Some(src_data))
748 }
749 };
750 if is_layered_target(dst_target) {
751 unsafe {
752 gl.tex_sub_image_3d(
753 dst_target,
754 copy.texture_base.mip_level as i32,
755 copy.texture_base.origin.x as i32,
756 copy.texture_base.origin.y as i32,
757 get_z_offset(dst_target, ©.texture_base) as i32,
758 copy.size.width as i32,
759 copy.size.height as i32,
760 copy.size.depth as i32,
761 format_desc.external,
762 format_desc.data_type,
763 unpack_data,
764 )
765 };
766 } else {
767 unsafe {
768 gl.tex_sub_image_2d(
769 get_2d_target(dst_target, copy.texture_base.array_layer),
770 copy.texture_base.mip_level as i32,
771 copy.texture_base.origin.x as i32,
772 copy.texture_base.origin.y as i32,
773 copy.size.width as i32,
774 copy.size.height as i32,
775 format_desc.external,
776 format_desc.data_type,
777 unpack_data,
778 )
779 };
780 }
781 } else {
782 let bytes_per_row = copy
783 .buffer_layout
784 .bytes_per_row
785 .unwrap_or(copy.size.width * block_size);
786 let minimum_rows_per_image = copy.size.height.div_ceil(block_height);
787 let rows_per_image = copy
788 .buffer_layout
789 .rows_per_image
790 .unwrap_or(minimum_rows_per_image);
791
792 let bytes_per_image = bytes_per_row * rows_per_image;
793 let minimum_bytes_per_image = bytes_per_row * minimum_rows_per_image;
794 let bytes_in_upload =
795 (bytes_per_image * (copy.size.depth - 1)) + minimum_bytes_per_image;
796 let offset = copy.buffer_layout.offset as u32;
797
798 let buffer_data;
799 let unpack_data = match src.raw {
800 Some(buffer) => {
801 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
802 unbind_unpack_buffer = true;
803 glow::CompressedPixelUnpackData::BufferRange(
804 offset..offset + bytes_in_upload,
805 )
806 }
807 None => {
808 buffer_data = lock(src.data.as_ref().unwrap());
809 let src_data = &buffer_data.as_slice()
810 [(offset as usize)..(offset + bytes_in_upload) as usize];
811 glow::CompressedPixelUnpackData::Slice(src_data)
812 }
813 };
814
815 if is_layered_target(dst_target) {
816 unsafe {
817 gl.compressed_tex_sub_image_3d(
818 dst_target,
819 copy.texture_base.mip_level as i32,
820 copy.texture_base.origin.x as i32,
821 copy.texture_base.origin.y as i32,
822 get_z_offset(dst_target, ©.texture_base) as i32,
823 copy.size.width as i32,
824 copy.size.height as i32,
825 copy.size.depth as i32,
826 format_desc.internal,
827 unpack_data,
828 )
829 };
830 } else {
831 unsafe {
832 gl.compressed_tex_sub_image_2d(
833 get_2d_target(dst_target, copy.texture_base.array_layer),
834 copy.texture_base.mip_level as i32,
835 copy.texture_base.origin.x as i32,
836 copy.texture_base.origin.y as i32,
837 copy.size.width as i32,
838 copy.size.height as i32,
839 format_desc.internal,
840 unpack_data,
841 )
842 };
843 }
844 }
845 if unbind_unpack_buffer {
846 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None) };
847 }
848 }
849 C::CopyTextureToBuffer {
850 src,
851 src_target,
852 src_format,
853 ref dst,
854 dst_target: _,
855 ref copy,
856 } => {
857 let block_size = src_format.block_copy_size(None).unwrap();
858 if src_format.is_compressed() {
859 log::error!("Not implemented yet: compressed texture copy to buffer");
860 return;
861 }
862 if src_target == glow::TEXTURE_CUBE_MAP
863 || src_target == glow::TEXTURE_CUBE_MAP_ARRAY
864 {
865 log::error!("Not implemented yet: cubemap texture copy to buffer");
866 return;
867 }
868 let format_desc = self.shared.describe_texture_format(src_format);
869 let row_texels = copy
870 .buffer_layout
871 .bytes_per_row
872 .map_or(copy.size.width, |bpr| bpr / block_size);
873 let column_texels = copy
874 .buffer_layout
875 .rows_per_image
876 .unwrap_or(copy.size.height);
877
878 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
879
880 let read_pixels = |offset| {
881 let mut buffer_data;
882 let unpack_data = match dst.raw {
883 Some(buffer) => {
884 unsafe { gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32) };
885 unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(buffer)) };
886 glow::PixelPackData::BufferOffset(offset as u32)
887 }
888 None => {
889 buffer_data = lock(dst.data.as_ref().unwrap());
890 let dst_data = &mut buffer_data.as_mut_slice()[offset as usize..];
891 glow::PixelPackData::Slice(Some(dst_data))
892 }
893 };
894 unsafe {
895 gl.read_pixels(
896 copy.texture_base.origin.x as i32,
897 copy.texture_base.origin.y as i32,
898 copy.size.width as i32,
899 copy.size.height as i32,
900 format_desc.external,
901 format_desc.data_type,
902 unpack_data,
903 )
904 };
905 };
906
907 match src_target {
908 glow::TEXTURE_2D => {
909 unsafe {
910 gl.framebuffer_texture_2d(
911 glow::READ_FRAMEBUFFER,
912 glow::COLOR_ATTACHMENT0,
913 src_target,
914 Some(src),
915 copy.texture_base.mip_level as i32,
916 )
917 };
918 read_pixels(copy.buffer_layout.offset);
919 }
920 glow::TEXTURE_2D_ARRAY => {
921 unsafe {
922 gl.framebuffer_texture_layer(
923 glow::READ_FRAMEBUFFER,
924 glow::COLOR_ATTACHMENT0,
925 Some(src),
926 copy.texture_base.mip_level as i32,
927 copy.texture_base.array_layer as i32,
928 )
929 };
930 read_pixels(copy.buffer_layout.offset);
931 }
932 glow::TEXTURE_3D => {
933 for z in copy.texture_base.origin.z..copy.size.depth {
934 unsafe {
935 gl.framebuffer_texture_layer(
936 glow::READ_FRAMEBUFFER,
937 glow::COLOR_ATTACHMENT0,
938 Some(src),
939 copy.texture_base.mip_level as i32,
940 z as i32,
941 )
942 };
943 let offset = copy.buffer_layout.offset
944 + (z * block_size * row_texels * column_texels) as u64;
945 read_pixels(offset);
946 }
947 }
948 glow::TEXTURE_CUBE_MAP | glow::TEXTURE_CUBE_MAP_ARRAY => unimplemented!(),
949 _ => unreachable!(),
950 }
951 }
952 C::SetIndexBuffer(buffer) => {
953 unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)) };
954 let mut current_index_buffer = self.current_index_buffer.lock();
955 *current_index_buffer = Some(buffer);
956 }
957 C::BeginQuery(query, target) => {
958 unsafe { gl.begin_query(target, query) };
959 }
960 C::EndQuery(target) => {
961 unsafe { gl.end_query(target) };
962 }
963 C::TimestampQuery(query) => {
964 unsafe { gl.query_counter(query, glow::TIMESTAMP) };
965 }
966 C::CopyQueryResults {
967 ref query_range,
968 ref dst,
969 dst_target,
970 dst_offset,
971 } => {
972 if self
973 .shared
974 .private_caps
975 .contains(PrivateCapabilities::QUERY_BUFFERS)
976 && dst.raw.is_some()
977 {
978 unsafe {
979 let query_size = 8;
982
983 let query_range_size = query_size * query_range.len();
984
985 let buffer = gl.create_buffer().ok();
986 gl.bind_buffer(glow::QUERY_BUFFER, buffer);
987 gl.buffer_data_size(
988 glow::QUERY_BUFFER,
989 query_range_size as _,
990 glow::STREAM_COPY,
991 );
992
993 for (i, &query) in queries
994 [query_range.start as usize..query_range.end as usize]
995 .iter()
996 .enumerate()
997 {
998 gl.get_query_parameter_u64_with_offset(
999 query,
1000 glow::QUERY_RESULT,
1001 query_size * i,
1002 )
1003 }
1004 gl.bind_buffer(dst_target, dst.raw);
1005 gl.copy_buffer_sub_data(
1006 glow::QUERY_BUFFER,
1007 dst_target,
1008 0,
1009 dst_offset as _,
1010 query_range_size as _,
1011 );
1012 if let Some(buffer) = buffer {
1013 gl.delete_buffer(buffer)
1014 }
1015 }
1016 } else {
1017 let mut temp_query_results = self.temp_query_results.lock();
1018 temp_query_results.clear();
1019 for &query in
1020 queries[query_range.start as usize..query_range.end as usize].iter()
1021 {
1022 let mut result: u64 = 0;
1023 unsafe {
1024 if self
1025 .shared
1026 .private_caps
1027 .contains(PrivateCapabilities::QUERY_64BIT)
1028 {
1029 let result: *mut u64 = &mut result;
1030 gl.get_query_parameter_u64_with_offset(
1031 query,
1032 glow::QUERY_RESULT,
1033 result as usize,
1034 )
1035 } else {
1036 result =
1037 gl.get_query_parameter_u32(query, glow::QUERY_RESULT) as u64;
1038 }
1039 };
1040 temp_query_results.push(result);
1041 }
1042 let query_data = bytemuck::cast_slice(&temp_query_results);
1043 match dst.raw {
1044 Some(buffer) => {
1045 unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
1046 unsafe {
1047 gl.buffer_sub_data_u8_slice(
1048 dst_target,
1049 dst_offset as i32,
1050 query_data,
1051 )
1052 };
1053 }
1054 None => {
1055 let data = &mut lock(dst.data.as_ref().unwrap());
1056 let len = query_data.len().min(data.len());
1057 data[..len].copy_from_slice(&query_data[..len]);
1058 }
1059 }
1060 }
1061 }
1062 C::ResetFramebuffer { is_default } => {
1063 if is_default {
1064 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
1065 } else {
1066 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1067 unsafe {
1068 gl.framebuffer_texture_2d(
1069 glow::DRAW_FRAMEBUFFER,
1070 glow::DEPTH_STENCIL_ATTACHMENT,
1071 glow::TEXTURE_2D,
1072 None,
1073 0,
1074 )
1075 };
1076 for i in 0..self.shared.limits.max_color_attachments {
1077 let target = glow::COLOR_ATTACHMENT0 + i;
1078 unsafe {
1079 gl.framebuffer_texture_2d(
1080 glow::DRAW_FRAMEBUFFER,
1081 target,
1082 glow::TEXTURE_2D,
1083 None,
1084 0,
1085 )
1086 };
1087 }
1088 }
1089 unsafe { gl.color_mask(true, true, true, true) };
1090 unsafe { gl.depth_mask(true) };
1091 unsafe { gl.stencil_mask(!0) };
1092 unsafe { gl.disable(glow::DEPTH_TEST) };
1093 unsafe { gl.disable(glow::STENCIL_TEST) };
1094 unsafe { gl.disable(glow::SCISSOR_TEST) };
1095 }
1096 C::BindAttachment {
1097 attachment,
1098 ref view,
1099 } => {
1100 unsafe { self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view) };
1101 }
1102 C::ResolveAttachment {
1103 attachment,
1104 ref dst,
1105 ref size,
1106 } => {
1107 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)) };
1108 unsafe { gl.read_buffer(attachment) };
1109 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
1110 unsafe {
1111 self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, glow::COLOR_ATTACHMENT0, dst)
1112 };
1113 unsafe {
1114 gl.blit_framebuffer(
1115 0,
1116 0,
1117 size.width as i32,
1118 size.height as i32,
1119 0,
1120 0,
1121 size.width as i32,
1122 size.height as i32,
1123 glow::COLOR_BUFFER_BIT,
1124 glow::NEAREST,
1125 )
1126 };
1127 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
1128 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1129 }
1130 C::InvalidateAttachments(ref list) => {
1131 if self
1132 .shared
1133 .private_caps
1134 .contains(PrivateCapabilities::INVALIDATE_FRAMEBUFFER)
1135 {
1136 unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) };
1137 }
1138 }
1139 C::SetDrawColorBuffers(count) => {
1140 self.draw_buffer_count.store(count, Ordering::Relaxed);
1141 let indices = (0..count as u32)
1142 .map(|i| glow::COLOR_ATTACHMENT0 + i)
1143 .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
1144 unsafe { gl.draw_buffers(&indices) };
1145 }
1146 C::ClearColorF {
1147 draw_buffer,
1148 ref color,
1149 is_srgb,
1150 } => {
1151 if self
1152 .shared
1153 .workarounds
1154 .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
1155 && is_srgb
1156 {
1157 unsafe { self.perform_shader_clear(gl, draw_buffer, *color) };
1158 } else {
1159 unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) };
1160 }
1161 }
1162 C::ClearColorU(draw_buffer, ref color) => {
1163 unsafe { gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, color) };
1164 }
1165 C::ClearColorI(draw_buffer, ref color) => {
1166 unsafe { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color) };
1167 }
1168 C::ClearDepth(depth) => {
1169 unsafe {
1172 gl.clear_depth_f32(depth);
1173 gl.clear(glow::DEPTH_BUFFER_BIT);
1174 }
1175 }
1176 C::ClearStencil(value) => {
1177 unsafe {
1180 gl.clear_stencil(value as i32);
1181 gl.clear(glow::STENCIL_BUFFER_BIT);
1182 }
1183 }
1184 C::ClearDepthAndStencil(depth, stencil_value) => {
1185 unsafe {
1188 gl.clear_depth_f32(depth);
1189 gl.clear_stencil(stencil_value as i32);
1190 gl.clear(glow::DEPTH_BUFFER_BIT | glow::STENCIL_BUFFER_BIT);
1191 }
1192 }
1193 C::BufferBarrier(raw, usage) => {
1194 let mut flags = 0;
1195 if usage.contains(wgt::BufferUses::VERTEX) {
1196 flags |= glow::VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1197 unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, Some(raw)) };
1198 unsafe { gl.vertex_attrib_pointer_f32(0, 1, glow::BYTE, true, 0, 0) };
1199 }
1200 if usage.contains(wgt::BufferUses::INDEX) {
1201 flags |= glow::ELEMENT_ARRAY_BARRIER_BIT;
1202 unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(raw)) };
1203 }
1204 if usage.contains(wgt::BufferUses::UNIFORM) {
1205 flags |= glow::UNIFORM_BARRIER_BIT;
1206 }
1207 if usage.contains(wgt::BufferUses::INDIRECT) {
1208 flags |= glow::COMMAND_BARRIER_BIT;
1209 unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(raw)) };
1210 }
1211 if usage.contains(wgt::BufferUses::COPY_SRC) {
1212 flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1213 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(raw)) };
1214 }
1215 if usage.contains(wgt::BufferUses::COPY_DST) {
1216 flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1217 unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(raw)) };
1218 }
1219 if usage.intersects(wgt::BufferUses::MAP_READ | wgt::BufferUses::MAP_WRITE) {
1220 flags |= glow::BUFFER_UPDATE_BARRIER_BIT;
1221 }
1222 if usage.intersects(
1223 wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE,
1224 ) {
1225 flags |= glow::SHADER_STORAGE_BARRIER_BIT;
1226 }
1227 unsafe { gl.memory_barrier(flags) };
1228 }
1229 C::TextureBarrier(usage) => {
1230 let mut flags = 0;
1231 if usage.contains(wgt::TextureUses::RESOURCE) {
1232 flags |= glow::TEXTURE_FETCH_BARRIER_BIT;
1233 }
1234 if usage.intersects(
1235 wgt::TextureUses::STORAGE_READ_ONLY
1236 | wgt::TextureUses::STORAGE_WRITE_ONLY
1237 | wgt::TextureUses::STORAGE_READ_WRITE,
1238 ) {
1239 flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT;
1240 }
1241 if usage.contains(wgt::TextureUses::COPY_DST) {
1242 flags |= glow::TEXTURE_UPDATE_BARRIER_BIT;
1243 }
1244 if usage.intersects(
1245 wgt::TextureUses::COLOR_TARGET
1246 | wgt::TextureUses::DEPTH_STENCIL_READ
1247 | wgt::TextureUses::DEPTH_STENCIL_WRITE,
1248 ) {
1249 flags |= glow::FRAMEBUFFER_BARRIER_BIT;
1250 }
1251 unsafe { gl.memory_barrier(flags) };
1252 }
1253 C::SetViewport {
1254 ref rect,
1255 ref depth,
1256 } => {
1257 unsafe { gl.viewport(rect.x, rect.y, rect.w, rect.h) };
1258 unsafe { gl.depth_range_f32(depth.start, depth.end) };
1259 }
1260 C::SetScissor(ref rect) => {
1261 unsafe { gl.scissor(rect.x, rect.y, rect.w, rect.h) };
1262 unsafe { gl.enable(glow::SCISSOR_TEST) };
1263 }
1264 C::SetStencilFunc {
1265 face,
1266 function,
1267 reference,
1268 read_mask,
1269 } => {
1270 unsafe { gl.stencil_func_separate(face, function, reference as i32, read_mask) };
1271 }
1272 C::SetStencilOps {
1273 face,
1274 write_mask,
1275 ref ops,
1276 } => {
1277 unsafe { gl.stencil_mask_separate(face, write_mask) };
1278 unsafe { gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass) };
1279 }
1280 C::SetVertexAttribute {
1281 buffer,
1282 ref buffer_desc,
1283 attribute_desc: ref vat,
1284 } => {
1285 unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, buffer) };
1286 unsafe { gl.enable_vertex_attrib_array(vat.location) };
1287
1288 if buffer.is_none() {
1289 match vat.format_desc.attrib_kind {
1290 super::VertexAttribKind::Float => unsafe {
1291 gl.vertex_attrib_format_f32(
1292 vat.location,
1293 vat.format_desc.element_count,
1294 vat.format_desc.element_format,
1295 true, vat.offset,
1297 )
1298 },
1299 super::VertexAttribKind::Integer => unsafe {
1300 gl.vertex_attrib_format_i32(
1301 vat.location,
1302 vat.format_desc.element_count,
1303 vat.format_desc.element_format,
1304 vat.offset,
1305 )
1306 },
1307 }
1308
1309 unsafe { gl.vertex_attrib_binding(vat.location, vat.buffer_index) };
1312 } else {
1313 match vat.format_desc.attrib_kind {
1314 super::VertexAttribKind::Float => unsafe {
1315 gl.vertex_attrib_pointer_f32(
1316 vat.location,
1317 vat.format_desc.element_count,
1318 vat.format_desc.element_format,
1319 true, buffer_desc.stride as i32,
1321 vat.offset as i32,
1322 )
1323 },
1324 super::VertexAttribKind::Integer => unsafe {
1325 gl.vertex_attrib_pointer_i32(
1326 vat.location,
1327 vat.format_desc.element_count,
1328 vat.format_desc.element_format,
1329 buffer_desc.stride as i32,
1330 vat.offset as i32,
1331 )
1332 },
1333 }
1334 unsafe { gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32) };
1335 }
1336 }
1337 C::UnsetVertexAttribute(location) => {
1338 unsafe { gl.disable_vertex_attrib_array(location) };
1339 }
1340 C::SetVertexBuffer {
1341 index,
1342 ref buffer,
1343 ref buffer_desc,
1344 } => {
1345 unsafe { gl.vertex_binding_divisor(index, buffer_desc.step as u32) };
1346 unsafe {
1347 gl.bind_vertex_buffer(
1348 index,
1349 Some(buffer.raw),
1350 buffer.offset as i32,
1351 buffer_desc.stride as i32,
1352 )
1353 };
1354 }
1355 C::SetDepth(ref depth) => {
1356 unsafe { gl.depth_func(depth.function) };
1357 unsafe { gl.depth_mask(depth.mask) };
1358 }
1359 C::SetDepthBias(bias) => {
1360 if bias.is_enabled() {
1361 unsafe { gl.enable(glow::POLYGON_OFFSET_FILL) };
1362 unsafe { gl.polygon_offset(bias.slope_scale, bias.constant as f32) };
1363 } else {
1364 unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
1365 }
1366 }
1367 C::ConfigureDepthStencil(aspects) => {
1368 if aspects.contains(crate::FormatAspects::DEPTH) {
1369 unsafe { gl.enable(glow::DEPTH_TEST) };
1370 } else {
1371 unsafe { gl.disable(glow::DEPTH_TEST) };
1372 }
1373 if aspects.contains(crate::FormatAspects::STENCIL) {
1374 unsafe { gl.enable(glow::STENCIL_TEST) };
1375 } else {
1376 unsafe { gl.disable(glow::STENCIL_TEST) };
1377 }
1378 }
1379 C::SetAlphaToCoverage(enabled) => {
1380 if enabled {
1381 unsafe { gl.enable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1382 } else {
1383 unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1384 }
1385 }
1386 C::SetProgram(program) => {
1387 unsafe { gl.use_program(Some(program)) };
1388 }
1389 C::SetPrimitive(ref state) => {
1390 unsafe { gl.front_face(state.front_face) };
1391 if state.cull_face != 0 {
1392 unsafe { gl.enable(glow::CULL_FACE) };
1393 unsafe { gl.cull_face(state.cull_face) };
1394 } else {
1395 unsafe { gl.disable(glow::CULL_FACE) };
1396 }
1397 if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
1398 if state.unclipped_depth {
1400 unsafe { gl.enable(glow::DEPTH_CLAMP) };
1401 } else {
1402 unsafe { gl.disable(glow::DEPTH_CLAMP) };
1403 }
1404 }
1405 if self.features.contains(wgt::Features::POLYGON_MODE_LINE) {
1407 unsafe { gl.polygon_mode(glow::FRONT_AND_BACK, state.polygon_mode) };
1408 }
1409 }
1410 C::SetBlendConstant(c) => {
1411 unsafe { gl.blend_color(c[0], c[1], c[2], c[3]) };
1412 }
1413 C::SetColorTarget {
1414 draw_buffer_index,
1415 desc: super::ColorTargetDesc { mask, ref blend },
1416 } => {
1417 use wgt::ColorWrites as Cw;
1418 if let Some(index) = draw_buffer_index {
1419 unsafe {
1420 gl.color_mask_draw_buffer(
1421 index,
1422 mask.contains(Cw::RED),
1423 mask.contains(Cw::GREEN),
1424 mask.contains(Cw::BLUE),
1425 mask.contains(Cw::ALPHA),
1426 )
1427 };
1428 if let Some(ref blend) = *blend {
1429 unsafe { gl.enable_draw_buffer(glow::BLEND, index) };
1430 if blend.color != blend.alpha {
1431 unsafe {
1432 gl.blend_equation_separate_draw_buffer(
1433 index,
1434 blend.color.equation,
1435 blend.alpha.equation,
1436 )
1437 };
1438 unsafe {
1439 gl.blend_func_separate_draw_buffer(
1440 index,
1441 blend.color.src,
1442 blend.color.dst,
1443 blend.alpha.src,
1444 blend.alpha.dst,
1445 )
1446 };
1447 } else {
1448 unsafe { gl.blend_equation_draw_buffer(index, blend.color.equation) };
1449 unsafe {
1450 gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst)
1451 };
1452 }
1453 } else {
1454 unsafe { gl.disable_draw_buffer(glow::BLEND, index) };
1455 }
1456 } else {
1457 unsafe {
1458 gl.color_mask(
1459 mask.contains(Cw::RED),
1460 mask.contains(Cw::GREEN),
1461 mask.contains(Cw::BLUE),
1462 mask.contains(Cw::ALPHA),
1463 )
1464 };
1465 if let Some(ref blend) = *blend {
1466 unsafe { gl.enable(glow::BLEND) };
1467 if blend.color != blend.alpha {
1468 unsafe {
1469 gl.blend_equation_separate(
1470 blend.color.equation,
1471 blend.alpha.equation,
1472 )
1473 };
1474 unsafe {
1475 gl.blend_func_separate(
1476 blend.color.src,
1477 blend.color.dst,
1478 blend.alpha.src,
1479 blend.alpha.dst,
1480 )
1481 };
1482 } else {
1483 unsafe { gl.blend_equation(blend.color.equation) };
1484 unsafe { gl.blend_func(blend.color.src, blend.color.dst) };
1485 }
1486 } else {
1487 unsafe { gl.disable(glow::BLEND) };
1488 }
1489 }
1490 }
1491 C::BindBuffer {
1492 target,
1493 slot,
1494 buffer,
1495 offset,
1496 size,
1497 } => {
1498 unsafe { gl.bind_buffer_range(target, slot, Some(buffer), offset, size) };
1499 }
1500 C::BindSampler(texture_index, sampler) => {
1501 unsafe { gl.bind_sampler(texture_index, sampler) };
1502 }
1503 C::BindTexture {
1504 slot,
1505 texture,
1506 target,
1507 aspects,
1508 ref mip_levels,
1509 } => {
1510 unsafe { gl.active_texture(glow::TEXTURE0 + slot) };
1511 unsafe { gl.bind_texture(target, Some(texture)) };
1512
1513 unsafe {
1514 gl.tex_parameter_i32(target, glow::TEXTURE_BASE_LEVEL, mip_levels.start as i32)
1515 };
1516 unsafe {
1517 gl.tex_parameter_i32(
1518 target,
1519 glow::TEXTURE_MAX_LEVEL,
1520 (mip_levels.end - 1) as i32,
1521 )
1522 };
1523
1524 let version = gl.version();
1525 let is_min_es_3_1 = version.is_embedded && (version.major, version.minor) >= (3, 1);
1526 let is_min_4_3 = !version.is_embedded && (version.major, version.minor) >= (4, 3);
1527 if is_min_es_3_1 || is_min_4_3 {
1528 let mode = match aspects {
1529 crate::FormatAspects::DEPTH => Some(glow::DEPTH_COMPONENT),
1530 crate::FormatAspects::STENCIL => Some(glow::STENCIL_INDEX),
1531 _ => None,
1532 };
1533 if let Some(mode) = mode {
1534 unsafe {
1535 gl.tex_parameter_i32(
1536 target,
1537 glow::DEPTH_STENCIL_TEXTURE_MODE,
1538 mode as _,
1539 )
1540 };
1541 }
1542 }
1543 }
1544 C::BindImage { slot, ref binding } => {
1545 unsafe {
1546 gl.bind_image_texture(
1547 slot,
1548 Some(binding.raw),
1549 binding.mip_level as i32,
1550 binding.array_layer.is_none(),
1551 binding.array_layer.unwrap_or_default() as i32,
1552 binding.access,
1553 binding.format,
1554 )
1555 };
1556 }
1557 C::InsertDebugMarker(ref range) => {
1558 let marker = extract_marker(data_bytes, range);
1559 unsafe {
1560 if self
1561 .shared
1562 .private_caps
1563 .contains(PrivateCapabilities::DEBUG_FNS)
1564 {
1565 gl.debug_message_insert(
1566 glow::DEBUG_SOURCE_APPLICATION,
1567 glow::DEBUG_TYPE_MARKER,
1568 DEBUG_ID,
1569 glow::DEBUG_SEVERITY_NOTIFICATION,
1570 marker,
1571 )
1572 }
1573 };
1574 }
1575 C::PushDebugGroup(ref range) => {
1576 let marker = extract_marker(data_bytes, range);
1577 unsafe {
1578 if self
1579 .shared
1580 .private_caps
1581 .contains(PrivateCapabilities::DEBUG_FNS)
1582 {
1583 gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker)
1584 }
1585 };
1586 }
1587 C::PopDebugGroup => {
1588 unsafe {
1589 if self
1590 .shared
1591 .private_caps
1592 .contains(PrivateCapabilities::DEBUG_FNS)
1593 {
1594 gl.pop_debug_group()
1595 }
1596 };
1597 }
1598 C::SetPushConstants {
1599 ref uniform,
1600 offset,
1601 } => {
1602 fn get_data<T, const COUNT: usize>(data: &[u8], offset: u32) -> [T; COUNT]
1603 where
1604 [T; COUNT]: bytemuck::AnyBitPattern,
1605 {
1606 let data_required = size_of::<T>() * COUNT;
1607 let raw = &data[(offset as usize)..][..data_required];
1608 bytemuck::pod_read_unaligned(raw)
1609 }
1610
1611 let location = Some(&uniform.location);
1612
1613 match uniform.ty {
1614 naga::TypeInner::Scalar(naga::Scalar::F32) => {
1618 let data = get_data::<f32, 1>(data_bytes, offset)[0];
1619 unsafe { gl.uniform_1_f32(location, data) };
1620 }
1621 naga::TypeInner::Vector {
1622 size: naga::VectorSize::Bi,
1623 scalar: naga::Scalar::F32,
1624 } => {
1625 let data = &get_data::<f32, 2>(data_bytes, offset);
1626 unsafe { gl.uniform_2_f32_slice(location, data) };
1627 }
1628 naga::TypeInner::Vector {
1629 size: naga::VectorSize::Tri,
1630 scalar: naga::Scalar::F32,
1631 } => {
1632 let data = &get_data::<f32, 3>(data_bytes, offset);
1633 unsafe { gl.uniform_3_f32_slice(location, data) };
1634 }
1635 naga::TypeInner::Vector {
1636 size: naga::VectorSize::Quad,
1637 scalar: naga::Scalar::F32,
1638 } => {
1639 let data = &get_data::<f32, 4>(data_bytes, offset);
1640 unsafe { gl.uniform_4_f32_slice(location, data) };
1641 }
1642
1643 naga::TypeInner::Scalar(naga::Scalar::I32) => {
1647 let data = get_data::<i32, 1>(data_bytes, offset)[0];
1648 unsafe { gl.uniform_1_i32(location, data) };
1649 }
1650 naga::TypeInner::Vector {
1651 size: naga::VectorSize::Bi,
1652 scalar: naga::Scalar::I32,
1653 } => {
1654 let data = &get_data::<i32, 2>(data_bytes, offset);
1655 unsafe { gl.uniform_2_i32_slice(location, data) };
1656 }
1657 naga::TypeInner::Vector {
1658 size: naga::VectorSize::Tri,
1659 scalar: naga::Scalar::I32,
1660 } => {
1661 let data = &get_data::<i32, 3>(data_bytes, offset);
1662 unsafe { gl.uniform_3_i32_slice(location, data) };
1663 }
1664 naga::TypeInner::Vector {
1665 size: naga::VectorSize::Quad,
1666 scalar: naga::Scalar::I32,
1667 } => {
1668 let data = &get_data::<i32, 4>(data_bytes, offset);
1669 unsafe { gl.uniform_4_i32_slice(location, data) };
1670 }
1671
1672 naga::TypeInner::Scalar(naga::Scalar::U32) => {
1676 let data = get_data::<u32, 1>(data_bytes, offset)[0];
1677 unsafe { gl.uniform_1_u32(location, data) };
1678 }
1679 naga::TypeInner::Vector {
1680 size: naga::VectorSize::Bi,
1681 scalar: naga::Scalar::U32,
1682 } => {
1683 let data = &get_data::<u32, 2>(data_bytes, offset);
1684 unsafe { gl.uniform_2_u32_slice(location, data) };
1685 }
1686 naga::TypeInner::Vector {
1687 size: naga::VectorSize::Tri,
1688 scalar: naga::Scalar::U32,
1689 } => {
1690 let data = &get_data::<u32, 3>(data_bytes, offset);
1691 unsafe { gl.uniform_3_u32_slice(location, data) };
1692 }
1693 naga::TypeInner::Vector {
1694 size: naga::VectorSize::Quad,
1695 scalar: naga::Scalar::U32,
1696 } => {
1697 let data = &get_data::<u32, 4>(data_bytes, offset);
1698 unsafe { gl.uniform_4_u32_slice(location, data) };
1699 }
1700
1701 naga::TypeInner::Matrix {
1705 columns: naga::VectorSize::Bi,
1706 rows: naga::VectorSize::Bi,
1707 scalar: naga::Scalar::F32,
1708 } => {
1709 let data = &get_data::<f32, 4>(data_bytes, offset);
1710 unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) };
1711 }
1712 naga::TypeInner::Matrix {
1713 columns: naga::VectorSize::Bi,
1714 rows: naga::VectorSize::Tri,
1715 scalar: naga::Scalar::F32,
1716 } => {
1717 let unpacked_data = &get_data::<f32, 8>(data_bytes, offset);
1719 #[rustfmt::skip]
1720 let packed_data = [
1721 unpacked_data[0], unpacked_data[1], unpacked_data[2],
1722 unpacked_data[4], unpacked_data[5], unpacked_data[6],
1723 ];
1724 unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) };
1725 }
1726 naga::TypeInner::Matrix {
1727 columns: naga::VectorSize::Bi,
1728 rows: naga::VectorSize::Quad,
1729 scalar: naga::Scalar::F32,
1730 } => {
1731 let data = &get_data::<f32, 8>(data_bytes, offset);
1732 unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) };
1733 }
1734
1735 naga::TypeInner::Matrix {
1739 columns: naga::VectorSize::Tri,
1740 rows: naga::VectorSize::Bi,
1741 scalar: naga::Scalar::F32,
1742 } => {
1743 let data = &get_data::<f32, 6>(data_bytes, offset);
1744 unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) };
1745 }
1746 naga::TypeInner::Matrix {
1747 columns: naga::VectorSize::Tri,
1748 rows: naga::VectorSize::Tri,
1749 scalar: naga::Scalar::F32,
1750 } => {
1751 let unpacked_data = &get_data::<f32, 12>(data_bytes, offset);
1753 #[rustfmt::skip]
1754 let packed_data = [
1755 unpacked_data[0], unpacked_data[1], unpacked_data[2],
1756 unpacked_data[4], unpacked_data[5], unpacked_data[6],
1757 unpacked_data[8], unpacked_data[9], unpacked_data[10],
1758 ];
1759 unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) };
1760 }
1761 naga::TypeInner::Matrix {
1762 columns: naga::VectorSize::Tri,
1763 rows: naga::VectorSize::Quad,
1764 scalar: naga::Scalar::F32,
1765 } => {
1766 let data = &get_data::<f32, 12>(data_bytes, offset);
1767 unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) };
1768 }
1769
1770 naga::TypeInner::Matrix {
1774 columns: naga::VectorSize::Quad,
1775 rows: naga::VectorSize::Bi,
1776 scalar: naga::Scalar::F32,
1777 } => {
1778 let data = &get_data::<f32, 8>(data_bytes, offset);
1779 unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) };
1780 }
1781 naga::TypeInner::Matrix {
1782 columns: naga::VectorSize::Quad,
1783 rows: naga::VectorSize::Tri,
1784 scalar: naga::Scalar::F32,
1785 } => {
1786 let unpacked_data = &get_data::<f32, 16>(data_bytes, offset);
1788 #[rustfmt::skip]
1789 let packed_data = [
1790 unpacked_data[0], unpacked_data[1], unpacked_data[2],
1791 unpacked_data[4], unpacked_data[5], unpacked_data[6],
1792 unpacked_data[8], unpacked_data[9], unpacked_data[10],
1793 unpacked_data[12], unpacked_data[13], unpacked_data[14],
1794 ];
1795 unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) };
1796 }
1797 naga::TypeInner::Matrix {
1798 columns: naga::VectorSize::Quad,
1799 rows: naga::VectorSize::Quad,
1800 scalar: naga::Scalar::F32,
1801 } => {
1802 let data = &get_data::<f32, 16>(data_bytes, offset);
1803 unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) };
1804 }
1805 _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
1806 }
1807 }
1808 }
1809 }
1810}
1811
1812impl crate::Queue for super::Queue {
1813 type A = super::Api;
1814
1815 unsafe fn submit(
1816 &self,
1817 command_buffers: &[&super::CommandBuffer],
1818 _surface_textures: &[&super::Texture],
1819 (signal_fence, signal_value): (&mut super::Fence, crate::FenceValue),
1820 ) -> Result<(), crate::DeviceError> {
1821 let shared = Arc::clone(&self.shared);
1822 let gl = &shared.context.lock();
1823 for cmd_buf in command_buffers.iter() {
1824 unsafe { self.reset_state(gl) };
1829 if let Some(ref label) = cmd_buf.label {
1830 if self
1831 .shared
1832 .private_caps
1833 .contains(PrivateCapabilities::DEBUG_FNS)
1834 {
1835 unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) };
1836 }
1837 }
1838
1839 for command in cmd_buf.commands.iter() {
1840 unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
1841 }
1842
1843 if cmd_buf.label.is_some()
1844 && self
1845 .shared
1846 .private_caps
1847 .contains(PrivateCapabilities::DEBUG_FNS)
1848 {
1849 unsafe { gl.pop_debug_group() };
1850 }
1851 }
1852
1853 signal_fence.maintain(gl);
1854 signal_fence.signal(gl, signal_value)?;
1855
1856 unsafe { gl.flush() };
1860
1861 Ok(())
1862 }
1863
1864 unsafe fn present(
1865 &self,
1866 surface: &super::Surface,
1867 texture: super::Texture,
1868 ) -> Result<(), crate::SurfaceError> {
1869 unsafe { surface.present(texture, &self.shared.context) }
1870 }
1871
1872 unsafe fn get_timestamp_period(&self) -> f32 {
1873 1.0
1874 }
1875}
1876
1877#[cfg(send_sync)]
1878unsafe impl Sync for super::Queue {}
1879#[cfg(send_sync)]
1880unsafe impl Send for super::Queue {}