wgpu_hal/gles/
queue.rs

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