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