wgpu_hal/gles/
queue.rs

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