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