Skip to main content

wgpu_hal/gles/
queue.rs

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