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