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