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