Skip to main content

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, 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_family = "wasm", 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                    let mut map_state = dst.map_state.lock();
381                    map_state.data.as_mut().unwrap().as_mut_slice()
382                        [range.start as usize..range.end as usize]
383                        .fill(0);
384                }
385            },
386            C::CopyBufferToBuffer {
387                ref src,
388                src_target,
389                ref dst,
390                dst_target,
391                copy,
392            } => {
393                let copy_src_target = glow::COPY_READ_BUFFER;
394                let is_index_buffer_only_element_dst = !self
395                    .shared
396                    .private_caps
397                    .contains(PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
398                    && dst_target == glow::ELEMENT_ARRAY_BUFFER
399                    || src_target == glow::ELEMENT_ARRAY_BUFFER;
400
401                // WebGL not allowed to copy data from other targets to element buffer and can't copy element data to other buffers
402                let copy_dst_target = if is_index_buffer_only_element_dst {
403                    glow::ELEMENT_ARRAY_BUFFER
404                } else {
405                    glow::COPY_WRITE_BUFFER
406                };
407                let size = copy.size.get() as usize;
408                match (src.raw, dst.raw) {
409                    (Some(ref src), Some(ref dst)) => {
410                        unsafe { gl.bind_buffer(copy_src_target, Some(*src)) };
411                        unsafe { gl.bind_buffer(copy_dst_target, Some(*dst)) };
412                        unsafe {
413                            gl.copy_buffer_sub_data(
414                                copy_src_target,
415                                copy_dst_target,
416                                copy.src_offset as _,
417                                copy.dst_offset as _,
418                                copy.size.get() as _,
419                            )
420                        };
421                    }
422                    (Some(src), None) => {
423                        let mut map_state = dst.map_state.lock();
424                        let dst_data = &mut map_state.data.as_mut().unwrap().as_mut_slice()
425                            [copy.dst_offset as usize..copy.dst_offset as usize + size];
426
427                        unsafe { gl.bind_buffer(copy_src_target, Some(src)) };
428                        unsafe {
429                            self.shared.get_buffer_sub_data(
430                                gl,
431                                copy_src_target,
432                                copy.src_offset as i32,
433                                dst_data,
434                            )
435                        };
436                    }
437                    (None, Some(dst)) => {
438                        let map_state = src.map_state.lock();
439                        let src_data = &map_state.data.as_ref().unwrap().as_slice()
440                            [copy.src_offset as usize..copy.src_offset as usize + size];
441                        unsafe { gl.bind_buffer(copy_dst_target, Some(dst)) };
442                        unsafe {
443                            gl.buffer_sub_data_u8_slice(
444                                copy_dst_target,
445                                copy.dst_offset as i32,
446                                src_data,
447                            )
448                        };
449                    }
450                    (None, None) => {
451                        todo!()
452                    }
453                }
454                unsafe { gl.bind_buffer(copy_src_target, None) };
455                if is_index_buffer_only_element_dst {
456                    unsafe {
457                        gl.bind_buffer(
458                            glow::ELEMENT_ARRAY_BUFFER,
459                            *self.current_index_buffer.lock(),
460                        )
461                    };
462                } else {
463                    unsafe { gl.bind_buffer(copy_dst_target, None) };
464                }
465            }
466            #[cfg(webgl)]
467            C::CopyExternalImageToTexture {
468                ref src,
469                dst,
470                dst_target,
471                dst_format,
472                dst_premultiplication,
473                ref copy,
474            } => {
475                const UNPACK_FLIP_Y_WEBGL: u32 =
476                    web_sys::WebGl2RenderingContext::UNPACK_FLIP_Y_WEBGL;
477                const UNPACK_PREMULTIPLY_ALPHA_WEBGL: u32 =
478                    web_sys::WebGl2RenderingContext::UNPACK_PREMULTIPLY_ALPHA_WEBGL;
479
480                unsafe {
481                    if src.flip_y {
482                        gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, true);
483                    }
484                    if dst_premultiplication {
485                        gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
486                    }
487                }
488
489                unsafe { gl.bind_texture(dst_target, Some(dst)) };
490                let format_desc = self.shared.describe_texture_format(dst_format);
491                if is_layered_target(dst_target) {
492                    let z_offset = get_z_offset(dst_target, &copy.dst_base);
493
494                    match src.source {
495                        wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
496                            gl.tex_sub_image_3d_with_image_bitmap(
497                                dst_target,
498                                copy.dst_base.mip_level as i32,
499                                copy.dst_base.origin.x as i32,
500                                copy.dst_base.origin.y as i32,
501                                z_offset as i32,
502                                copy.size.width as i32,
503                                copy.size.height as i32,
504                                copy.size.depth as i32,
505                                format_desc.external,
506                                format_desc.data_type,
507                                b,
508                            );
509                        },
510                        wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
511                            gl.tex_sub_image_3d_with_html_image_element(
512                                dst_target,
513                                copy.dst_base.mip_level as i32,
514                                copy.dst_base.origin.x as i32,
515                                copy.dst_base.origin.y as i32,
516                                z_offset as i32,
517                                copy.size.width as i32,
518                                copy.size.height as i32,
519                                copy.size.depth as i32,
520                                format_desc.external,
521                                format_desc.data_type,
522                                i,
523                            );
524                        },
525                        wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
526                            gl.tex_sub_image_3d_with_html_video_element(
527                                dst_target,
528                                copy.dst_base.mip_level as i32,
529                                copy.dst_base.origin.x as i32,
530                                copy.dst_base.origin.y as i32,
531                                z_offset as i32,
532                                copy.size.width as i32,
533                                copy.size.height as i32,
534                                copy.size.depth as i32,
535                                format_desc.external,
536                                format_desc.data_type,
537                                v,
538                            );
539                        },
540                        wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
541                            gl.tex_sub_image_3d_with_video_frame(
542                                dst_target,
543                                copy.dst_base.mip_level as i32,
544                                copy.dst_base.origin.x as i32,
545                                copy.dst_base.origin.y as i32,
546                                z_offset as i32,
547                                copy.size.width as i32,
548                                copy.size.height as i32,
549                                copy.size.depth as i32,
550                                format_desc.external,
551                                format_desc.data_type,
552                                v,
553                            )
554                        },
555                        wgt::ExternalImageSource::ImageData(ref i) => unsafe {
556                            gl.tex_sub_image_3d_with_image_data(
557                                dst_target,
558                                copy.dst_base.mip_level as i32,
559                                copy.dst_base.origin.x as i32,
560                                copy.dst_base.origin.y as i32,
561                                z_offset as i32,
562                                copy.size.width as i32,
563                                copy.size.height as i32,
564                                copy.size.depth as i32,
565                                format_desc.external,
566                                format_desc.data_type,
567                                i,
568                            );
569                        },
570                        wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
571                            gl.tex_sub_image_3d_with_html_canvas_element(
572                                dst_target,
573                                copy.dst_base.mip_level as i32,
574                                copy.dst_base.origin.x as i32,
575                                copy.dst_base.origin.y as i32,
576                                z_offset as i32,
577                                copy.size.width as i32,
578                                copy.size.height as i32,
579                                copy.size.depth as i32,
580                                format_desc.external,
581                                format_desc.data_type,
582                                c,
583                            );
584                        },
585                        wgt::ExternalImageSource::OffscreenCanvas(ref c) => unsafe {
586                            // WebGL2's `texSubImage3D` accepts any `TexImageSource`,
587                            // including `OffscreenCanvas`, but web-sys 0.3.x generates
588                            // no typed overload for it. Re-wrap the same JS object as
589                            // `HtmlCanvasElement` — a type-erased pass-through, not a
590                            // conversion; the browser dispatches on the real object.
591                            // Tracked in wasm-bindgen PR#5312.
592                            use wasm_bindgen::JsCast as _;
593                            gl.tex_sub_image_3d_with_html_canvas_element(
594                                dst_target,
595                                copy.dst_base.mip_level as i32,
596                                copy.dst_base.origin.x as i32,
597                                copy.dst_base.origin.y as i32,
598                                z_offset as i32,
599                                copy.size.width as i32,
600                                copy.size.height as i32,
601                                copy.size.depth as i32,
602                                format_desc.external,
603                                format_desc.data_type,
604                                c.unchecked_ref(),
605                            );
606                        },
607                    }
608                } else {
609                    let dst_target = get_2d_target(dst_target, copy.dst_base.array_layer);
610
611                    match src.source {
612                        wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
613                            gl.tex_sub_image_2d_with_image_bitmap_and_width_and_height(
614                                dst_target,
615                                copy.dst_base.mip_level as i32,
616                                copy.dst_base.origin.x as i32,
617                                copy.dst_base.origin.y as i32,
618                                copy.size.width as i32,
619                                copy.size.height as i32,
620                                format_desc.external,
621                                format_desc.data_type,
622                                b,
623                            );
624                        },
625                        wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
626                            gl.tex_sub_image_2d_with_html_image_and_width_and_height(
627                                dst_target,
628                                copy.dst_base.mip_level as i32,
629                                copy.dst_base.origin.x as i32,
630                                copy.dst_base.origin.y as i32,
631                                copy.size.width as i32,
632                                copy.size.height as i32,
633                                format_desc.external,
634                                format_desc.data_type,
635                                i,
636                            )
637                        },
638                        wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
639                            gl.tex_sub_image_2d_with_html_video_and_width_and_height(
640                                dst_target,
641                                copy.dst_base.mip_level as i32,
642                                copy.dst_base.origin.x as i32,
643                                copy.dst_base.origin.y as i32,
644                                copy.size.width as i32,
645                                copy.size.height as i32,
646                                format_desc.external,
647                                format_desc.data_type,
648                                v,
649                            )
650                        },
651                        wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
652                            gl.tex_sub_image_2d_with_video_frame_and_width_and_height(
653                                dst_target,
654                                copy.dst_base.mip_level as i32,
655                                copy.dst_base.origin.x as i32,
656                                copy.dst_base.origin.y as i32,
657                                copy.size.width as i32,
658                                copy.size.height as i32,
659                                format_desc.external,
660                                format_desc.data_type,
661                                v,
662                            )
663                        },
664                        wgt::ExternalImageSource::ImageData(ref i) => unsafe {
665                            gl.tex_sub_image_2d_with_image_data_and_width_and_height(
666                                dst_target,
667                                copy.dst_base.mip_level as i32,
668                                copy.dst_base.origin.x as i32,
669                                copy.dst_base.origin.y as i32,
670                                copy.size.width as i32,
671                                copy.size.height as i32,
672                                format_desc.external,
673                                format_desc.data_type,
674                                i,
675                            );
676                        },
677                        wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
678                            gl.tex_sub_image_2d_with_html_canvas_and_width_and_height(
679                                dst_target,
680                                copy.dst_base.mip_level as i32,
681                                copy.dst_base.origin.x as i32,
682                                copy.dst_base.origin.y as i32,
683                                copy.size.width as i32,
684                                copy.size.height as i32,
685                                format_desc.external,
686                                format_desc.data_type,
687                                c,
688                            )
689                        },
690                        wgt::ExternalImageSource::OffscreenCanvas(ref c) => unsafe {
691                            // Same `TexImageSource` pass-through as the 3D path above:
692                            // web-sys 0.3.x has no `OffscreenCanvas` overload, so the
693                            // handle rides the `HtmlCanvasElement` binding unchanged.
694                            use wasm_bindgen::JsCast as _;
695                            gl.tex_sub_image_2d_with_html_canvas_and_width_and_height(
696                                dst_target,
697                                copy.dst_base.mip_level as i32,
698                                copy.dst_base.origin.x as i32,
699                                copy.dst_base.origin.y as i32,
700                                copy.size.width as i32,
701                                copy.size.height as i32,
702                                format_desc.external,
703                                format_desc.data_type,
704                                c.unchecked_ref(),
705                            )
706                        },
707                    }
708                }
709
710                unsafe {
711                    if src.flip_y {
712                        gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, false);
713                    }
714                    if dst_premultiplication {
715                        gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
716                    }
717                }
718            }
719            C::CopyTextureToTexture {
720                src,
721                src_target,
722                dst,
723                dst_target,
724                ref copy,
725            } => {
726                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
727                unsafe { gl.bind_texture(dst_target, Some(dst)) };
728
729                // The read framebuffer holds a single 2D slice at a time, so a copy of
730                // depth > 1 is issued one slice per iteration.
731                for z in 0..copy.size.depth {
732                    if is_layered_target(src_target) {
733                        //TODO: handle GLES without framebuffer_texture_3d
734                        unsafe {
735                            gl.framebuffer_texture_layer(
736                                glow::READ_FRAMEBUFFER,
737                                glow::COLOR_ATTACHMENT0,
738                                Some(src),
739                                copy.src_base.mip_level as i32,
740                                (get_z_offset(src_target, &copy.src_base) + z) as i32,
741                            )
742                        };
743                    } else {
744                        unsafe {
745                            gl.framebuffer_texture_2d(
746                                glow::READ_FRAMEBUFFER,
747                                glow::COLOR_ATTACHMENT0,
748                                get_2d_target(src_target, copy.src_base.array_layer + z),
749                                Some(src),
750                                copy.src_base.mip_level as i32,
751                            )
752                        };
753                    }
754
755                    if is_layered_target(dst_target) {
756                        unsafe {
757                            gl.copy_tex_sub_image_3d(
758                                dst_target,
759                                copy.dst_base.mip_level as i32,
760                                copy.dst_base.origin.x as i32,
761                                copy.dst_base.origin.y as i32,
762                                (get_z_offset(dst_target, &copy.dst_base) + z) as i32,
763                                copy.src_base.origin.x as i32,
764                                copy.src_base.origin.y as i32,
765                                copy.size.width as i32,
766                                copy.size.height as i32,
767                            )
768                        };
769                    } else {
770                        unsafe {
771                            gl.copy_tex_sub_image_2d(
772                                get_2d_target(dst_target, copy.dst_base.array_layer + z),
773                                copy.dst_base.mip_level as i32,
774                                copy.dst_base.origin.x as i32,
775                                copy.dst_base.origin.y as i32,
776                                copy.src_base.origin.x as i32,
777                                copy.src_base.origin.y as i32,
778                                copy.size.width as i32,
779                                copy.size.height as i32,
780                            )
781                        };
782                    }
783                }
784            }
785            C::CopyBufferToTexture {
786                ref src,
787                src_target: _,
788                dst,
789                dst_target,
790                dst_format,
791                ref copy,
792            } => {
793                let (block_width, block_height) = dst_format.block_dimensions();
794                let block_size = dst_format.block_copy_size(None).unwrap();
795                let format_desc = self.shared.describe_texture_format(dst_format);
796                let row_texels = copy
797                    .buffer_layout
798                    .bytes_per_row
799                    .map_or(0, |bpr| block_width * bpr / block_size);
800                let column_texels = copy
801                    .buffer_layout
802                    .rows_per_image
803                    .map_or(0, |rpi| block_height * rpi);
804
805                unsafe { gl.bind_texture(dst_target, Some(dst)) };
806                unsafe { gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32) };
807                unsafe { gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32) };
808                let mut unbind_unpack_buffer = false;
809                if !dst_format.is_compressed() {
810                    let map_state;
811                    let unpack_data = match src.raw {
812                        Some(buffer) => {
813                            unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
814                            unbind_unpack_buffer = true;
815                            glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32)
816                        }
817                        None => {
818                            map_state = src.map_state.lock();
819                            let src_data = &map_state.data.as_ref().unwrap().as_slice()
820                                [copy.buffer_layout.offset as usize..];
821                            glow::PixelUnpackData::Slice(Some(src_data))
822                        }
823                    };
824                    if is_layered_target(dst_target) {
825                        unsafe {
826                            gl.tex_sub_image_3d(
827                                dst_target,
828                                copy.texture_base.mip_level as i32,
829                                copy.texture_base.origin.x as i32,
830                                copy.texture_base.origin.y as i32,
831                                get_z_offset(dst_target, &copy.texture_base) as i32,
832                                copy.size.width as i32,
833                                copy.size.height as i32,
834                                copy.size.depth as i32,
835                                format_desc.external,
836                                format_desc.data_type,
837                                unpack_data,
838                            )
839                        };
840                    } else {
841                        unsafe {
842                            gl.tex_sub_image_2d(
843                                get_2d_target(dst_target, copy.texture_base.array_layer),
844                                copy.texture_base.mip_level as i32,
845                                copy.texture_base.origin.x as i32,
846                                copy.texture_base.origin.y as i32,
847                                copy.size.width as i32,
848                                copy.size.height as i32,
849                                format_desc.external,
850                                format_desc.data_type,
851                                unpack_data,
852                            )
853                        };
854                    }
855                } else {
856                    let bytes_per_row = copy
857                        .buffer_layout
858                        .bytes_per_row
859                        .unwrap_or(copy.size.width * block_size);
860                    let minimum_rows_per_image = copy.size.height.div_ceil(block_height);
861                    let rows_per_image = copy
862                        .buffer_layout
863                        .rows_per_image
864                        .unwrap_or(minimum_rows_per_image);
865
866                    let bytes_per_image = bytes_per_row * rows_per_image;
867                    let minimum_bytes_per_image = bytes_per_row * minimum_rows_per_image;
868                    let bytes_in_upload =
869                        (bytes_per_image * (copy.size.depth - 1)) + minimum_bytes_per_image;
870                    let offset = copy.buffer_layout.offset as u32;
871
872                    let map_state;
873                    let unpack_data = match src.raw {
874                        Some(buffer) => {
875                            unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
876                            unbind_unpack_buffer = true;
877                            glow::CompressedPixelUnpackData::BufferRange(
878                                offset..offset + bytes_in_upload,
879                            )
880                        }
881                        None => {
882                            map_state = src.map_state.lock();
883                            let src_data = &map_state.data.as_ref().unwrap().as_slice()
884                                [(offset as usize)..(offset + bytes_in_upload) as usize];
885                            glow::CompressedPixelUnpackData::Slice(src_data)
886                        }
887                    };
888
889                    if is_layered_target(dst_target) {
890                        unsafe {
891                            gl.compressed_tex_sub_image_3d(
892                                dst_target,
893                                copy.texture_base.mip_level as i32,
894                                copy.texture_base.origin.x as i32,
895                                copy.texture_base.origin.y as i32,
896                                get_z_offset(dst_target, &copy.texture_base) as i32,
897                                copy.size.width as i32,
898                                copy.size.height as i32,
899                                copy.size.depth as i32,
900                                format_desc.internal,
901                                unpack_data,
902                            )
903                        };
904                    } else {
905                        unsafe {
906                            gl.compressed_tex_sub_image_2d(
907                                get_2d_target(dst_target, copy.texture_base.array_layer),
908                                copy.texture_base.mip_level as i32,
909                                copy.texture_base.origin.x as i32,
910                                copy.texture_base.origin.y as i32,
911                                copy.size.width as i32,
912                                copy.size.height as i32,
913                                format_desc.internal,
914                                unpack_data,
915                            )
916                        };
917                    }
918                }
919                if unbind_unpack_buffer {
920                    unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None) };
921                }
922            }
923            C::CopyTextureToBuffer {
924                src,
925                src_target,
926                src_format,
927                ref dst,
928                dst_target: _,
929                ref copy,
930            } => {
931                let block_size = src_format.block_copy_size(None).unwrap();
932                if src_format.is_compressed() {
933                    log::error!("Not implemented yet: compressed texture copy to buffer");
934                    return;
935                }
936                if src_target == glow::TEXTURE_CUBE_MAP
937                    || src_target == glow::TEXTURE_CUBE_MAP_ARRAY
938                {
939                    log::error!("Not implemented yet: cubemap texture copy to buffer");
940                    return;
941                }
942                let format_desc = self.shared.describe_texture_format(src_format);
943                let row_texels = copy
944                    .buffer_layout
945                    .bytes_per_row
946                    .map_or(copy.size.width, |bpr| bpr / block_size);
947                let column_texels = copy
948                    .buffer_layout
949                    .rows_per_image
950                    .unwrap_or(copy.size.height);
951
952                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
953
954                let read_pixels = |offset| {
955                    let mut map_state;
956                    let unpack_data = match dst.raw {
957                        Some(buffer) => {
958                            unsafe { gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32) };
959                            unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(buffer)) };
960                            glow::PixelPackData::BufferOffset(offset as u32)
961                        }
962                        None => {
963                            map_state = dst.map_state.lock();
964                            let dst_data = &mut map_state.data.as_mut().unwrap().as_mut_slice()
965                                [offset as usize..];
966                            glow::PixelPackData::Slice(Some(dst_data))
967                        }
968                    };
969                    unsafe {
970                        gl.read_pixels(
971                            copy.texture_base.origin.x as i32,
972                            copy.texture_base.origin.y as i32,
973                            copy.size.width as i32,
974                            copy.size.height as i32,
975                            format_desc.external,
976                            format_desc.data_type,
977                            unpack_data,
978                        )
979                    };
980                };
981
982                match src_target {
983                    glow::TEXTURE_2D => {
984                        unsafe {
985                            gl.framebuffer_texture_2d(
986                                glow::READ_FRAMEBUFFER,
987                                glow::COLOR_ATTACHMENT0,
988                                src_target,
989                                Some(src),
990                                copy.texture_base.mip_level as i32,
991                            )
992                        };
993                        read_pixels(copy.buffer_layout.offset);
994                    }
995                    glow::TEXTURE_2D_ARRAY => {
996                        unsafe {
997                            gl.framebuffer_texture_layer(
998                                glow::READ_FRAMEBUFFER,
999                                glow::COLOR_ATTACHMENT0,
1000                                Some(src),
1001                                copy.texture_base.mip_level as i32,
1002                                copy.texture_base.array_layer as i32,
1003                            )
1004                        };
1005                        read_pixels(copy.buffer_layout.offset);
1006                    }
1007                    glow::TEXTURE_3D => {
1008                        for z in copy.texture_base.origin.z..copy.size.depth {
1009                            unsafe {
1010                                gl.framebuffer_texture_layer(
1011                                    glow::READ_FRAMEBUFFER,
1012                                    glow::COLOR_ATTACHMENT0,
1013                                    Some(src),
1014                                    copy.texture_base.mip_level as i32,
1015                                    z as i32,
1016                                )
1017                            };
1018                            let offset = copy.buffer_layout.offset
1019                                + (z * block_size * row_texels * column_texels) as u64;
1020                            read_pixels(offset);
1021                        }
1022                    }
1023                    glow::TEXTURE_CUBE_MAP | glow::TEXTURE_CUBE_MAP_ARRAY => unimplemented!(),
1024                    _ => unreachable!(),
1025                }
1026            }
1027            C::SetIndexBuffer(buffer) => {
1028                unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)) };
1029                let mut current_index_buffer = self.current_index_buffer.lock();
1030                *current_index_buffer = Some(buffer);
1031            }
1032            C::BeginQuery(query, target) => {
1033                unsafe { gl.begin_query(target, query) };
1034            }
1035            C::EndQuery(target) => {
1036                unsafe { gl.end_query(target) };
1037            }
1038            C::TimestampQuery(query) => {
1039                unsafe { gl.query_counter(query, glow::TIMESTAMP) };
1040            }
1041            C::CopyQueryResults {
1042                ref query_range,
1043                ref dst,
1044                dst_target,
1045                dst_offset,
1046            } => {
1047                if self
1048                    .shared
1049                    .private_caps
1050                    .contains(PrivateCapabilities::QUERY_BUFFERS)
1051                    && dst.raw.is_some()
1052                {
1053                    unsafe {
1054                        // We're assuming that the only relevant queries are 8 byte timestamps or
1055                        // occlusion tests.
1056                        let query_size = 8;
1057
1058                        let query_range_size = query_size * query_range.len();
1059
1060                        let buffer = gl.create_buffer().ok();
1061                        gl.bind_buffer(glow::QUERY_BUFFER, buffer);
1062                        gl.buffer_data_size(
1063                            glow::QUERY_BUFFER,
1064                            query_range_size as _,
1065                            glow::STREAM_COPY,
1066                        );
1067
1068                        for (i, &query) in queries
1069                            [query_range.start as usize..query_range.end as usize]
1070                            .iter()
1071                            .enumerate()
1072                        {
1073                            gl.get_query_parameter_u64_with_offset(
1074                                query,
1075                                glow::QUERY_RESULT,
1076                                query_size * i,
1077                            )
1078                        }
1079                        gl.bind_buffer(dst_target, dst.raw);
1080                        gl.copy_buffer_sub_data(
1081                            glow::QUERY_BUFFER,
1082                            dst_target,
1083                            0,
1084                            dst_offset as _,
1085                            query_range_size as _,
1086                        );
1087                        if let Some(buffer) = buffer {
1088                            gl.delete_buffer(buffer)
1089                        }
1090                    }
1091                } else {
1092                    let mut temp_query_results = self.temp_query_results.lock();
1093                    temp_query_results.clear();
1094                    for &query in
1095                        queries[query_range.start as usize..query_range.end as usize].iter()
1096                    {
1097                        let mut result: u64 = 0;
1098                        unsafe {
1099                            if self
1100                                .shared
1101                                .private_caps
1102                                .contains(PrivateCapabilities::QUERY_64BIT)
1103                            {
1104                                let result: *mut u64 = &mut result;
1105                                gl.get_query_parameter_u64_with_offset(
1106                                    query,
1107                                    glow::QUERY_RESULT,
1108                                    result as usize,
1109                                )
1110                            } else {
1111                                result =
1112                                    gl.get_query_parameter_u32(query, glow::QUERY_RESULT) as u64;
1113                            }
1114                        };
1115                        temp_query_results.push(result);
1116                    }
1117                    let query_data = bytemuck::cast_slice(&temp_query_results);
1118                    match dst.raw {
1119                        Some(buffer) => {
1120                            unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
1121                            unsafe {
1122                                gl.buffer_sub_data_u8_slice(
1123                                    dst_target,
1124                                    dst_offset as i32,
1125                                    query_data,
1126                                )
1127                            };
1128                        }
1129                        None => {
1130                            let mut map_state = dst.map_state.lock();
1131                            let data = map_state.data.as_mut().unwrap();
1132                            let len = query_data.len().min(data.len());
1133                            data[..len].copy_from_slice(&query_data[..len]);
1134                        }
1135                    }
1136                }
1137            }
1138            C::ResetFramebuffer { is_default } => {
1139                if is_default {
1140                    unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
1141                } else {
1142                    unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1143                    unsafe {
1144                        gl.framebuffer_texture_2d(
1145                            glow::DRAW_FRAMEBUFFER,
1146                            glow::DEPTH_STENCIL_ATTACHMENT,
1147                            glow::TEXTURE_2D,
1148                            None,
1149                            0,
1150                        )
1151                    };
1152                    for i in 0..self.shared.limits.max_color_attachments {
1153                        let target = glow::COLOR_ATTACHMENT0 + i;
1154                        unsafe {
1155                            gl.framebuffer_texture_2d(
1156                                glow::DRAW_FRAMEBUFFER,
1157                                target,
1158                                glow::TEXTURE_2D,
1159                                None,
1160                                0,
1161                            )
1162                        };
1163                    }
1164                }
1165                unsafe { gl.color_mask(true, true, true, true) };
1166                unsafe { gl.depth_mask(true) };
1167                unsafe { gl.stencil_mask(!0) };
1168                unsafe { gl.disable(glow::DEPTH_TEST) };
1169                unsafe { gl.disable(glow::STENCIL_TEST) };
1170                unsafe { gl.disable(glow::SCISSOR_TEST) };
1171            }
1172            C::BindAttachment {
1173                attachment,
1174                ref view,
1175                depth_slice,
1176                sample_count,
1177            } => {
1178                unsafe {
1179                    self.set_attachment(
1180                        gl,
1181                        glow::DRAW_FRAMEBUFFER,
1182                        attachment,
1183                        view,
1184                        depth_slice,
1185                        sample_count,
1186                    )
1187                };
1188            }
1189            C::ResolveAttachment {
1190                attachment,
1191                ref dst,
1192                ref size,
1193            } => {
1194                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)) };
1195                unsafe { gl.read_buffer(attachment) };
1196                unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
1197                unsafe {
1198                    self.set_attachment(
1199                        gl,
1200                        glow::DRAW_FRAMEBUFFER,
1201                        glow::COLOR_ATTACHMENT0,
1202                        dst,
1203                        None,
1204                        1,
1205                    )
1206                };
1207                unsafe {
1208                    gl.blit_framebuffer(
1209                        0,
1210                        0,
1211                        size.width as i32,
1212                        size.height as i32,
1213                        0,
1214                        0,
1215                        size.width as i32,
1216                        size.height as i32,
1217                        glow::COLOR_BUFFER_BIT,
1218                        glow::NEAREST,
1219                    )
1220                };
1221                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
1222                unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1223            }
1224            C::InvalidateAttachments(ref list) => {
1225                if self
1226                    .shared
1227                    .private_caps
1228                    .contains(PrivateCapabilities::INVALIDATE_FRAMEBUFFER)
1229                {
1230                    unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) };
1231                }
1232            }
1233            C::SetDrawColorBuffers(count) => {
1234                self.draw_buffer_count.store(count, Ordering::Relaxed);
1235                let indices = (0..count as u32)
1236                    .map(|i| glow::COLOR_ATTACHMENT0 + i)
1237                    .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
1238                unsafe { gl.draw_buffers(&indices) };
1239            }
1240            C::ClearColorF {
1241                draw_buffer,
1242                ref color,
1243                is_srgb,
1244            } => {
1245                if self
1246                    .shared
1247                    .workarounds
1248                    .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
1249                    && is_srgb
1250                {
1251                    unsafe { self.perform_shader_clear(gl, draw_buffer, *color) };
1252                } else {
1253                    unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) };
1254                }
1255            }
1256            C::ClearColorU(draw_buffer, ref color) => {
1257                unsafe { gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, color) };
1258            }
1259            C::ClearColorI(draw_buffer, ref color) => {
1260                unsafe { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color) };
1261            }
1262            C::ClearDepth(depth) => {
1263                // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge
1264                // on Windows.
1265                unsafe {
1266                    gl.clear_depth_f32(depth);
1267                    gl.clear(glow::DEPTH_BUFFER_BIT);
1268                }
1269            }
1270            C::ClearStencil(value) => {
1271                // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge
1272                // on Windows.
1273                unsafe {
1274                    gl.clear_stencil(value as i32);
1275                    gl.clear(glow::STENCIL_BUFFER_BIT);
1276                }
1277            }
1278            C::ClearDepthAndStencil(depth, stencil_value) => {
1279                // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge
1280                // on Windows.
1281                unsafe {
1282                    gl.clear_depth_f32(depth);
1283                    gl.clear_stencil(stencil_value as i32);
1284                    gl.clear(glow::DEPTH_BUFFER_BIT | glow::STENCIL_BUFFER_BIT);
1285                }
1286            }
1287            C::BufferBarrier(raw, usage) => {
1288                let mut flags = 0;
1289                if usage.contains(wgt::BufferUses::VERTEX) {
1290                    flags |= glow::VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1291                    unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, Some(raw)) };
1292                    unsafe { gl.vertex_attrib_pointer_f32(0, 1, glow::BYTE, true, 0, 0) };
1293                }
1294                if usage.contains(wgt::BufferUses::INDEX) {
1295                    flags |= glow::ELEMENT_ARRAY_BARRIER_BIT;
1296                    unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(raw)) };
1297                }
1298                if usage.contains(wgt::BufferUses::UNIFORM) {
1299                    flags |= glow::UNIFORM_BARRIER_BIT;
1300                }
1301                if usage.contains(wgt::BufferUses::INDIRECT) {
1302                    flags |= glow::COMMAND_BARRIER_BIT;
1303                    unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(raw)) };
1304                }
1305                if usage.contains(wgt::BufferUses::COPY_SRC) {
1306                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1307                    unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(raw)) };
1308                }
1309                if usage.contains(wgt::BufferUses::COPY_DST) {
1310                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1311                    unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(raw)) };
1312                }
1313                if usage.intersects(wgt::BufferUses::MAP_READ | wgt::BufferUses::MAP_WRITE) {
1314                    flags |= glow::BUFFER_UPDATE_BARRIER_BIT;
1315                }
1316                if usage.intersects(
1317                    wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE,
1318                ) {
1319                    flags |= glow::SHADER_STORAGE_BARRIER_BIT;
1320                }
1321                unsafe { gl.memory_barrier(flags) };
1322            }
1323            // because `STORAGE_WRITE_ONLY` and `STORAGE_READ_WRITE` are only states
1324            // we can transit from due OpenGL memory barriers are used to make _subsequent_
1325            // operations see changes from the _shader_ side. We filter out usage changes that are
1326            // does not comes from the shader side in `transition_textures`
1327            C::TextureBarrier(usage) => {
1328                let mut flags = 0;
1329                if usage.contains(wgt::TextureUses::RESOURCE) {
1330                    flags |= glow::TEXTURE_FETCH_BARRIER_BIT;
1331                }
1332                if usage.intersects(
1333                    wgt::TextureUses::STORAGE_READ_ONLY
1334                        | wgt::TextureUses::STORAGE_WRITE_ONLY
1335                        | wgt::TextureUses::STORAGE_READ_WRITE,
1336                ) {
1337                    flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT;
1338                }
1339                if usage.intersects(wgt::TextureUses::COPY_SRC) {
1340                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1341                }
1342                if usage.contains(wgt::TextureUses::COPY_DST) {
1343                    flags |= glow::TEXTURE_UPDATE_BARRIER_BIT;
1344                }
1345                if usage.intersects(
1346                    wgt::TextureUses::COLOR_TARGET
1347                        | wgt::TextureUses::DEPTH_READ
1348                        | wgt::TextureUses::DEPTH_WRITE
1349                        | wgt::TextureUses::STENCIL_READ
1350                        | wgt::TextureUses::STENCIL_WRITE,
1351                ) {
1352                    flags |= glow::FRAMEBUFFER_BARRIER_BIT;
1353                }
1354                unsafe { gl.memory_barrier(flags) };
1355            }
1356            C::SetViewport {
1357                ref rect,
1358                ref depth,
1359            } => {
1360                unsafe { gl.viewport(rect.x, rect.y, rect.w, rect.h) };
1361                unsafe { gl.depth_range_f32(depth.start, depth.end) };
1362            }
1363            C::SetScissor(ref rect) => {
1364                unsafe { gl.scissor(rect.x, rect.y, rect.w, rect.h) };
1365                unsafe { gl.enable(glow::SCISSOR_TEST) };
1366            }
1367            C::SetStencilFunc {
1368                face,
1369                function,
1370                reference,
1371                read_mask,
1372            } => {
1373                unsafe { gl.stencil_func_separate(face, function, reference as i32, read_mask) };
1374            }
1375            C::SetStencilOps {
1376                face,
1377                write_mask,
1378                ref ops,
1379            } => {
1380                unsafe { gl.stencil_mask_separate(face, write_mask) };
1381                unsafe { gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass) };
1382            }
1383            C::SetVertexAttribute {
1384                buffer,
1385                ref buffer_desc,
1386                attribute_desc: ref vat,
1387            } => {
1388                unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, buffer) };
1389                unsafe { gl.enable_vertex_attrib_array(vat.location) };
1390
1391                if buffer.is_none() {
1392                    match vat.format_desc.attrib_kind {
1393                        super::VertexAttribKind::Float => unsafe {
1394                            gl.vertex_attrib_format_f32(
1395                                vat.location,
1396                                vat.format_desc.element_count,
1397                                vat.format_desc.element_format,
1398                                true, // always normalized
1399                                vat.offset,
1400                            )
1401                        },
1402                        super::VertexAttribKind::Integer => unsafe {
1403                            gl.vertex_attrib_format_i32(
1404                                vat.location,
1405                                vat.format_desc.element_count,
1406                                vat.format_desc.element_format,
1407                                vat.offset,
1408                            )
1409                        },
1410                    }
1411
1412                    //Note: there is apparently a bug on AMD 3500U:
1413                    // this call is ignored if the current array is disabled.
1414                    unsafe { gl.vertex_attrib_binding(vat.location, vat.buffer_index) };
1415                } else {
1416                    match vat.format_desc.attrib_kind {
1417                        super::VertexAttribKind::Float => unsafe {
1418                            gl.vertex_attrib_pointer_f32(
1419                                vat.location,
1420                                vat.format_desc.element_count,
1421                                vat.format_desc.element_format,
1422                                true, // always normalized
1423                                buffer_desc.stride as i32,
1424                                vat.offset as i32,
1425                            )
1426                        },
1427                        super::VertexAttribKind::Integer => unsafe {
1428                            gl.vertex_attrib_pointer_i32(
1429                                vat.location,
1430                                vat.format_desc.element_count,
1431                                vat.format_desc.element_format,
1432                                buffer_desc.stride as i32,
1433                                vat.offset as i32,
1434                            )
1435                        },
1436                    }
1437                    unsafe { gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32) };
1438                }
1439            }
1440            C::UnsetVertexAttribute(location) => {
1441                unsafe { gl.disable_vertex_attrib_array(location) };
1442            }
1443            C::SetVertexBuffer {
1444                index,
1445                ref buffer,
1446                ref buffer_desc,
1447            } => {
1448                unsafe { gl.vertex_binding_divisor(index, buffer_desc.step as u32) };
1449                unsafe {
1450                    gl.bind_vertex_buffer(
1451                        index,
1452                        Some(buffer.raw),
1453                        buffer.offset as i32,
1454                        buffer_desc.stride as i32,
1455                    )
1456                };
1457            }
1458            C::SetDepth(ref depth) => {
1459                unsafe { gl.depth_func(depth.function) };
1460                unsafe { gl.depth_mask(depth.mask) };
1461            }
1462            C::SetDepthBias(bias) => {
1463                if bias.is_enabled() {
1464                    unsafe { gl.enable(glow::POLYGON_OFFSET_FILL) };
1465                    unsafe { gl.polygon_offset(bias.slope_scale, bias.constant as f32) };
1466                } else {
1467                    unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
1468                }
1469            }
1470            C::ConfigureDepthStencil(aspects) => {
1471                if aspects.contains(crate::FormatAspects::DEPTH) {
1472                    unsafe { gl.enable(glow::DEPTH_TEST) };
1473                } else {
1474                    unsafe { gl.disable(glow::DEPTH_TEST) };
1475                }
1476                if aspects.contains(crate::FormatAspects::STENCIL) {
1477                    unsafe { gl.enable(glow::STENCIL_TEST) };
1478                } else {
1479                    unsafe { gl.disable(glow::STENCIL_TEST) };
1480                }
1481            }
1482            C::SetAlphaToCoverage(enabled) => {
1483                if enabled {
1484                    unsafe { gl.enable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1485                } else {
1486                    unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1487                }
1488            }
1489            C::SetProgram(program) => {
1490                unsafe { gl.use_program(Some(program)) };
1491            }
1492            C::SetPrimitive(ref state) => {
1493                unsafe { gl.front_face(state.front_face) };
1494                if state.cull_face != 0 {
1495                    unsafe { gl.enable(glow::CULL_FACE) };
1496                    unsafe { gl.cull_face(state.cull_face) };
1497                } else {
1498                    unsafe { gl.disable(glow::CULL_FACE) };
1499                }
1500                if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
1501                    //Note: this is a bit tricky, since we are controlling the clip, not the clamp.
1502                    if state.unclipped_depth {
1503                        unsafe { gl.enable(glow::DEPTH_CLAMP) };
1504                    } else {
1505                        unsafe { gl.disable(glow::DEPTH_CLAMP) };
1506                    }
1507                }
1508                // POLYGON_MODE_LINE also implies POLYGON_MODE_POINT
1509                if self.features.contains(wgt::Features::POLYGON_MODE_LINE) {
1510                    unsafe { gl.polygon_mode(glow::FRONT_AND_BACK, state.polygon_mode) };
1511                }
1512            }
1513            C::SetBlendConstant(c) => {
1514                unsafe { gl.blend_color(c[0], c[1], c[2], c[3]) };
1515            }
1516            C::SetColorTarget {
1517                draw_buffer_index,
1518                desc: super::ColorTargetDesc { mask, ref blend },
1519            } => {
1520                use wgt::ColorWrites as Cw;
1521                if let Some(index) = draw_buffer_index {
1522                    unsafe {
1523                        gl.color_mask_draw_buffer(
1524                            index,
1525                            mask.contains(Cw::RED),
1526                            mask.contains(Cw::GREEN),
1527                            mask.contains(Cw::BLUE),
1528                            mask.contains(Cw::ALPHA),
1529                        )
1530                    };
1531                    if let Some(ref blend) = *blend {
1532                        unsafe { gl.enable_draw_buffer(glow::BLEND, index) };
1533                        if blend.color != blend.alpha {
1534                            unsafe {
1535                                gl.blend_equation_separate_draw_buffer(
1536                                    index,
1537                                    blend.color.equation,
1538                                    blend.alpha.equation,
1539                                )
1540                            };
1541                            unsafe {
1542                                gl.blend_func_separate_draw_buffer(
1543                                    index,
1544                                    blend.color.src,
1545                                    blend.color.dst,
1546                                    blend.alpha.src,
1547                                    blend.alpha.dst,
1548                                )
1549                            };
1550                        } else {
1551                            unsafe { gl.blend_equation_draw_buffer(index, blend.color.equation) };
1552                            unsafe {
1553                                gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst)
1554                            };
1555                        }
1556                    } else {
1557                        unsafe { gl.disable_draw_buffer(glow::BLEND, index) };
1558                    }
1559                } else {
1560                    unsafe {
1561                        gl.color_mask(
1562                            mask.contains(Cw::RED),
1563                            mask.contains(Cw::GREEN),
1564                            mask.contains(Cw::BLUE),
1565                            mask.contains(Cw::ALPHA),
1566                        )
1567                    };
1568                    if let Some(ref blend) = *blend {
1569                        unsafe { gl.enable(glow::BLEND) };
1570                        if blend.color != blend.alpha {
1571                            unsafe {
1572                                gl.blend_equation_separate(
1573                                    blend.color.equation,
1574                                    blend.alpha.equation,
1575                                )
1576                            };
1577                            unsafe {
1578                                gl.blend_func_separate(
1579                                    blend.color.src,
1580                                    blend.color.dst,
1581                                    blend.alpha.src,
1582                                    blend.alpha.dst,
1583                                )
1584                            };
1585                        } else {
1586                            unsafe { gl.blend_equation(blend.color.equation) };
1587                            unsafe { gl.blend_func(blend.color.src, blend.color.dst) };
1588                        }
1589                    } else {
1590                        unsafe { gl.disable(glow::BLEND) };
1591                    }
1592                }
1593            }
1594            C::BindBuffer {
1595                target,
1596                slot,
1597                buffer,
1598                offset,
1599                size,
1600            } => {
1601                unsafe { gl.bind_buffer_range(target, slot, Some(buffer), offset, size) };
1602            }
1603            C::BindSampler(texture_index, sampler) => {
1604                unsafe { gl.bind_sampler(texture_index, sampler) };
1605            }
1606            C::BindTexture {
1607                slot,
1608                texture,
1609                target,
1610                aspects,
1611                ref mip_levels,
1612            } => {
1613                unsafe { gl.active_texture(glow::TEXTURE0 + slot) };
1614                unsafe { gl.bind_texture(target, Some(texture)) };
1615
1616                unsafe {
1617                    gl.tex_parameter_i32(target, glow::TEXTURE_BASE_LEVEL, mip_levels.start as i32)
1618                };
1619                unsafe {
1620                    gl.tex_parameter_i32(
1621                        target,
1622                        glow::TEXTURE_MAX_LEVEL,
1623                        (mip_levels.end - 1) as i32,
1624                    )
1625                };
1626
1627                let version = gl.version();
1628                let is_min_es_3_1 = version.is_embedded && (version.major, version.minor) >= (3, 1);
1629                let is_min_4_3 = !version.is_embedded && (version.major, version.minor) >= (4, 3);
1630                if is_min_es_3_1 || is_min_4_3 {
1631                    let mode = match aspects {
1632                        crate::FormatAspects::DEPTH => Some(glow::DEPTH_COMPONENT),
1633                        crate::FormatAspects::STENCIL => Some(glow::STENCIL_INDEX),
1634                        _ => None,
1635                    };
1636                    if let Some(mode) = mode {
1637                        unsafe {
1638                            gl.tex_parameter_i32(
1639                                target,
1640                                glow::DEPTH_STENCIL_TEXTURE_MODE,
1641                                mode as _,
1642                            )
1643                        };
1644                    }
1645                }
1646            }
1647            C::BindImage { slot, ref binding } => {
1648                unsafe {
1649                    gl.bind_image_texture(
1650                        slot,
1651                        Some(binding.raw),
1652                        binding.mip_level as i32,
1653                        binding.array_layer.is_none(),
1654                        binding.array_layer.unwrap_or_default() as i32,
1655                        binding.access,
1656                        binding.format,
1657                    )
1658                };
1659            }
1660            C::InsertDebugMarker(ref range) => {
1661                let marker = extract_marker(data_bytes, range);
1662                unsafe {
1663                    if self
1664                        .shared
1665                        .private_caps
1666                        .contains(PrivateCapabilities::DEBUG_FNS)
1667                    {
1668                        gl.debug_message_insert(
1669                            glow::DEBUG_SOURCE_APPLICATION,
1670                            glow::DEBUG_TYPE_MARKER,
1671                            DEBUG_ID,
1672                            glow::DEBUG_SEVERITY_NOTIFICATION,
1673                            to_debug_str(marker),
1674                        )
1675                    }
1676                };
1677            }
1678            C::PushDebugGroup(ref range) => {
1679                let marker = extract_marker(data_bytes, range);
1680                unsafe {
1681                    if self
1682                        .shared
1683                        .private_caps
1684                        .contains(PrivateCapabilities::DEBUG_FNS)
1685                    {
1686                        gl.push_debug_group(
1687                            glow::DEBUG_SOURCE_APPLICATION,
1688                            DEBUG_ID,
1689                            to_debug_str(marker),
1690                        )
1691                    }
1692                };
1693            }
1694            C::PopDebugGroup => {
1695                unsafe {
1696                    if self
1697                        .shared
1698                        .private_caps
1699                        .contains(PrivateCapabilities::DEBUG_FNS)
1700                    {
1701                        gl.pop_debug_group()
1702                    }
1703                };
1704            }
1705            C::SetImmediates {
1706                ref uniform,
1707                offset,
1708            } => {
1709                fn get_data<T, const COUNT: usize>(data: &[u8], offset: u32) -> [T; COUNT]
1710                where
1711                    [T; COUNT]: bytemuck::AnyBitPattern,
1712                {
1713                    let data_required = size_of::<T>() * COUNT;
1714                    let raw = &data[(offset as usize)..][..data_required];
1715                    bytemuck::pod_read_unaligned(raw)
1716                }
1717
1718                let location = Some(&uniform.location);
1719                use nt::glsl::{GlslScalar, GlslUniformType, GlslVectorSize};
1720                match uniform.ty {
1721                    //
1722                    // --- Float 1-4 Component ---
1723                    //
1724                    GlslUniformType::Scalar(GlslScalar::F32) => {
1725                        let data = get_data::<f32, 1>(data_bytes, offset)[0];
1726                        unsafe { gl.uniform_1_f32(location, data) };
1727                    }
1728                    GlslUniformType::Vector {
1729                        size: GlslVectorSize::Bi,
1730                        scalar: GlslScalar::F32,
1731                    } => {
1732                        let data = &get_data::<f32, 2>(data_bytes, offset);
1733                        unsafe { gl.uniform_2_f32_slice(location, data) };
1734                    }
1735                    GlslUniformType::Vector {
1736                        size: GlslVectorSize::Tri,
1737                        scalar: GlslScalar::F32,
1738                    } => {
1739                        let data = &get_data::<f32, 3>(data_bytes, offset);
1740                        unsafe { gl.uniform_3_f32_slice(location, data) };
1741                    }
1742                    GlslUniformType::Vector {
1743                        size: GlslVectorSize::Quad,
1744                        scalar: GlslScalar::F32,
1745                    } => {
1746                        let data = &get_data::<f32, 4>(data_bytes, offset);
1747                        unsafe { gl.uniform_4_f32_slice(location, data) };
1748                    }
1749
1750                    //
1751                    // --- Int 1-4 Component ---
1752                    //
1753                    GlslUniformType::Scalar(GlslScalar::I32) => {
1754                        let data = get_data::<i32, 1>(data_bytes, offset)[0];
1755                        unsafe { gl.uniform_1_i32(location, data) };
1756                    }
1757                    GlslUniformType::Vector {
1758                        size: GlslVectorSize::Bi,
1759                        scalar: GlslScalar::I32,
1760                    } => {
1761                        let data = &get_data::<i32, 2>(data_bytes, offset);
1762                        unsafe { gl.uniform_2_i32_slice(location, data) };
1763                    }
1764                    GlslUniformType::Vector {
1765                        size: GlslVectorSize::Tri,
1766                        scalar: GlslScalar::I32,
1767                    } => {
1768                        let data = &get_data::<i32, 3>(data_bytes, offset);
1769                        unsafe { gl.uniform_3_i32_slice(location, data) };
1770                    }
1771                    GlslUniformType::Vector {
1772                        size: GlslVectorSize::Quad,
1773                        scalar: GlslScalar::I32,
1774                    } => {
1775                        let data = &get_data::<i32, 4>(data_bytes, offset);
1776                        unsafe { gl.uniform_4_i32_slice(location, data) };
1777                    }
1778
1779                    //
1780                    // --- Uint 1-4 Component ---
1781                    //
1782                    GlslUniformType::Scalar(GlslScalar::U32) => {
1783                        let data = get_data::<u32, 1>(data_bytes, offset)[0];
1784                        unsafe { gl.uniform_1_u32(location, data) };
1785                    }
1786                    GlslUniformType::Vector {
1787                        size: GlslVectorSize::Bi,
1788                        scalar: GlslScalar::U32,
1789                    } => {
1790                        let data = &get_data::<u32, 2>(data_bytes, offset);
1791                        unsafe { gl.uniform_2_u32_slice(location, data) };
1792                    }
1793                    GlslUniformType::Vector {
1794                        size: GlslVectorSize::Tri,
1795                        scalar: GlslScalar::U32,
1796                    } => {
1797                        let data = &get_data::<u32, 3>(data_bytes, offset);
1798                        unsafe { gl.uniform_3_u32_slice(location, data) };
1799                    }
1800                    GlslUniformType::Vector {
1801                        size: GlslVectorSize::Quad,
1802                        scalar: GlslScalar::U32,
1803                    } => {
1804                        let data = &get_data::<u32, 4>(data_bytes, offset);
1805                        unsafe { gl.uniform_4_u32_slice(location, data) };
1806                    }
1807
1808                    //
1809                    // --- Matrix 2xR ---
1810                    //
1811                    GlslUniformType::Matrix {
1812                        columns: GlslVectorSize::Bi,
1813                        rows: GlslVectorSize::Bi,
1814                        scalar: GlslScalar::F32,
1815                    } => {
1816                        let data = &get_data::<f32, 4>(data_bytes, offset);
1817                        unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) };
1818                    }
1819                    GlslUniformType::Matrix {
1820                        columns: GlslVectorSize::Bi,
1821                        rows: GlslVectorSize::Tri,
1822                        scalar: GlslScalar::F32,
1823                    } => {
1824                        // repack 2 vec3s into 6 values.
1825                        let unpacked_data = &get_data::<f32, 8>(data_bytes, offset);
1826                        #[rustfmt::skip]
1827                        let packed_data = [
1828                            unpacked_data[0], unpacked_data[1], unpacked_data[2],
1829                            unpacked_data[4], unpacked_data[5], unpacked_data[6],
1830                        ];
1831                        unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) };
1832                    }
1833                    GlslUniformType::Matrix {
1834                        columns: GlslVectorSize::Bi,
1835                        rows: GlslVectorSize::Quad,
1836                        scalar: GlslScalar::F32,
1837                    } => {
1838                        let data = &get_data::<f32, 8>(data_bytes, offset);
1839                        unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) };
1840                    }
1841
1842                    //
1843                    // --- Matrix 3xR ---
1844                    //
1845                    GlslUniformType::Matrix {
1846                        columns: GlslVectorSize::Tri,
1847                        rows: GlslVectorSize::Bi,
1848                        scalar: GlslScalar::F32,
1849                    } => {
1850                        let data = &get_data::<f32, 6>(data_bytes, offset);
1851                        unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) };
1852                    }
1853                    GlslUniformType::Matrix {
1854                        columns: GlslVectorSize::Tri,
1855                        rows: GlslVectorSize::Tri,
1856                        scalar: GlslScalar::F32,
1857                    } => {
1858                        // repack 3 vec3s into 9 values.
1859                        let unpacked_data = &get_data::<f32, 12>(data_bytes, offset);
1860                        #[rustfmt::skip]
1861                        let packed_data = [
1862                            unpacked_data[0], unpacked_data[1], unpacked_data[2],
1863                            unpacked_data[4], unpacked_data[5], unpacked_data[6],
1864                            unpacked_data[8], unpacked_data[9], unpacked_data[10],
1865                        ];
1866                        unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) };
1867                    }
1868                    GlslUniformType::Matrix {
1869                        columns: GlslVectorSize::Tri,
1870                        rows: GlslVectorSize::Quad,
1871                        scalar: GlslScalar::F32,
1872                    } => {
1873                        let data = &get_data::<f32, 12>(data_bytes, offset);
1874                        unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) };
1875                    }
1876
1877                    //
1878                    // --- Matrix 4xR ---
1879                    //
1880                    GlslUniformType::Matrix {
1881                        columns: GlslVectorSize::Quad,
1882                        rows: GlslVectorSize::Bi,
1883                        scalar: GlslScalar::F32,
1884                    } => {
1885                        let data = &get_data::<f32, 8>(data_bytes, offset);
1886                        unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) };
1887                    }
1888                    GlslUniformType::Matrix {
1889                        columns: GlslVectorSize::Quad,
1890                        rows: GlslVectorSize::Tri,
1891                        scalar: GlslScalar::F32,
1892                    } => {
1893                        // repack 4 vec3s into 12 values.
1894                        let unpacked_data = &get_data::<f32, 16>(data_bytes, offset);
1895                        #[rustfmt::skip]
1896                        let packed_data = [
1897                            unpacked_data[0], unpacked_data[1], unpacked_data[2],
1898                            unpacked_data[4], unpacked_data[5], unpacked_data[6],
1899                            unpacked_data[8], unpacked_data[9], unpacked_data[10],
1900                            unpacked_data[12], unpacked_data[13], unpacked_data[14],
1901                        ];
1902                        unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) };
1903                    }
1904                    GlslUniformType::Matrix {
1905                        columns: GlslVectorSize::Quad,
1906                        rows: GlslVectorSize::Quad,
1907                        scalar: GlslScalar::F32,
1908                    } => {
1909                        let data = &get_data::<f32, 16>(data_bytes, offset);
1910                        unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) };
1911                    }
1912                    _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
1913                }
1914            }
1915            C::SetClipDistances {
1916                old_count,
1917                new_count,
1918            } => {
1919                // Disable clip planes that are no longer active
1920                for i in new_count..old_count {
1921                    unsafe { gl.disable(glow::CLIP_DISTANCE0 + i) };
1922                }
1923
1924                // Enable clip planes that are now active
1925                for i in old_count..new_count {
1926                    unsafe { gl.enable(glow::CLIP_DISTANCE0 + i) };
1927                }
1928            }
1929        }
1930    }
1931}
1932
1933impl crate::Queue for super::Queue {
1934    type A = super::Api;
1935
1936    unsafe fn submit(
1937        &self,
1938        command_buffers: &[&super::CommandBuffer],
1939        _surface_textures: &[&super::Texture],
1940        (signal_fence, signal_value): (&super::Fence, crate::FenceValue),
1941    ) -> Result<(), crate::DeviceError> {
1942        let shared = Arc::clone(&self.shared);
1943        let gl = &shared.context.lock();
1944        for cmd_buf in command_buffers.iter() {
1945            // The command encoder assumes a default state when encoding the command buffer.
1946            // Always reset the state between command_buffers to reflect this assumption. Do
1947            // this at the beginning of the loop in case something outside of wgpu modified
1948            // this state prior to commit.
1949            unsafe { self.reset_state(gl) };
1950            if let Some(ref label) = cmd_buf.label {
1951                if self
1952                    .shared
1953                    .private_caps
1954                    .contains(PrivateCapabilities::DEBUG_FNS)
1955                {
1956                    unsafe {
1957                        gl.push_debug_group(
1958                            glow::DEBUG_SOURCE_APPLICATION,
1959                            DEBUG_ID,
1960                            to_debug_str(label),
1961                        )
1962                    };
1963                }
1964            }
1965
1966            for command in cmd_buf.commands.iter() {
1967                unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
1968            }
1969
1970            if cmd_buf.label.is_some()
1971                && self
1972                    .shared
1973                    .private_caps
1974                    .contains(PrivateCapabilities::DEBUG_FNS)
1975            {
1976                unsafe { gl.pop_debug_group() };
1977            }
1978        }
1979
1980        signal_fence.maintain(gl);
1981        signal_fence.signal(gl, signal_value)?;
1982
1983        // This is extremely important. If we don't flush, the above fences may never
1984        // be signaled, particularly in headless contexts. Headed contexts will
1985        // often flush every so often, but headless contexts may not.
1986        unsafe { gl.flush() };
1987
1988        Ok(())
1989    }
1990
1991    unsafe fn present(
1992        &self,
1993        surface: &super::Surface,
1994        texture: super::Texture,
1995    ) -> Result<(), crate::SurfaceError> {
1996        unsafe { surface.present(texture, &self.shared.context) }
1997    }
1998
1999    unsafe fn get_timestamp_period(&self) -> f32 {
2000        1.0
2001    }
2002
2003    unsafe fn wait_for_idle(&self) -> Result<(), crate::DeviceError> {
2004        let gl = &self.shared.context.lock();
2005        unsafe { gl.finish() };
2006        Ok(())
2007    }
2008}
2009
2010#[cfg(send_sync)]
2011unsafe impl Sync for super::Queue {}
2012#[cfg(send_sync)]
2013unsafe impl Send for super::Queue {}