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(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 = src.data.as_ref().unwrap().lock().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 = dst.data.as_ref().unwrap().lock().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 = unsafe {
1043                        slice::from_raw_parts(
1044                            temp_query_results.as_ptr().cast::<u8>(),
1045                            temp_query_results.len() * size_of::<u64>(),
1046                        )
1047                    };
1048                    match dst.raw {
1049                        Some(buffer) => {
1050                            unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
1051                            unsafe {
1052                                gl.buffer_sub_data_u8_slice(
1053                                    dst_target,
1054                                    dst_offset as i32,
1055                                    query_data,
1056                                )
1057                            };
1058                        }
1059                        None => {
1060                            let data = &mut dst.data.as_ref().unwrap().lock().unwrap();
1061                            let len = query_data.len().min(data.len());
1062                            data[..len].copy_from_slice(&query_data[..len]);
1063                        }
1064                    }
1065                }
1066            }
1067            C::ResetFramebuffer { is_default } => {
1068                if is_default {
1069                    unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
1070                } else {
1071                    unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1072                    unsafe {
1073                        gl.framebuffer_texture_2d(
1074                            glow::DRAW_FRAMEBUFFER,
1075                            glow::DEPTH_STENCIL_ATTACHMENT,
1076                            glow::TEXTURE_2D,
1077                            None,
1078                            0,
1079                        )
1080                    };
1081                    for i in 0..self.shared.limits.max_color_attachments {
1082                        let target = glow::COLOR_ATTACHMENT0 + i;
1083                        unsafe {
1084                            gl.framebuffer_texture_2d(
1085                                glow::DRAW_FRAMEBUFFER,
1086                                target,
1087                                glow::TEXTURE_2D,
1088                                None,
1089                                0,
1090                            )
1091                        };
1092                    }
1093                }
1094                unsafe { gl.color_mask(true, true, true, true) };
1095                unsafe { gl.depth_mask(true) };
1096                unsafe { gl.stencil_mask(!0) };
1097                unsafe { gl.disable(glow::DEPTH_TEST) };
1098                unsafe { gl.disable(glow::STENCIL_TEST) };
1099                unsafe { gl.disable(glow::SCISSOR_TEST) };
1100            }
1101            C::BindAttachment {
1102                attachment,
1103                ref view,
1104            } => {
1105                unsafe { self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view) };
1106            }
1107            C::ResolveAttachment {
1108                attachment,
1109                ref dst,
1110                ref size,
1111            } => {
1112                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)) };
1113                unsafe { gl.read_buffer(attachment) };
1114                unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
1115                unsafe {
1116                    self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, glow::COLOR_ATTACHMENT0, dst)
1117                };
1118                unsafe {
1119                    gl.blit_framebuffer(
1120                        0,
1121                        0,
1122                        size.width as i32,
1123                        size.height as i32,
1124                        0,
1125                        0,
1126                        size.width as i32,
1127                        size.height as i32,
1128                        glow::COLOR_BUFFER_BIT,
1129                        glow::NEAREST,
1130                    )
1131                };
1132                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
1133                unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
1134            }
1135            C::InvalidateAttachments(ref list) => {
1136                if self
1137                    .shared
1138                    .private_caps
1139                    .contains(PrivateCapabilities::INVALIDATE_FRAMEBUFFER)
1140                {
1141                    unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) };
1142                }
1143            }
1144            C::SetDrawColorBuffers(count) => {
1145                self.draw_buffer_count.store(count, Ordering::Relaxed);
1146                let indices = (0..count as u32)
1147                    .map(|i| glow::COLOR_ATTACHMENT0 + i)
1148                    .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
1149                unsafe { gl.draw_buffers(&indices) };
1150            }
1151            C::ClearColorF {
1152                draw_buffer,
1153                ref color,
1154                is_srgb,
1155            } => {
1156                if self
1157                    .shared
1158                    .workarounds
1159                    .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
1160                    && is_srgb
1161                {
1162                    unsafe { self.perform_shader_clear(gl, draw_buffer, *color) };
1163                } else {
1164                    unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) };
1165                }
1166            }
1167            C::ClearColorU(draw_buffer, ref color) => {
1168                unsafe { gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, color) };
1169            }
1170            C::ClearColorI(draw_buffer, ref color) => {
1171                unsafe { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color) };
1172            }
1173            C::ClearDepth(depth) => {
1174                // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge
1175                // on Windows.
1176                unsafe {
1177                    gl.clear_depth_f32(depth);
1178                    gl.clear(glow::DEPTH_BUFFER_BIT);
1179                }
1180            }
1181            C::ClearStencil(value) => {
1182                // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge
1183                // on Windows.
1184                unsafe {
1185                    gl.clear_stencil(value as i32);
1186                    gl.clear(glow::STENCIL_BUFFER_BIT);
1187                }
1188            }
1189            C::ClearDepthAndStencil(depth, stencil_value) => {
1190                // Prefer `clear` as `clear_buffer` functions have issues on Sandy Bridge
1191                // on Windows.
1192                unsafe {
1193                    gl.clear_depth_f32(depth);
1194                    gl.clear_stencil(stencil_value as i32);
1195                    gl.clear(glow::DEPTH_BUFFER_BIT | glow::STENCIL_BUFFER_BIT);
1196                }
1197            }
1198            C::BufferBarrier(raw, usage) => {
1199                let mut flags = 0;
1200                if usage.contains(crate::BufferUses::VERTEX) {
1201                    flags |= glow::VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1202                    unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, Some(raw)) };
1203                    unsafe { gl.vertex_attrib_pointer_f32(0, 1, glow::BYTE, true, 0, 0) };
1204                }
1205                if usage.contains(crate::BufferUses::INDEX) {
1206                    flags |= glow::ELEMENT_ARRAY_BARRIER_BIT;
1207                    unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(raw)) };
1208                }
1209                if usage.contains(crate::BufferUses::UNIFORM) {
1210                    flags |= glow::UNIFORM_BARRIER_BIT;
1211                }
1212                if usage.contains(crate::BufferUses::INDIRECT) {
1213                    flags |= glow::COMMAND_BARRIER_BIT;
1214                    unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(raw)) };
1215                }
1216                if usage.contains(crate::BufferUses::COPY_SRC) {
1217                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1218                    unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(raw)) };
1219                }
1220                if usage.contains(crate::BufferUses::COPY_DST) {
1221                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1222                    unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(raw)) };
1223                }
1224                if usage.intersects(crate::BufferUses::MAP_READ | crate::BufferUses::MAP_WRITE) {
1225                    flags |= glow::BUFFER_UPDATE_BARRIER_BIT;
1226                }
1227                if usage.intersects(
1228                    crate::BufferUses::STORAGE_READ_ONLY | crate::BufferUses::STORAGE_READ_WRITE,
1229                ) {
1230                    flags |= glow::SHADER_STORAGE_BARRIER_BIT;
1231                }
1232                unsafe { gl.memory_barrier(flags) };
1233            }
1234            C::TextureBarrier(usage) => {
1235                let mut flags = 0;
1236                if usage.contains(crate::TextureUses::RESOURCE) {
1237                    flags |= glow::TEXTURE_FETCH_BARRIER_BIT;
1238                }
1239                if usage.intersects(
1240                    crate::TextureUses::STORAGE_READ_ONLY
1241                        | crate::TextureUses::STORAGE_WRITE_ONLY
1242                        | crate::TextureUses::STORAGE_READ_WRITE,
1243                ) {
1244                    flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT;
1245                }
1246                if usage.contains(crate::TextureUses::COPY_DST) {
1247                    flags |= glow::TEXTURE_UPDATE_BARRIER_BIT;
1248                }
1249                if usage.intersects(
1250                    crate::TextureUses::COLOR_TARGET
1251                        | crate::TextureUses::DEPTH_STENCIL_READ
1252                        | crate::TextureUses::DEPTH_STENCIL_WRITE,
1253                ) {
1254                    flags |= glow::FRAMEBUFFER_BARRIER_BIT;
1255                }
1256                unsafe { gl.memory_barrier(flags) };
1257            }
1258            C::SetViewport {
1259                ref rect,
1260                ref depth,
1261            } => {
1262                unsafe { gl.viewport(rect.x, rect.y, rect.w, rect.h) };
1263                unsafe { gl.depth_range_f32(depth.start, depth.end) };
1264            }
1265            C::SetScissor(ref rect) => {
1266                unsafe { gl.scissor(rect.x, rect.y, rect.w, rect.h) };
1267                unsafe { gl.enable(glow::SCISSOR_TEST) };
1268            }
1269            C::SetStencilFunc {
1270                face,
1271                function,
1272                reference,
1273                read_mask,
1274            } => {
1275                unsafe { gl.stencil_func_separate(face, function, reference as i32, read_mask) };
1276            }
1277            C::SetStencilOps {
1278                face,
1279                write_mask,
1280                ref ops,
1281            } => {
1282                unsafe { gl.stencil_mask_separate(face, write_mask) };
1283                unsafe { gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass) };
1284            }
1285            C::SetVertexAttribute {
1286                buffer,
1287                ref buffer_desc,
1288                attribute_desc: ref vat,
1289            } => {
1290                unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, buffer) };
1291                unsafe { gl.enable_vertex_attrib_array(vat.location) };
1292
1293                if buffer.is_none() {
1294                    match vat.format_desc.attrib_kind {
1295                        super::VertexAttribKind::Float => unsafe {
1296                            gl.vertex_attrib_format_f32(
1297                                vat.location,
1298                                vat.format_desc.element_count,
1299                                vat.format_desc.element_format,
1300                                true, // always normalized
1301                                vat.offset,
1302                            )
1303                        },
1304                        super::VertexAttribKind::Integer => unsafe {
1305                            gl.vertex_attrib_format_i32(
1306                                vat.location,
1307                                vat.format_desc.element_count,
1308                                vat.format_desc.element_format,
1309                                vat.offset,
1310                            )
1311                        },
1312                    }
1313
1314                    //Note: there is apparently a bug on AMD 3500U:
1315                    // this call is ignored if the current array is disabled.
1316                    unsafe { gl.vertex_attrib_binding(vat.location, vat.buffer_index) };
1317                } else {
1318                    match vat.format_desc.attrib_kind {
1319                        super::VertexAttribKind::Float => unsafe {
1320                            gl.vertex_attrib_pointer_f32(
1321                                vat.location,
1322                                vat.format_desc.element_count,
1323                                vat.format_desc.element_format,
1324                                true, // always normalized
1325                                buffer_desc.stride as i32,
1326                                vat.offset as i32,
1327                            )
1328                        },
1329                        super::VertexAttribKind::Integer => unsafe {
1330                            gl.vertex_attrib_pointer_i32(
1331                                vat.location,
1332                                vat.format_desc.element_count,
1333                                vat.format_desc.element_format,
1334                                buffer_desc.stride as i32,
1335                                vat.offset as i32,
1336                            )
1337                        },
1338                    }
1339                    unsafe { gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32) };
1340                }
1341            }
1342            C::UnsetVertexAttribute(location) => {
1343                unsafe { gl.disable_vertex_attrib_array(location) };
1344            }
1345            C::SetVertexBuffer {
1346                index,
1347                ref buffer,
1348                ref buffer_desc,
1349            } => {
1350                unsafe { gl.vertex_binding_divisor(index, buffer_desc.step as u32) };
1351                unsafe {
1352                    gl.bind_vertex_buffer(
1353                        index,
1354                        Some(buffer.raw),
1355                        buffer.offset as i32,
1356                        buffer_desc.stride as i32,
1357                    )
1358                };
1359            }
1360            C::SetDepth(ref depth) => {
1361                unsafe { gl.depth_func(depth.function) };
1362                unsafe { gl.depth_mask(depth.mask) };
1363            }
1364            C::SetDepthBias(bias) => {
1365                if bias.is_enabled() {
1366                    unsafe { gl.enable(glow::POLYGON_OFFSET_FILL) };
1367                    unsafe { gl.polygon_offset(bias.slope_scale, bias.constant as f32) };
1368                } else {
1369                    unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
1370                }
1371            }
1372            C::ConfigureDepthStencil(aspects) => {
1373                if aspects.contains(crate::FormatAspects::DEPTH) {
1374                    unsafe { gl.enable(glow::DEPTH_TEST) };
1375                } else {
1376                    unsafe { gl.disable(glow::DEPTH_TEST) };
1377                }
1378                if aspects.contains(crate::FormatAspects::STENCIL) {
1379                    unsafe { gl.enable(glow::STENCIL_TEST) };
1380                } else {
1381                    unsafe { gl.disable(glow::STENCIL_TEST) };
1382                }
1383            }
1384            C::SetAlphaToCoverage(enabled) => {
1385                if enabled {
1386                    unsafe { gl.enable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1387                } else {
1388                    unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1389                }
1390            }
1391            C::SetProgram(program) => {
1392                unsafe { gl.use_program(Some(program)) };
1393            }
1394            C::SetPrimitive(ref state) => {
1395                unsafe { gl.front_face(state.front_face) };
1396                if state.cull_face != 0 {
1397                    unsafe { gl.enable(glow::CULL_FACE) };
1398                    unsafe { gl.cull_face(state.cull_face) };
1399                } else {
1400                    unsafe { gl.disable(glow::CULL_FACE) };
1401                }
1402                if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
1403                    //Note: this is a bit tricky, since we are controlling the clip, not the clamp.
1404                    if state.unclipped_depth {
1405                        unsafe { gl.enable(glow::DEPTH_CLAMP) };
1406                    } else {
1407                        unsafe { gl.disable(glow::DEPTH_CLAMP) };
1408                    }
1409                }
1410                // POLYGON_MODE_LINE also implies POLYGON_MODE_POINT
1411                if self.features.contains(wgt::Features::POLYGON_MODE_LINE) {
1412                    unsafe { gl.polygon_mode(glow::FRONT_AND_BACK, state.polygon_mode) };
1413                }
1414            }
1415            C::SetBlendConstant(c) => {
1416                unsafe { gl.blend_color(c[0], c[1], c[2], c[3]) };
1417            }
1418            C::SetColorTarget {
1419                draw_buffer_index,
1420                desc: super::ColorTargetDesc { mask, ref blend },
1421            } => {
1422                use wgt::ColorWrites as Cw;
1423                if let Some(index) = draw_buffer_index {
1424                    unsafe {
1425                        gl.color_mask_draw_buffer(
1426                            index,
1427                            mask.contains(Cw::RED),
1428                            mask.contains(Cw::GREEN),
1429                            mask.contains(Cw::BLUE),
1430                            mask.contains(Cw::ALPHA),
1431                        )
1432                    };
1433                    if let Some(ref blend) = *blend {
1434                        unsafe { gl.enable_draw_buffer(glow::BLEND, index) };
1435                        if blend.color != blend.alpha {
1436                            unsafe {
1437                                gl.blend_equation_separate_draw_buffer(
1438                                    index,
1439                                    blend.color.equation,
1440                                    blend.alpha.equation,
1441                                )
1442                            };
1443                            unsafe {
1444                                gl.blend_func_separate_draw_buffer(
1445                                    index,
1446                                    blend.color.src,
1447                                    blend.color.dst,
1448                                    blend.alpha.src,
1449                                    blend.alpha.dst,
1450                                )
1451                            };
1452                        } else {
1453                            unsafe { gl.blend_equation_draw_buffer(index, blend.color.equation) };
1454                            unsafe {
1455                                gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst)
1456                            };
1457                        }
1458                    } else {
1459                        unsafe { gl.disable_draw_buffer(glow::BLEND, index) };
1460                    }
1461                } else {
1462                    unsafe {
1463                        gl.color_mask(
1464                            mask.contains(Cw::RED),
1465                            mask.contains(Cw::GREEN),
1466                            mask.contains(Cw::BLUE),
1467                            mask.contains(Cw::ALPHA),
1468                        )
1469                    };
1470                    if let Some(ref blend) = *blend {
1471                        unsafe { gl.enable(glow::BLEND) };
1472                        if blend.color != blend.alpha {
1473                            unsafe {
1474                                gl.blend_equation_separate(
1475                                    blend.color.equation,
1476                                    blend.alpha.equation,
1477                                )
1478                            };
1479                            unsafe {
1480                                gl.blend_func_separate(
1481                                    blend.color.src,
1482                                    blend.color.dst,
1483                                    blend.alpha.src,
1484                                    blend.alpha.dst,
1485                                )
1486                            };
1487                        } else {
1488                            unsafe { gl.blend_equation(blend.color.equation) };
1489                            unsafe { gl.blend_func(blend.color.src, blend.color.dst) };
1490                        }
1491                    } else {
1492                        unsafe { gl.disable(glow::BLEND) };
1493                    }
1494                }
1495            }
1496            C::BindBuffer {
1497                target,
1498                slot,
1499                buffer,
1500                offset,
1501                size,
1502            } => {
1503                unsafe { gl.bind_buffer_range(target, slot, Some(buffer), offset, size) };
1504            }
1505            C::BindSampler(texture_index, sampler) => {
1506                unsafe { gl.bind_sampler(texture_index, sampler) };
1507            }
1508            C::BindTexture {
1509                slot,
1510                texture,
1511                target,
1512                aspects,
1513                ref mip_levels,
1514            } => {
1515                unsafe { gl.active_texture(glow::TEXTURE0 + slot) };
1516                unsafe { gl.bind_texture(target, Some(texture)) };
1517
1518                unsafe {
1519                    gl.tex_parameter_i32(target, glow::TEXTURE_BASE_LEVEL, mip_levels.start as i32)
1520                };
1521                unsafe {
1522                    gl.tex_parameter_i32(
1523                        target,
1524                        glow::TEXTURE_MAX_LEVEL,
1525                        (mip_levels.end - 1) as i32,
1526                    )
1527                };
1528
1529                let version = gl.version();
1530                let is_min_es_3_1 = version.is_embedded && (version.major, version.minor) >= (3, 1);
1531                let is_min_4_3 = !version.is_embedded && (version.major, version.minor) >= (4, 3);
1532                if is_min_es_3_1 || is_min_4_3 {
1533                    let mode = match aspects {
1534                        crate::FormatAspects::DEPTH => Some(glow::DEPTH_COMPONENT),
1535                        crate::FormatAspects::STENCIL => Some(glow::STENCIL_INDEX),
1536                        _ => None,
1537                    };
1538                    if let Some(mode) = mode {
1539                        unsafe {
1540                            gl.tex_parameter_i32(
1541                                target,
1542                                glow::DEPTH_STENCIL_TEXTURE_MODE,
1543                                mode as _,
1544                            )
1545                        };
1546                    }
1547                }
1548            }
1549            C::BindImage { slot, ref binding } => {
1550                unsafe {
1551                    gl.bind_image_texture(
1552                        slot,
1553                        Some(binding.raw),
1554                        binding.mip_level as i32,
1555                        binding.array_layer.is_none(),
1556                        binding.array_layer.unwrap_or_default() as i32,
1557                        binding.access,
1558                        binding.format,
1559                    )
1560                };
1561            }
1562            C::InsertDebugMarker(ref range) => {
1563                let marker = extract_marker(data_bytes, range);
1564                unsafe {
1565                    if self
1566                        .shared
1567                        .private_caps
1568                        .contains(PrivateCapabilities::DEBUG_FNS)
1569                    {
1570                        gl.debug_message_insert(
1571                            glow::DEBUG_SOURCE_APPLICATION,
1572                            glow::DEBUG_TYPE_MARKER,
1573                            DEBUG_ID,
1574                            glow::DEBUG_SEVERITY_NOTIFICATION,
1575                            marker,
1576                        )
1577                    }
1578                };
1579            }
1580            C::PushDebugGroup(ref range) => {
1581                let marker = extract_marker(data_bytes, range);
1582                unsafe {
1583                    if self
1584                        .shared
1585                        .private_caps
1586                        .contains(PrivateCapabilities::DEBUG_FNS)
1587                    {
1588                        gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker)
1589                    }
1590                };
1591            }
1592            C::PopDebugGroup => {
1593                unsafe {
1594                    if self
1595                        .shared
1596                        .private_caps
1597                        .contains(PrivateCapabilities::DEBUG_FNS)
1598                    {
1599                        gl.pop_debug_group()
1600                    }
1601                };
1602            }
1603            C::SetPushConstants {
1604                ref uniform,
1605                offset,
1606            } => {
1607                fn get_data<T, const COUNT: usize>(data: &[u8], offset: u32) -> [T; COUNT]
1608                where
1609                    [T; COUNT]: bytemuck::AnyBitPattern,
1610                {
1611                    let data_required = size_of::<T>() * COUNT;
1612                    let raw = &data[(offset as usize)..][..data_required];
1613                    bytemuck::pod_read_unaligned(raw)
1614                }
1615
1616                let location = Some(&uniform.location);
1617
1618                match uniform.ty {
1619                    //
1620                    // --- Float 1-4 Component ---
1621                    //
1622                    naga::TypeInner::Scalar(naga::Scalar::F32) => {
1623                        let data = get_data::<f32, 1>(data_bytes, offset)[0];
1624                        unsafe { gl.uniform_1_f32(location, data) };
1625                    }
1626                    naga::TypeInner::Vector {
1627                        size: naga::VectorSize::Bi,
1628                        scalar: naga::Scalar::F32,
1629                    } => {
1630                        let data = &get_data::<f32, 2>(data_bytes, offset);
1631                        unsafe { gl.uniform_2_f32_slice(location, data) };
1632                    }
1633                    naga::TypeInner::Vector {
1634                        size: naga::VectorSize::Tri,
1635                        scalar: naga::Scalar::F32,
1636                    } => {
1637                        let data = &get_data::<f32, 3>(data_bytes, offset);
1638                        unsafe { gl.uniform_3_f32_slice(location, data) };
1639                    }
1640                    naga::TypeInner::Vector {
1641                        size: naga::VectorSize::Quad,
1642                        scalar: naga::Scalar::F32,
1643                    } => {
1644                        let data = &get_data::<f32, 4>(data_bytes, offset);
1645                        unsafe { gl.uniform_4_f32_slice(location, data) };
1646                    }
1647
1648                    //
1649                    // --- Int 1-4 Component ---
1650                    //
1651                    naga::TypeInner::Scalar(naga::Scalar::I32) => {
1652                        let data = get_data::<i32, 1>(data_bytes, offset)[0];
1653                        unsafe { gl.uniform_1_i32(location, data) };
1654                    }
1655                    naga::TypeInner::Vector {
1656                        size: naga::VectorSize::Bi,
1657                        scalar: naga::Scalar::I32,
1658                    } => {
1659                        let data = &get_data::<i32, 2>(data_bytes, offset);
1660                        unsafe { gl.uniform_2_i32_slice(location, data) };
1661                    }
1662                    naga::TypeInner::Vector {
1663                        size: naga::VectorSize::Tri,
1664                        scalar: naga::Scalar::I32,
1665                    } => {
1666                        let data = &get_data::<i32, 3>(data_bytes, offset);
1667                        unsafe { gl.uniform_3_i32_slice(location, data) };
1668                    }
1669                    naga::TypeInner::Vector {
1670                        size: naga::VectorSize::Quad,
1671                        scalar: naga::Scalar::I32,
1672                    } => {
1673                        let data = &get_data::<i32, 4>(data_bytes, offset);
1674                        unsafe { gl.uniform_4_i32_slice(location, data) };
1675                    }
1676
1677                    //
1678                    // --- Uint 1-4 Component ---
1679                    //
1680                    naga::TypeInner::Scalar(naga::Scalar::U32) => {
1681                        let data = get_data::<u32, 1>(data_bytes, offset)[0];
1682                        unsafe { gl.uniform_1_u32(location, data) };
1683                    }
1684                    naga::TypeInner::Vector {
1685                        size: naga::VectorSize::Bi,
1686                        scalar: naga::Scalar::U32,
1687                    } => {
1688                        let data = &get_data::<u32, 2>(data_bytes, offset);
1689                        unsafe { gl.uniform_2_u32_slice(location, data) };
1690                    }
1691                    naga::TypeInner::Vector {
1692                        size: naga::VectorSize::Tri,
1693                        scalar: naga::Scalar::U32,
1694                    } => {
1695                        let data = &get_data::<u32, 3>(data_bytes, offset);
1696                        unsafe { gl.uniform_3_u32_slice(location, data) };
1697                    }
1698                    naga::TypeInner::Vector {
1699                        size: naga::VectorSize::Quad,
1700                        scalar: naga::Scalar::U32,
1701                    } => {
1702                        let data = &get_data::<u32, 4>(data_bytes, offset);
1703                        unsafe { gl.uniform_4_u32_slice(location, data) };
1704                    }
1705
1706                    //
1707                    // --- Matrix 2xR ---
1708                    //
1709                    naga::TypeInner::Matrix {
1710                        columns: naga::VectorSize::Bi,
1711                        rows: naga::VectorSize::Bi,
1712                        scalar: naga::Scalar::F32,
1713                    } => {
1714                        let data = &get_data::<f32, 4>(data_bytes, offset);
1715                        unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) };
1716                    }
1717                    naga::TypeInner::Matrix {
1718                        columns: naga::VectorSize::Bi,
1719                        rows: naga::VectorSize::Tri,
1720                        scalar: naga::Scalar::F32,
1721                    } => {
1722                        // repack 2 vec3s into 6 values.
1723                        let unpacked_data = &get_data::<f32, 8>(data_bytes, offset);
1724                        #[rustfmt::skip]
1725                        let packed_data = [
1726                            unpacked_data[0], unpacked_data[1], unpacked_data[2],
1727                            unpacked_data[4], unpacked_data[5], unpacked_data[6],
1728                        ];
1729                        unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) };
1730                    }
1731                    naga::TypeInner::Matrix {
1732                        columns: naga::VectorSize::Bi,
1733                        rows: naga::VectorSize::Quad,
1734                        scalar: naga::Scalar::F32,
1735                    } => {
1736                        let data = &get_data::<f32, 8>(data_bytes, offset);
1737                        unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) };
1738                    }
1739
1740                    //
1741                    // --- Matrix 3xR ---
1742                    //
1743                    naga::TypeInner::Matrix {
1744                        columns: naga::VectorSize::Tri,
1745                        rows: naga::VectorSize::Bi,
1746                        scalar: naga::Scalar::F32,
1747                    } => {
1748                        let data = &get_data::<f32, 6>(data_bytes, offset);
1749                        unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) };
1750                    }
1751                    naga::TypeInner::Matrix {
1752                        columns: naga::VectorSize::Tri,
1753                        rows: naga::VectorSize::Tri,
1754                        scalar: naga::Scalar::F32,
1755                    } => {
1756                        // repack 3 vec3s into 9 values.
1757                        let unpacked_data = &get_data::<f32, 12>(data_bytes, offset);
1758                        #[rustfmt::skip]
1759                        let packed_data = [
1760                            unpacked_data[0], unpacked_data[1], unpacked_data[2],
1761                            unpacked_data[4], unpacked_data[5], unpacked_data[6],
1762                            unpacked_data[8], unpacked_data[9], unpacked_data[10],
1763                        ];
1764                        unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) };
1765                    }
1766                    naga::TypeInner::Matrix {
1767                        columns: naga::VectorSize::Tri,
1768                        rows: naga::VectorSize::Quad,
1769                        scalar: naga::Scalar::F32,
1770                    } => {
1771                        let data = &get_data::<f32, 12>(data_bytes, offset);
1772                        unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) };
1773                    }
1774
1775                    //
1776                    // --- Matrix 4xR ---
1777                    //
1778                    naga::TypeInner::Matrix {
1779                        columns: naga::VectorSize::Quad,
1780                        rows: naga::VectorSize::Bi,
1781                        scalar: naga::Scalar::F32,
1782                    } => {
1783                        let data = &get_data::<f32, 8>(data_bytes, offset);
1784                        unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) };
1785                    }
1786                    naga::TypeInner::Matrix {
1787                        columns: naga::VectorSize::Quad,
1788                        rows: naga::VectorSize::Tri,
1789                        scalar: naga::Scalar::F32,
1790                    } => {
1791                        // repack 4 vec3s into 12 values.
1792                        let unpacked_data = &get_data::<f32, 16>(data_bytes, offset);
1793                        #[rustfmt::skip]
1794                        let packed_data = [
1795                            unpacked_data[0], unpacked_data[1], unpacked_data[2],
1796                            unpacked_data[4], unpacked_data[5], unpacked_data[6],
1797                            unpacked_data[8], unpacked_data[9], unpacked_data[10],
1798                            unpacked_data[12], unpacked_data[13], unpacked_data[14],
1799                        ];
1800                        unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) };
1801                    }
1802                    naga::TypeInner::Matrix {
1803                        columns: naga::VectorSize::Quad,
1804                        rows: naga::VectorSize::Quad,
1805                        scalar: naga::Scalar::F32,
1806                    } => {
1807                        let data = &get_data::<f32, 16>(data_bytes, offset);
1808                        unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) };
1809                    }
1810                    _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
1811                }
1812            }
1813        }
1814    }
1815}
1816
1817impl crate::Queue for super::Queue {
1818    type A = super::Api;
1819
1820    unsafe fn submit(
1821        &self,
1822        command_buffers: &[&super::CommandBuffer],
1823        _surface_textures: &[&super::Texture],
1824        (signal_fence, signal_value): (&mut super::Fence, crate::FenceValue),
1825    ) -> Result<(), crate::DeviceError> {
1826        let shared = Arc::clone(&self.shared);
1827        let gl = &shared.context.lock();
1828        for cmd_buf in command_buffers.iter() {
1829            // The command encoder assumes a default state when encoding the command buffer.
1830            // Always reset the state between command_buffers to reflect this assumption. Do
1831            // this at the beginning of the loop in case something outside of wgpu modified
1832            // this state prior to commit.
1833            unsafe { self.reset_state(gl) };
1834            if let Some(ref label) = cmd_buf.label {
1835                if self
1836                    .shared
1837                    .private_caps
1838                    .contains(PrivateCapabilities::DEBUG_FNS)
1839                {
1840                    unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) };
1841                }
1842            }
1843
1844            for command in cmd_buf.commands.iter() {
1845                unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
1846            }
1847
1848            if cmd_buf.label.is_some()
1849                && self
1850                    .shared
1851                    .private_caps
1852                    .contains(PrivateCapabilities::DEBUG_FNS)
1853            {
1854                unsafe { gl.pop_debug_group() };
1855            }
1856        }
1857
1858        signal_fence.maintain(gl);
1859        let sync = unsafe { gl.fence_sync(glow::SYNC_GPU_COMMANDS_COMPLETE, 0) }
1860            .map_err(|_| crate::DeviceError::OutOfMemory)?;
1861        signal_fence.pending.push((signal_value, sync));
1862
1863        Ok(())
1864    }
1865
1866    unsafe fn present(
1867        &self,
1868        surface: &super::Surface,
1869        texture: super::Texture,
1870    ) -> Result<(), crate::SurfaceError> {
1871        unsafe { surface.present(texture, &self.shared.context) }
1872    }
1873
1874    unsafe fn get_timestamp_period(&self) -> f32 {
1875        1.0
1876    }
1877}
1878
1879#[cfg(send_sync)]
1880unsafe impl Sync for super::Queue {}
1881#[cfg(send_sync)]
1882unsafe impl Send for super::Queue {}