wgpu_hal/gles/
queue.rs

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