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