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(web_sys_unstable_apis)]
540 wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
541 gl.tex_sub_image_3d_with_video_frame(
542 dst_target,
543 copy.dst_base.mip_level as i32,
544 copy.dst_base.origin.x as i32,
545 copy.dst_base.origin.y as i32,
546 z_offset as i32,
547 copy.size.width as i32,
548 copy.size.height as i32,
549 copy.size.depth as i32,
550 format_desc.external,
551 format_desc.data_type,
552 v,
553 )
554 },
555 wgt::ExternalImageSource::ImageData(ref i) => unsafe {
556 gl.tex_sub_image_3d_with_image_data(
557 dst_target,
558 copy.dst_base.mip_level as i32,
559 copy.dst_base.origin.x as i32,
560 copy.dst_base.origin.y as i32,
561 z_offset as i32,
562 copy.size.width as i32,
563 copy.size.height as i32,
564 copy.size.depth as i32,
565 format_desc.external,
566 format_desc.data_type,
567 i,
568 );
569 },
570 wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
571 gl.tex_sub_image_3d_with_html_canvas_element(
572 dst_target,
573 copy.dst_base.mip_level as i32,
574 copy.dst_base.origin.x as i32,
575 copy.dst_base.origin.y as i32,
576 z_offset as i32,
577 copy.size.width as i32,
578 copy.size.height as i32,
579 copy.size.depth as i32,
580 format_desc.external,
581 format_desc.data_type,
582 c,
583 );
584 },
585 wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
586 }
587 } else {
588 let dst_target = get_2d_target(dst_target, copy.dst_base.array_layer);
589
590 match src.source {
591 wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
592 gl.tex_sub_image_2d_with_image_bitmap_and_width_and_height(
593 dst_target,
594 copy.dst_base.mip_level as i32,
595 copy.dst_base.origin.x as i32,
596 copy.dst_base.origin.y as i32,
597 copy.size.width as i32,
598 copy.size.height as i32,
599 format_desc.external,
600 format_desc.data_type,
601 b,
602 );
603 },
604 wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
605 gl.tex_sub_image_2d_with_html_image_and_width_and_height(
606 dst_target,
607 copy.dst_base.mip_level as i32,
608 copy.dst_base.origin.x as i32,
609 copy.dst_base.origin.y as i32,
610 copy.size.width as i32,
611 copy.size.height as i32,
612 format_desc.external,
613 format_desc.data_type,
614 i,
615 )
616 },
617 wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
618 gl.tex_sub_image_2d_with_html_video_and_width_and_height(
619 dst_target,
620 copy.dst_base.mip_level as i32,
621 copy.dst_base.origin.x as i32,
622 copy.dst_base.origin.y as i32,
623 copy.size.width as i32,
624 copy.size.height as i32,
625 format_desc.external,
626 format_desc.data_type,
627 v,
628 )
629 },
630 #[cfg(web_sys_unstable_apis)]
631 wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
632 gl.tex_sub_image_2d_with_video_frame_and_width_and_height(
633 dst_target,
634 copy.dst_base.mip_level as i32,
635 copy.dst_base.origin.x as i32,
636 copy.dst_base.origin.y as i32,
637 copy.size.width as i32,
638 copy.size.height as i32,
639 format_desc.external,
640 format_desc.data_type,
641 v,
642 )
643 },
644 wgt::ExternalImageSource::ImageData(ref i) => unsafe {
645 gl.tex_sub_image_2d_with_image_data_and_width_and_height(
646 dst_target,
647 copy.dst_base.mip_level as i32,
648 copy.dst_base.origin.x as i32,
649 copy.dst_base.origin.y as i32,
650 copy.size.width as i32,
651 copy.size.height as i32,
652 format_desc.external,
653 format_desc.data_type,
654 i,
655 );
656 },
657 wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
658 gl.tex_sub_image_2d_with_html_canvas_and_width_and_height(
659 dst_target,
660 copy.dst_base.mip_level as i32,
661 copy.dst_base.origin.x as i32,
662 copy.dst_base.origin.y as i32,
663 copy.size.width as i32,
664 copy.size.height as i32,
665 format_desc.external,
666 format_desc.data_type,
667 c,
668 )
669 },
670 wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
671 }
672 }
673
674 unsafe {
675 if src.flip_y {
676 gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, false);
677 }
678 if dst_premultiplication {
679 gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
680 }
681 }
682 }
683 C::CopyTextureToTexture {
684 src,
685 src_target,
686 dst,
687 dst_target,
688 ref copy,
689 } => {
690 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
692 if is_layered_target(src_target) {
693 unsafe {
695 gl.framebuffer_texture_layer(
696 glow::READ_FRAMEBUFFER,
697 glow::COLOR_ATTACHMENT0,
698 Some(src),
699 copy.src_base.mip_level as i32,
700 copy.src_base.array_layer as i32,
701 )
702 };
703 } else {
704 unsafe {
705 gl.framebuffer_texture_2d(
706 glow::READ_FRAMEBUFFER,
707 glow::COLOR_ATTACHMENT0,
708 src_target,
709 Some(src),
710 copy.src_base.mip_level as i32,
711 )
712 };
713 }
714
715 unsafe { gl.bind_texture(dst_target, Some(dst)) };
716 if is_layered_target(dst_target) {
717 unsafe {
718 gl.copy_tex_sub_image_3d(
719 dst_target,
720 copy.dst_base.mip_level as i32,
721 copy.dst_base.origin.x as i32,
722 copy.dst_base.origin.y as i32,
723 get_z_offset(dst_target, ©.dst_base) as i32,
724 copy.src_base.origin.x as i32,
725 copy.src_base.origin.y as i32,
726 copy.size.width as i32,
727 copy.size.height as i32,
728 )
729 };
730 } else {
731 unsafe {
732 gl.copy_tex_sub_image_2d(
733 get_2d_target(dst_target, copy.dst_base.array_layer),
734 copy.dst_base.mip_level as i32,
735 copy.dst_base.origin.x as i32,
736 copy.dst_base.origin.y as i32,
737 copy.src_base.origin.x as i32,
738 copy.src_base.origin.y as i32,
739 copy.size.width as i32,
740 copy.size.height as i32,
741 )
742 };
743 }
744 }
745 C::CopyBufferToTexture {
746 ref src,
747 src_target: _,
748 dst,
749 dst_target,
750 dst_format,
751 ref copy,
752 } => {
753 let (block_width, block_height) = dst_format.block_dimensions();
754 let block_size = dst_format.block_copy_size(None).unwrap();
755 let format_desc = self.shared.describe_texture_format(dst_format);
756 let row_texels = copy
757 .buffer_layout
758 .bytes_per_row
759 .map_or(0, |bpr| block_width * bpr / block_size);
760 let column_texels = copy
761 .buffer_layout
762 .rows_per_image
763 .map_or(0, |rpi| block_height * rpi);
764
765 unsafe { gl.bind_texture(dst_target, Some(dst)) };
766 unsafe { gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32) };
767 unsafe { gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32) };
768 let mut unbind_unpack_buffer = false;
769 if !dst_format.is_compressed() {
770 let buffer_data;
771 let unpack_data = match src.raw {
772 Some(buffer) => {
773 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
774 unbind_unpack_buffer = true;
775 glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32)
776 }
777 None => {
778 buffer_data = lock(src.data.as_ref().unwrap());
779 let src_data =
780 &buffer_data.as_slice()[copy.buffer_layout.offset as usize..];
781 glow::PixelUnpackData::Slice(Some(src_data))
782 }
783 };
784 if is_layered_target(dst_target) {
785 unsafe {
786 gl.tex_sub_image_3d(
787 dst_target,
788 copy.texture_base.mip_level as i32,
789 copy.texture_base.origin.x as i32,
790 copy.texture_base.origin.y as i32,
791 get_z_offset(dst_target, ©.texture_base) as i32,
792 copy.size.width as i32,
793 copy.size.height as i32,
794 copy.size.depth as i32,
795 format_desc.external,
796 format_desc.data_type,
797 unpack_data,
798 )
799 };
800 } else {
801 unsafe {
802 gl.tex_sub_image_2d(
803 get_2d_target(dst_target, copy.texture_base.array_layer),
804 copy.texture_base.mip_level as i32,
805 copy.texture_base.origin.x as i32,
806 copy.texture_base.origin.y as i32,
807 copy.size.width as i32,
808 copy.size.height as i32,
809 format_desc.external,
810 format_desc.data_type,
811 unpack_data,
812 )
813 };
814 }
815 } else {
816 let bytes_per_row = copy
817 .buffer_layout
818 .bytes_per_row
819 .unwrap_or(copy.size.width * block_size);
820 let minimum_rows_per_image = copy.size.height.div_ceil(block_height);
821 let rows_per_image = copy
822 .buffer_layout
823 .rows_per_image
824 .unwrap_or(minimum_rows_per_image);
825
826 let bytes_per_image = bytes_per_row * rows_per_image;
827 let minimum_bytes_per_image = bytes_per_row * minimum_rows_per_image;
828 let bytes_in_upload =
829 (bytes_per_image * (copy.size.depth - 1)) + minimum_bytes_per_image;
830 let offset = copy.buffer_layout.offset as u32;
831
832 let buffer_data;
833 let unpack_data = match src.raw {
834 Some(buffer) => {
835 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
836 unbind_unpack_buffer = true;
837 glow::CompressedPixelUnpackData::BufferRange(
838 offset..offset + bytes_in_upload,
839 )
840 }
841 None => {
842 buffer_data = lock(src.data.as_ref().unwrap());
843 let src_data = &buffer_data.as_slice()
844 [(offset as usize)..(offset + bytes_in_upload) as usize];
845 glow::CompressedPixelUnpackData::Slice(src_data)
846 }
847 };
848
849 if is_layered_target(dst_target) {
850 unsafe {
851 gl.compressed_tex_sub_image_3d(
852 dst_target,
853 copy.texture_base.mip_level as i32,
854 copy.texture_base.origin.x as i32,
855 copy.texture_base.origin.y as i32,
856 get_z_offset(dst_target, ©.texture_base) as i32,
857 copy.size.width as i32,
858 copy.size.height as i32,
859 copy.size.depth as i32,
860 format_desc.internal,
861 unpack_data,
862 )
863 };
864 } else {
865 unsafe {
866 gl.compressed_tex_sub_image_2d(
867 get_2d_target(dst_target, copy.texture_base.array_layer),
868 copy.texture_base.mip_level as i32,
869 copy.texture_base.origin.x as i32,
870 copy.texture_base.origin.y as i32,
871 copy.size.width as i32,
872 copy.size.height as i32,
873 format_desc.internal,
874 unpack_data,
875 )
876 };
877 }
878 }
879 if unbind_unpack_buffer {
880 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None) };
881 }
882 }
883 C::CopyTextureToBuffer {
884 src,
885 src_target,
886 src_format,
887 ref dst,
888 dst_target: _,
889 ref copy,
890 } => {
891 let block_size = src_format.block_copy_size(None).unwrap();
892 if src_format.is_compressed() {
893 log::error!("Not implemented yet: compressed texture copy to buffer");
894 return;
895 }
896 if src_target == glow::TEXTURE_CUBE_MAP
897 || src_target == glow::TEXTURE_CUBE_MAP_ARRAY
898 {
899 log::error!("Not implemented yet: cubemap texture copy to buffer");
900 return;
901 }
902 let format_desc = self.shared.describe_texture_format(src_format);
903 let row_texels = copy
904 .buffer_layout
905 .bytes_per_row
906 .map_or(copy.size.width, |bpr| bpr / block_size);
907 let column_texels = copy
908 .buffer_layout
909 .rows_per_image
910 .unwrap_or(copy.size.height);
911
912 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
913
914 let read_pixels = |offset| {
915 let mut buffer_data;
916 let unpack_data = match dst.raw {
917 Some(buffer) => {
918 unsafe { gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32) };
919 unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(buffer)) };
920 glow::PixelPackData::BufferOffset(offset as u32)
921 }
922 None => {
923 buffer_data = lock(dst.data.as_ref().unwrap());
924 let dst_data = &mut buffer_data.as_mut_slice()[offset as usize..];
925 glow::PixelPackData::Slice(Some(dst_data))
926 }
927 };
928 unsafe {
929 gl.read_pixels(
930 copy.texture_base.origin.x as i32,
931 copy.texture_base.origin.y as i32,
932 copy.size.width as i32,
933 copy.size.height as i32,
934 format_desc.external,
935 format_desc.data_type,
936 unpack_data,
937 )
938 };
939 };
940
941 match src_target {
942 glow::TEXTURE_2D => {
943 unsafe {
944 gl.framebuffer_texture_2d(
945 glow::READ_FRAMEBUFFER,
946 glow::COLOR_ATTACHMENT0,
947 src_target,
948 Some(src),
949 copy.texture_base.mip_level as i32,
950 )
951 };
952 read_pixels(copy.buffer_layout.offset);
953 }
954 glow::TEXTURE_2D_ARRAY => {
955 unsafe {
956 gl.framebuffer_texture_layer(
957 glow::READ_FRAMEBUFFER,
958 glow::COLOR_ATTACHMENT0,
959 Some(src),
960 copy.texture_base.mip_level as i32,
961 copy.texture_base.array_layer as i32,
962 )
963 };
964 read_pixels(copy.buffer_layout.offset);
965 }
966 glow::TEXTURE_3D => {
967 for z in copy.texture_base.origin.z..copy.size.depth {
968 unsafe {
969 gl.framebuffer_texture_layer(
970 glow::READ_FRAMEBUFFER,
971 glow::COLOR_ATTACHMENT0,
972 Some(src),
973 copy.texture_base.mip_level as i32,
974 z as i32,
975 )
976 };
977 let offset = copy.buffer_layout.offset
978 + (z * block_size * row_texels * column_texels) as u64;
979 read_pixels(offset);
980 }
981 }
982 glow::TEXTURE_CUBE_MAP | glow::TEXTURE_CUBE_MAP_ARRAY => unimplemented!(),
983 _ => unreachable!(),
984 }
985 }
986 C::SetIndexBuffer(buffer) => {
987 unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)) };
988 let mut current_index_buffer = self.current_index_buffer.lock();
989 *current_index_buffer = Some(buffer);
990 }
991 C::BeginQuery(query, target) => {
992 unsafe { gl.begin_query(target, query) };
993 }
994 C::EndQuery(target) => {
995 unsafe { gl.end_query(target) };
996 }
997 C::TimestampQuery(query) => {
998 unsafe { gl.query_counter(query, glow::TIMESTAMP) };
999 }
1000 C::CopyQueryResults {
1001 ref query_range,
1002 ref dst,
1003 dst_target,
1004 dst_offset,
1005 } => {
1006 if self
1007 .shared
1008 .private_caps
1009 .contains(PrivateCapabilities::QUERY_BUFFERS)
1010 && dst.raw.is_some()
1011 {
1012 unsafe {
1013 let query_size = 8;
1016
1017 let query_range_size = query_size * query_range.len();
1018
1019 let buffer = gl.create_buffer().ok();
1020 gl.bind_buffer(glow::QUERY_BUFFER, buffer);
1021 gl.buffer_data_size(
1022 glow::QUERY_BUFFER,
1023 query_range_size as _,
1024 glow::STREAM_COPY,
1025 );
1026
1027 for (i, &query) in queries
1028 [query_range.start as usize..query_range.end as usize]
1029 .iter()
1030 .enumerate()
1031 {
1032 gl.get_query_parameter_u64_with_offset(
1033 query,
1034 glow::QUERY_RESULT,
1035 query_size * i,
1036 )
1037 }
1038 gl.bind_buffer(dst_target, dst.raw);
1039 gl.copy_buffer_sub_data(
1040 glow::QUERY_BUFFER,
1041 dst_target,
1042 0,
1043 dst_offset as _,
1044 query_range_size as _,
1045 );
1046 if let Some(buffer) = buffer {
1047 gl.delete_buffer(buffer)
1048 }
1049 }
1050 } else {
1051 let mut temp_query_results = self.temp_query_results.lock();
1052 temp_query_results.clear();
1053 for &query in
1054 queries[query_range.start as usize..query_range.end as usize].iter()
1055 {
1056 let mut result: u64 = 0;
1057 unsafe {
1058 if self
1059 .shared
1060 .private_caps
1061 .contains(PrivateCapabilities::QUERY_64BIT)
1062 {
1063 let result: *mut u64 = &mut result;
1064 gl.get_query_parameter_u64_with_offset(
1065 query,
1066 glow::QUERY_RESULT,
1067 result as usize,
1068 )
1069 } else {
1070 result =
1071 gl.get_query_parameter_u32(query, glow::QUERY_RESULT) as u64;
1072 }
1073 };
1074 temp_query_results.push(result);
1075 }
1076 let query_data = bytemuck::cast_slice(&temp_query_results);
1077 match dst.raw {
1078 Some(buffer) => {
1079 unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
1080 unsafe {
1081 gl.buffer_sub_data_u8_slice(
1082 dst_target,
1083 dst_offset as i32,
1084 query_data,
1085 )
1086 };
1087 }
1088 None => {
1089 let data = &mut lock(dst.data.as_ref().unwrap());
1090 let len = query_data.len().min(data.len());
1091 data[..len].copy_from_slice(&query_data[..len]);
1092 }
1093 }
1094 }
1095 }
1096 C::ResetFramebuffer { is_default } => {
1097 if is_default {
1098 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
1099 } else {
1100 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1101 unsafe {
1102 gl.framebuffer_texture_2d(
1103 glow::DRAW_FRAMEBUFFER,
1104 glow::DEPTH_STENCIL_ATTACHMENT,
1105 glow::TEXTURE_2D,
1106 None,
1107 0,
1108 )
1109 };
1110 for i in 0..self.shared.limits.max_color_attachments {
1111 let target = glow::COLOR_ATTACHMENT0 + i;
1112 unsafe {
1113 gl.framebuffer_texture_2d(
1114 glow::DRAW_FRAMEBUFFER,
1115 target,
1116 glow::TEXTURE_2D,
1117 None,
1118 0,
1119 )
1120 };
1121 }
1122 }
1123 unsafe { gl.color_mask(true, true, true, true) };
1124 unsafe { gl.depth_mask(true) };
1125 unsafe { gl.stencil_mask(!0) };
1126 unsafe { gl.disable(glow::DEPTH_TEST) };
1127 unsafe { gl.disable(glow::STENCIL_TEST) };
1128 unsafe { gl.disable(glow::SCISSOR_TEST) };
1129 }
1130 C::BindAttachment {
1131 attachment,
1132 ref view,
1133 depth_slice,
1134 sample_count,
1135 } => {
1136 unsafe {
1137 self.set_attachment(
1138 gl,
1139 glow::DRAW_FRAMEBUFFER,
1140 attachment,
1141 view,
1142 depth_slice,
1143 sample_count,
1144 )
1145 };
1146 }
1147 C::ResolveAttachment {
1148 attachment,
1149 ref dst,
1150 ref size,
1151 } => {
1152 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)) };
1153 unsafe { gl.read_buffer(attachment) };
1154 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
1155 unsafe {
1156 self.set_attachment(
1157 gl,
1158 glow::DRAW_FRAMEBUFFER,
1159 glow::COLOR_ATTACHMENT0,
1160 dst,
1161 None,
1162 1,
1163 )
1164 };
1165 unsafe {
1166 gl.blit_framebuffer(
1167 0,
1168 0,
1169 size.width as i32,
1170 size.height as i32,
1171 0,
1172 0,
1173 size.width as i32,
1174 size.height as i32,
1175 glow::COLOR_BUFFER_BIT,
1176 glow::NEAREST,
1177 )
1178 };
1179 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
1180 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1181 }
1182 C::InvalidateAttachments(ref list) => {
1183 if self
1184 .shared
1185 .private_caps
1186 .contains(PrivateCapabilities::INVALIDATE_FRAMEBUFFER)
1187 {
1188 unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) };
1189 }
1190 }
1191 C::SetDrawColorBuffers(count) => {
1192 self.draw_buffer_count.store(count, Ordering::Relaxed);
1193 let indices = (0..count as u32)
1194 .map(|i| glow::COLOR_ATTACHMENT0 + i)
1195 .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
1196 unsafe { gl.draw_buffers(&indices) };
1197 }
1198 C::ClearColorF {
1199 draw_buffer,
1200 ref color,
1201 is_srgb,
1202 } => {
1203 if self
1204 .shared
1205 .workarounds
1206 .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
1207 && is_srgb
1208 {
1209 unsafe { self.perform_shader_clear(gl, draw_buffer, *color) };
1210 } else {
1211 unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) };
1212 }
1213 }
1214 C::ClearColorU(draw_buffer, ref color) => {
1215 unsafe { gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, color) };
1216 }
1217 C::ClearColorI(draw_buffer, ref color) => {
1218 unsafe { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color) };
1219 }
1220 C::ClearDepth(depth) => {
1221 unsafe {
1224 gl.clear_depth_f32(depth);
1225 gl.clear(glow::DEPTH_BUFFER_BIT);
1226 }
1227 }
1228 C::ClearStencil(value) => {
1229 unsafe {
1232 gl.clear_stencil(value as i32);
1233 gl.clear(glow::STENCIL_BUFFER_BIT);
1234 }
1235 }
1236 C::ClearDepthAndStencil(depth, stencil_value) => {
1237 unsafe {
1240 gl.clear_depth_f32(depth);
1241 gl.clear_stencil(stencil_value as i32);
1242 gl.clear(glow::DEPTH_BUFFER_BIT | glow::STENCIL_BUFFER_BIT);
1243 }
1244 }
1245 C::BufferBarrier(raw, usage) => {
1246 let mut flags = 0;
1247 if usage.contains(wgt::BufferUses::VERTEX) {
1248 flags |= glow::VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1249 unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, Some(raw)) };
1250 unsafe { gl.vertex_attrib_pointer_f32(0, 1, glow::BYTE, true, 0, 0) };
1251 }
1252 if usage.contains(wgt::BufferUses::INDEX) {
1253 flags |= glow::ELEMENT_ARRAY_BARRIER_BIT;
1254 unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(raw)) };
1255 }
1256 if usage.contains(wgt::BufferUses::UNIFORM) {
1257 flags |= glow::UNIFORM_BARRIER_BIT;
1258 }
1259 if usage.contains(wgt::BufferUses::INDIRECT) {
1260 flags |= glow::COMMAND_BARRIER_BIT;
1261 unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(raw)) };
1262 }
1263 if usage.contains(wgt::BufferUses::COPY_SRC) {
1264 flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1265 unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(raw)) };
1266 }
1267 if usage.contains(wgt::BufferUses::COPY_DST) {
1268 flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1269 unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(raw)) };
1270 }
1271 if usage.intersects(wgt::BufferUses::MAP_READ | wgt::BufferUses::MAP_WRITE) {
1272 flags |= glow::BUFFER_UPDATE_BARRIER_BIT;
1273 }
1274 if usage.intersects(
1275 wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE,
1276 ) {
1277 flags |= glow::SHADER_STORAGE_BARRIER_BIT;
1278 }
1279 unsafe { gl.memory_barrier(flags) };
1280 }
1281 C::TextureBarrier(usage) => {
1286 let mut flags = 0;
1287 if usage.contains(wgt::TextureUses::RESOURCE) {
1288 flags |= glow::TEXTURE_FETCH_BARRIER_BIT;
1289 }
1290 if usage.intersects(
1291 wgt::TextureUses::STORAGE_READ_ONLY
1292 | wgt::TextureUses::STORAGE_WRITE_ONLY
1293 | wgt::TextureUses::STORAGE_READ_WRITE,
1294 ) {
1295 flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT;
1296 }
1297 if usage.intersects(wgt::TextureUses::COPY_SRC) {
1298 flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1299 }
1300 if usage.contains(wgt::TextureUses::COPY_DST) {
1301 flags |= glow::TEXTURE_UPDATE_BARRIER_BIT;
1302 }
1303 if usage.intersects(
1304 wgt::TextureUses::COLOR_TARGET
1305 | wgt::TextureUses::DEPTH_STENCIL_READ
1306 | wgt::TextureUses::DEPTH_STENCIL_WRITE,
1307 ) {
1308 flags |= glow::FRAMEBUFFER_BARRIER_BIT;
1309 }
1310 unsafe { gl.memory_barrier(flags) };
1311 }
1312 C::SetViewport {
1313 ref rect,
1314 ref depth,
1315 } => {
1316 unsafe { gl.viewport(rect.x, rect.y, rect.w, rect.h) };
1317 unsafe { gl.depth_range_f32(depth.start, depth.end) };
1318 }
1319 C::SetScissor(ref rect) => {
1320 unsafe { gl.scissor(rect.x, rect.y, rect.w, rect.h) };
1321 unsafe { gl.enable(glow::SCISSOR_TEST) };
1322 }
1323 C::SetStencilFunc {
1324 face,
1325 function,
1326 reference,
1327 read_mask,
1328 } => {
1329 unsafe { gl.stencil_func_separate(face, function, reference as i32, read_mask) };
1330 }
1331 C::SetStencilOps {
1332 face,
1333 write_mask,
1334 ref ops,
1335 } => {
1336 unsafe { gl.stencil_mask_separate(face, write_mask) };
1337 unsafe { gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass) };
1338 }
1339 C::SetVertexAttribute {
1340 buffer,
1341 ref buffer_desc,
1342 attribute_desc: ref vat,
1343 } => {
1344 unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, buffer) };
1345 unsafe { gl.enable_vertex_attrib_array(vat.location) };
1346
1347 if buffer.is_none() {
1348 match vat.format_desc.attrib_kind {
1349 super::VertexAttribKind::Float => unsafe {
1350 gl.vertex_attrib_format_f32(
1351 vat.location,
1352 vat.format_desc.element_count,
1353 vat.format_desc.element_format,
1354 true, vat.offset,
1356 )
1357 },
1358 super::VertexAttribKind::Integer => unsafe {
1359 gl.vertex_attrib_format_i32(
1360 vat.location,
1361 vat.format_desc.element_count,
1362 vat.format_desc.element_format,
1363 vat.offset,
1364 )
1365 },
1366 }
1367
1368 unsafe { gl.vertex_attrib_binding(vat.location, vat.buffer_index) };
1371 } else {
1372 match vat.format_desc.attrib_kind {
1373 super::VertexAttribKind::Float => unsafe {
1374 gl.vertex_attrib_pointer_f32(
1375 vat.location,
1376 vat.format_desc.element_count,
1377 vat.format_desc.element_format,
1378 true, buffer_desc.stride as i32,
1380 vat.offset as i32,
1381 )
1382 },
1383 super::VertexAttribKind::Integer => unsafe {
1384 gl.vertex_attrib_pointer_i32(
1385 vat.location,
1386 vat.format_desc.element_count,
1387 vat.format_desc.element_format,
1388 buffer_desc.stride as i32,
1389 vat.offset as i32,
1390 )
1391 },
1392 }
1393 unsafe { gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32) };
1394 }
1395 }
1396 C::UnsetVertexAttribute(location) => {
1397 unsafe { gl.disable_vertex_attrib_array(location) };
1398 }
1399 C::SetVertexBuffer {
1400 index,
1401 ref buffer,
1402 ref buffer_desc,
1403 } => {
1404 unsafe { gl.vertex_binding_divisor(index, buffer_desc.step as u32) };
1405 unsafe {
1406 gl.bind_vertex_buffer(
1407 index,
1408 Some(buffer.raw),
1409 buffer.offset as i32,
1410 buffer_desc.stride as i32,
1411 )
1412 };
1413 }
1414 C::SetDepth(ref depth) => {
1415 unsafe { gl.depth_func(depth.function) };
1416 unsafe { gl.depth_mask(depth.mask) };
1417 }
1418 C::SetDepthBias(bias) => {
1419 if bias.is_enabled() {
1420 unsafe { gl.enable(glow::POLYGON_OFFSET_FILL) };
1421 unsafe { gl.polygon_offset(bias.slope_scale, bias.constant as f32) };
1422 } else {
1423 unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
1424 }
1425 }
1426 C::ConfigureDepthStencil(aspects) => {
1427 if aspects.contains(crate::FormatAspects::DEPTH) {
1428 unsafe { gl.enable(glow::DEPTH_TEST) };
1429 } else {
1430 unsafe { gl.disable(glow::DEPTH_TEST) };
1431 }
1432 if aspects.contains(crate::FormatAspects::STENCIL) {
1433 unsafe { gl.enable(glow::STENCIL_TEST) };
1434 } else {
1435 unsafe { gl.disable(glow::STENCIL_TEST) };
1436 }
1437 }
1438 C::SetAlphaToCoverage(enabled) => {
1439 if enabled {
1440 unsafe { gl.enable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1441 } else {
1442 unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1443 }
1444 }
1445 C::SetProgram(program) => {
1446 unsafe { gl.use_program(Some(program)) };
1447 }
1448 C::SetPrimitive(ref state) => {
1449 unsafe { gl.front_face(state.front_face) };
1450 if state.cull_face != 0 {
1451 unsafe { gl.enable(glow::CULL_FACE) };
1452 unsafe { gl.cull_face(state.cull_face) };
1453 } else {
1454 unsafe { gl.disable(glow::CULL_FACE) };
1455 }
1456 if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
1457 if state.unclipped_depth {
1459 unsafe { gl.enable(glow::DEPTH_CLAMP) };
1460 } else {
1461 unsafe { gl.disable(glow::DEPTH_CLAMP) };
1462 }
1463 }
1464 if self.features.contains(wgt::Features::POLYGON_MODE_LINE) {
1466 unsafe { gl.polygon_mode(glow::FRONT_AND_BACK, state.polygon_mode) };
1467 }
1468 }
1469 C::SetBlendConstant(c) => {
1470 unsafe { gl.blend_color(c[0], c[1], c[2], c[3]) };
1471 }
1472 C::SetColorTarget {
1473 draw_buffer_index,
1474 desc: super::ColorTargetDesc { mask, ref blend },
1475 } => {
1476 use wgt::ColorWrites as Cw;
1477 if let Some(index) = draw_buffer_index {
1478 unsafe {
1479 gl.color_mask_draw_buffer(
1480 index,
1481 mask.contains(Cw::RED),
1482 mask.contains(Cw::GREEN),
1483 mask.contains(Cw::BLUE),
1484 mask.contains(Cw::ALPHA),
1485 )
1486 };
1487 if let Some(ref blend) = *blend {
1488 unsafe { gl.enable_draw_buffer(glow::BLEND, index) };
1489 if blend.color != blend.alpha {
1490 unsafe {
1491 gl.blend_equation_separate_draw_buffer(
1492 index,
1493 blend.color.equation,
1494 blend.alpha.equation,
1495 )
1496 };
1497 unsafe {
1498 gl.blend_func_separate_draw_buffer(
1499 index,
1500 blend.color.src,
1501 blend.color.dst,
1502 blend.alpha.src,
1503 blend.alpha.dst,
1504 )
1505 };
1506 } else {
1507 unsafe { gl.blend_equation_draw_buffer(index, blend.color.equation) };
1508 unsafe {
1509 gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst)
1510 };
1511 }
1512 } else {
1513 unsafe { gl.disable_draw_buffer(glow::BLEND, index) };
1514 }
1515 } else {
1516 unsafe {
1517 gl.color_mask(
1518 mask.contains(Cw::RED),
1519 mask.contains(Cw::GREEN),
1520 mask.contains(Cw::BLUE),
1521 mask.contains(Cw::ALPHA),
1522 )
1523 };
1524 if let Some(ref blend) = *blend {
1525 unsafe { gl.enable(glow::BLEND) };
1526 if blend.color != blend.alpha {
1527 unsafe {
1528 gl.blend_equation_separate(
1529 blend.color.equation,
1530 blend.alpha.equation,
1531 )
1532 };
1533 unsafe {
1534 gl.blend_func_separate(
1535 blend.color.src,
1536 blend.color.dst,
1537 blend.alpha.src,
1538 blend.alpha.dst,
1539 )
1540 };
1541 } else {
1542 unsafe { gl.blend_equation(blend.color.equation) };
1543 unsafe { gl.blend_func(blend.color.src, blend.color.dst) };
1544 }
1545 } else {
1546 unsafe { gl.disable(glow::BLEND) };
1547 }
1548 }
1549 }
1550 C::BindBuffer {
1551 target,
1552 slot,
1553 buffer,
1554 offset,
1555 size,
1556 } => {
1557 unsafe { gl.bind_buffer_range(target, slot, Some(buffer), offset, size) };
1558 }
1559 C::BindSampler(texture_index, sampler) => {
1560 unsafe { gl.bind_sampler(texture_index, sampler) };
1561 }
1562 C::BindTexture {
1563 slot,
1564 texture,
1565 target,
1566 aspects,
1567 ref mip_levels,
1568 } => {
1569 unsafe { gl.active_texture(glow::TEXTURE0 + slot) };
1570 unsafe { gl.bind_texture(target, Some(texture)) };
1571
1572 unsafe {
1573 gl.tex_parameter_i32(target, glow::TEXTURE_BASE_LEVEL, mip_levels.start as i32)
1574 };
1575 unsafe {
1576 gl.tex_parameter_i32(
1577 target,
1578 glow::TEXTURE_MAX_LEVEL,
1579 (mip_levels.end - 1) as i32,
1580 )
1581 };
1582
1583 let version = gl.version();
1584 let is_min_es_3_1 = version.is_embedded && (version.major, version.minor) >= (3, 1);
1585 let is_min_4_3 = !version.is_embedded && (version.major, version.minor) >= (4, 3);
1586 if is_min_es_3_1 || is_min_4_3 {
1587 let mode = match aspects {
1588 crate::FormatAspects::DEPTH => Some(glow::DEPTH_COMPONENT),
1589 crate::FormatAspects::STENCIL => Some(glow::STENCIL_INDEX),
1590 _ => None,
1591 };
1592 if let Some(mode) = mode {
1593 unsafe {
1594 gl.tex_parameter_i32(
1595 target,
1596 glow::DEPTH_STENCIL_TEXTURE_MODE,
1597 mode as _,
1598 )
1599 };
1600 }
1601 }
1602 }
1603 C::BindImage { slot, ref binding } => {
1604 unsafe {
1605 gl.bind_image_texture(
1606 slot,
1607 Some(binding.raw),
1608 binding.mip_level as i32,
1609 binding.array_layer.is_none(),
1610 binding.array_layer.unwrap_or_default() as i32,
1611 binding.access,
1612 binding.format,
1613 )
1614 };
1615 }
1616 C::InsertDebugMarker(ref range) => {
1617 let marker = extract_marker(data_bytes, range);
1618 unsafe {
1619 if self
1620 .shared
1621 .private_caps
1622 .contains(PrivateCapabilities::DEBUG_FNS)
1623 {
1624 gl.debug_message_insert(
1625 glow::DEBUG_SOURCE_APPLICATION,
1626 glow::DEBUG_TYPE_MARKER,
1627 DEBUG_ID,
1628 glow::DEBUG_SEVERITY_NOTIFICATION,
1629 to_debug_str(marker),
1630 )
1631 }
1632 };
1633 }
1634 C::PushDebugGroup(ref range) => {
1635 let marker = extract_marker(data_bytes, range);
1636 unsafe {
1637 if self
1638 .shared
1639 .private_caps
1640 .contains(PrivateCapabilities::DEBUG_FNS)
1641 {
1642 gl.push_debug_group(
1643 glow::DEBUG_SOURCE_APPLICATION,
1644 DEBUG_ID,
1645 to_debug_str(marker),
1646 )
1647 }
1648 };
1649 }
1650 C::PopDebugGroup => {
1651 unsafe {
1652 if self
1653 .shared
1654 .private_caps
1655 .contains(PrivateCapabilities::DEBUG_FNS)
1656 {
1657 gl.pop_debug_group()
1658 }
1659 };
1660 }
1661 C::SetImmediates {
1662 ref uniform,
1663 offset,
1664 } => {
1665 fn get_data<T, const COUNT: usize>(data: &[u8], offset: u32) -> [T; COUNT]
1666 where
1667 [T; COUNT]: bytemuck::AnyBitPattern,
1668 {
1669 let data_required = size_of::<T>() * COUNT;
1670 let raw = &data[(offset as usize)..][..data_required];
1671 bytemuck::pod_read_unaligned(raw)
1672 }
1673
1674 let location = Some(&uniform.location);
1675
1676 match uniform.ty {
1677 naga::TypeInner::Scalar(naga::Scalar::F32) => {
1681 let data = get_data::<f32, 1>(data_bytes, offset)[0];
1682 unsafe { gl.uniform_1_f32(location, data) };
1683 }
1684 naga::TypeInner::Vector {
1685 size: naga::VectorSize::Bi,
1686 scalar: naga::Scalar::F32,
1687 } => {
1688 let data = &get_data::<f32, 2>(data_bytes, offset);
1689 unsafe { gl.uniform_2_f32_slice(location, data) };
1690 }
1691 naga::TypeInner::Vector {
1692 size: naga::VectorSize::Tri,
1693 scalar: naga::Scalar::F32,
1694 } => {
1695 let data = &get_data::<f32, 3>(data_bytes, offset);
1696 unsafe { gl.uniform_3_f32_slice(location, data) };
1697 }
1698 naga::TypeInner::Vector {
1699 size: naga::VectorSize::Quad,
1700 scalar: naga::Scalar::F32,
1701 } => {
1702 let data = &get_data::<f32, 4>(data_bytes, offset);
1703 unsafe { gl.uniform_4_f32_slice(location, data) };
1704 }
1705
1706 naga::TypeInner::Scalar(naga::Scalar::I32) => {
1710 let data = get_data::<i32, 1>(data_bytes, offset)[0];
1711 unsafe { gl.uniform_1_i32(location, data) };
1712 }
1713 naga::TypeInner::Vector {
1714 size: naga::VectorSize::Bi,
1715 scalar: naga::Scalar::I32,
1716 } => {
1717 let data = &get_data::<i32, 2>(data_bytes, offset);
1718 unsafe { gl.uniform_2_i32_slice(location, data) };
1719 }
1720 naga::TypeInner::Vector {
1721 size: naga::VectorSize::Tri,
1722 scalar: naga::Scalar::I32,
1723 } => {
1724 let data = &get_data::<i32, 3>(data_bytes, offset);
1725 unsafe { gl.uniform_3_i32_slice(location, data) };
1726 }
1727 naga::TypeInner::Vector {
1728 size: naga::VectorSize::Quad,
1729 scalar: naga::Scalar::I32,
1730 } => {
1731 let data = &get_data::<i32, 4>(data_bytes, offset);
1732 unsafe { gl.uniform_4_i32_slice(location, data) };
1733 }
1734
1735 naga::TypeInner::Scalar(naga::Scalar::U32) => {
1739 let data = get_data::<u32, 1>(data_bytes, offset)[0];
1740 unsafe { gl.uniform_1_u32(location, data) };
1741 }
1742 naga::TypeInner::Vector {
1743 size: naga::VectorSize::Bi,
1744 scalar: naga::Scalar::U32,
1745 } => {
1746 let data = &get_data::<u32, 2>(data_bytes, offset);
1747 unsafe { gl.uniform_2_u32_slice(location, data) };
1748 }
1749 naga::TypeInner::Vector {
1750 size: naga::VectorSize::Tri,
1751 scalar: naga::Scalar::U32,
1752 } => {
1753 let data = &get_data::<u32, 3>(data_bytes, offset);
1754 unsafe { gl.uniform_3_u32_slice(location, data) };
1755 }
1756 naga::TypeInner::Vector {
1757 size: naga::VectorSize::Quad,
1758 scalar: naga::Scalar::U32,
1759 } => {
1760 let data = &get_data::<u32, 4>(data_bytes, offset);
1761 unsafe { gl.uniform_4_u32_slice(location, data) };
1762 }
1763
1764 naga::TypeInner::Matrix {
1768 columns: naga::VectorSize::Bi,
1769 rows: naga::VectorSize::Bi,
1770 scalar: naga::Scalar::F32,
1771 } => {
1772 let data = &get_data::<f32, 4>(data_bytes, offset);
1773 unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) };
1774 }
1775 naga::TypeInner::Matrix {
1776 columns: naga::VectorSize::Bi,
1777 rows: naga::VectorSize::Tri,
1778 scalar: naga::Scalar::F32,
1779 } => {
1780 let unpacked_data = &get_data::<f32, 8>(data_bytes, offset);
1782 #[rustfmt::skip]
1783 let packed_data = [
1784 unpacked_data[0], unpacked_data[1], unpacked_data[2],
1785 unpacked_data[4], unpacked_data[5], unpacked_data[6],
1786 ];
1787 unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) };
1788 }
1789 naga::TypeInner::Matrix {
1790 columns: naga::VectorSize::Bi,
1791 rows: naga::VectorSize::Quad,
1792 scalar: naga::Scalar::F32,
1793 } => {
1794 let data = &get_data::<f32, 8>(data_bytes, offset);
1795 unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) };
1796 }
1797
1798 naga::TypeInner::Matrix {
1802 columns: naga::VectorSize::Tri,
1803 rows: naga::VectorSize::Bi,
1804 scalar: naga::Scalar::F32,
1805 } => {
1806 let data = &get_data::<f32, 6>(data_bytes, offset);
1807 unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) };
1808 }
1809 naga::TypeInner::Matrix {
1810 columns: naga::VectorSize::Tri,
1811 rows: naga::VectorSize::Tri,
1812 scalar: naga::Scalar::F32,
1813 } => {
1814 let unpacked_data = &get_data::<f32, 12>(data_bytes, offset);
1816 #[rustfmt::skip]
1817 let packed_data = [
1818 unpacked_data[0], unpacked_data[1], unpacked_data[2],
1819 unpacked_data[4], unpacked_data[5], unpacked_data[6],
1820 unpacked_data[8], unpacked_data[9], unpacked_data[10],
1821 ];
1822 unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) };
1823 }
1824 naga::TypeInner::Matrix {
1825 columns: naga::VectorSize::Tri,
1826 rows: naga::VectorSize::Quad,
1827 scalar: naga::Scalar::F32,
1828 } => {
1829 let data = &get_data::<f32, 12>(data_bytes, offset);
1830 unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) };
1831 }
1832
1833 naga::TypeInner::Matrix {
1837 columns: naga::VectorSize::Quad,
1838 rows: naga::VectorSize::Bi,
1839 scalar: naga::Scalar::F32,
1840 } => {
1841 let data = &get_data::<f32, 8>(data_bytes, offset);
1842 unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) };
1843 }
1844 naga::TypeInner::Matrix {
1845 columns: naga::VectorSize::Quad,
1846 rows: naga::VectorSize::Tri,
1847 scalar: naga::Scalar::F32,
1848 } => {
1849 let unpacked_data = &get_data::<f32, 16>(data_bytes, offset);
1851 #[rustfmt::skip]
1852 let packed_data = [
1853 unpacked_data[0], unpacked_data[1], unpacked_data[2],
1854 unpacked_data[4], unpacked_data[5], unpacked_data[6],
1855 unpacked_data[8], unpacked_data[9], unpacked_data[10],
1856 unpacked_data[12], unpacked_data[13], unpacked_data[14],
1857 ];
1858 unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) };
1859 }
1860 naga::TypeInner::Matrix {
1861 columns: naga::VectorSize::Quad,
1862 rows: naga::VectorSize::Quad,
1863 scalar: naga::Scalar::F32,
1864 } => {
1865 let data = &get_data::<f32, 16>(data_bytes, offset);
1866 unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) };
1867 }
1868 _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
1869 }
1870 }
1871 C::SetClipDistances {
1872 old_count,
1873 new_count,
1874 } => {
1875 for i in new_count..old_count {
1877 unsafe { gl.disable(glow::CLIP_DISTANCE0 + i) };
1878 }
1879
1880 for i in old_count..new_count {
1882 unsafe { gl.enable(glow::CLIP_DISTANCE0 + i) };
1883 }
1884 }
1885 }
1886 }
1887}
1888
1889impl crate::Queue for super::Queue {
1890 type A = super::Api;
1891
1892 unsafe fn submit(
1893 &self,
1894 command_buffers: &[&super::CommandBuffer],
1895 _surface_textures: &[&super::Texture],
1896 (signal_fence, signal_value): (&mut super::Fence, crate::FenceValue),
1897 ) -> Result<(), crate::DeviceError> {
1898 let shared = Arc::clone(&self.shared);
1899 let gl = &shared.context.lock();
1900 for cmd_buf in command_buffers.iter() {
1901 unsafe { self.reset_state(gl) };
1906 if let Some(ref label) = cmd_buf.label {
1907 if self
1908 .shared
1909 .private_caps
1910 .contains(PrivateCapabilities::DEBUG_FNS)
1911 {
1912 unsafe {
1913 gl.push_debug_group(
1914 glow::DEBUG_SOURCE_APPLICATION,
1915 DEBUG_ID,
1916 to_debug_str(label),
1917 )
1918 };
1919 }
1920 }
1921
1922 for command in cmd_buf.commands.iter() {
1923 unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
1924 }
1925
1926 if cmd_buf.label.is_some()
1927 && self
1928 .shared
1929 .private_caps
1930 .contains(PrivateCapabilities::DEBUG_FNS)
1931 {
1932 unsafe { gl.pop_debug_group() };
1933 }
1934 }
1935
1936 signal_fence.maintain(gl);
1937 signal_fence.signal(gl, signal_value)?;
1938
1939 unsafe { gl.flush() };
1943
1944 Ok(())
1945 }
1946
1947 unsafe fn present(
1948 &self,
1949 surface: &super::Surface,
1950 texture: super::Texture,
1951 ) -> Result<(), crate::SurfaceError> {
1952 unsafe { surface.present(texture, &self.shared.context) }
1953 }
1954
1955 unsafe fn get_timestamp_period(&self) -> f32 {
1956 1.0
1957 }
1958}
1959
1960#[cfg(send_sync)]
1961unsafe impl Sync for super::Queue {}
1962#[cfg(send_sync)]
1963unsafe impl Send for super::Queue {}