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