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