wgpu_hal/gles/
queue.rs

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