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