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