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    /// Runs `command`; `program` is what the program in use tells.
193    unsafe fn process(
194        &self,
195        gl: &glow::Context,
196        command: &C,
197        #[cfg_attr(target_arch = "wasm32", allow(unused))] data_bytes: &[u8],
198        queries: &[glow::Query],
199        program: Option<&super::LinkedProgram>,
200    ) {
201        let first_instance_location =
202            program.and_then(|program| program.first_instance_location.as_ref());
203        match *command {
204            C::Draw {
205                topology,
206                first_vertex,
207                vertex_count,
208                instance_count,
209                first_instance,
210            } => {
211                let supports_full_instancing = self
212                    .shared
213                    .private_caps
214                    .contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING);
215
216                if supports_full_instancing {
217                    unsafe {
218                        gl.draw_arrays_instanced_base_instance(
219                            topology,
220                            first_vertex as i32,
221                            vertex_count as i32,
222                            instance_count as i32,
223                            first_instance,
224                        )
225                    }
226                } else {
227                    if let Some(location) = first_instance_location {
228                        unsafe { gl.uniform_1_u32(Some(location), first_instance) };
229                    }
230
231                    // Don't use `gl.draw_arrays` for `instance_count == 1`.
232                    // Angle has a bug where it doesn't consider the instance divisor when `DYNAMIC_DRAW` is used in `draw_arrays`.
233                    // See https://github.com/gfx-rs/wgpu/issues/3578
234                    unsafe {
235                        gl.draw_arrays_instanced(
236                            topology,
237                            first_vertex as i32,
238                            vertex_count as i32,
239                            instance_count as i32,
240                        )
241                    }
242                };
243            }
244            C::DrawIndexed {
245                topology,
246                index_type,
247                index_count,
248                index_offset,
249                base_vertex,
250                first_instance,
251                instance_count,
252            } => {
253                let supports_full_instancing = self
254                    .shared
255                    .private_caps
256                    .contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING);
257
258                if supports_full_instancing {
259                    unsafe {
260                        gl.draw_elements_instanced_base_vertex_base_instance(
261                            topology,
262                            index_count as i32,
263                            index_type,
264                            index_offset as i32,
265                            instance_count as i32,
266                            base_vertex,
267                            first_instance,
268                        )
269                    }
270                } else {
271                    if let Some(location) = first_instance_location {
272                        unsafe { gl.uniform_1_u32(Some(location), first_instance) };
273                    }
274
275                    if base_vertex == 0 {
276                        unsafe {
277                            // Don't use `gl.draw_elements`/`gl.draw_elements_base_vertex` for `instance_count == 1`.
278                            // 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`.
279                            // See https://github.com/gfx-rs/wgpu/issues/3578
280                            gl.draw_elements_instanced(
281                                topology,
282                                index_count as i32,
283                                index_type,
284                                index_offset as i32,
285                                instance_count as i32,
286                            )
287                        }
288                    } else {
289                        // If we've gotten here, wgpu-core has already validated that this function exists via the DownlevelFlags::BASE_VERTEX feature.
290                        unsafe {
291                            gl.draw_elements_instanced_base_vertex(
292                                topology,
293                                index_count as _,
294                                index_type,
295                                index_offset as i32,
296                                instance_count as i32,
297                                base_vertex,
298                            )
299                        }
300                    }
301                }
302            }
303            C::DrawIndirect {
304                topology,
305                indirect_buf,
306                indirect_offset,
307            } => {
308                unsafe { gl.uniform_1_u32(first_instance_location, 0) };
309
310                unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)) };
311                unsafe { gl.draw_arrays_indirect_offset(topology, indirect_offset as i32) };
312            }
313            C::DrawIndexedIndirect {
314                topology,
315                index_type,
316                indirect_buf,
317                indirect_offset,
318            } => {
319                unsafe { gl.uniform_1_u32(first_instance_location, 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 { ref data } => {
1591                // Each uniform of the program from the block: one per stage
1592                // may read the same words, and those the program does not
1593                // use have no location.
1594                for uniform in program.into_iter().flat_map(|program| &program.immediates_descs) {
1595                    unsafe { set_immediate(gl, uniform, data_bytes, data.start + uniform.offset) };
1596                }
1597            }
1598            C::SetClipDistances {
1599                old_count,
1600                new_count,
1601            } => {
1602                // Disable clip planes that are no longer active
1603                for i in new_count..old_count {
1604                    unsafe { gl.disable(glow::CLIP_DISTANCE0 + i) };
1605                }
1606
1607                // Enable clip planes that are now active
1608                for i in old_count..new_count {
1609                    unsafe { gl.enable(glow::CLIP_DISTANCE0 + i) };
1610                }
1611            }
1612        }
1613    }
1614}
1615
1616impl crate::Queue for super::Queue {
1617    type A = super::Api;
1618
1619    unsafe fn submit(
1620        &self,
1621        command_buffers: &[&super::CommandBuffer],
1622        _surface_textures: &[&super::Texture],
1623        (signal_fence, signal_value): (&super::Fence, crate::FenceValue),
1624    ) -> Result<(), crate::DeviceError> {
1625        let shared = Arc::clone(&self.shared);
1626        let gl = &shared.context.lock();
1627        for cmd_buf in command_buffers.iter() {
1628            // The command encoder assumes a default state when encoding the command buffer.
1629            // Always reset the state between command_buffers to reflect this assumption. Do
1630            // this at the beginning of the loop in case something outside of wgpu modified
1631            // this state prior to commit.
1632            unsafe { self.reset_state(gl) };
1633            if let Some(ref label) = cmd_buf.label {
1634                if self
1635                    .shared
1636                    .private_caps
1637                    .contains(PrivateCapabilities::DEBUG_FNS)
1638                {
1639                    unsafe {
1640                        gl.push_debug_group(
1641                            glow::DEBUG_SOURCE_APPLICATION,
1642                            DEBUG_ID,
1643                            to_debug_str(label),
1644                        )
1645                    };
1646                }
1647            }
1648
1649            let mut state = super::gl_state::GlState::default();
1650            // The program in use: its link is read at its first use, so
1651            // the GPU process links while the encoders record.
1652            let mut program = None;
1653            for command in cmd_buf.commands.iter() {
1654                if let C::SetProgram(ref inner) = *command {
1655                    program = Some(unsafe { inner.linked(gl) });
1656                }
1657                if !unsafe { state.apply(gl, command) } {
1658                    unsafe {
1659                        self.process(
1660                            gl,
1661                            command,
1662                            &cmd_buf.data_bytes,
1663                            &cmd_buf.queries,
1664                            program.as_deref(),
1665                        )
1666                    };
1667                }
1668            }
1669            unsafe { state.finish(gl) };
1670
1671            if cmd_buf.label.is_some()
1672                && self
1673                    .shared
1674                    .private_caps
1675                    .contains(PrivateCapabilities::DEBUG_FNS)
1676            {
1677                unsafe { gl.pop_debug_group() };
1678            }
1679        }
1680
1681        signal_fence.maintain(gl);
1682        signal_fence.signal(gl, signal_value)?;
1683
1684        // This is extremely important. If we don't flush, the above fences may never
1685        // be signaled, particularly in headless contexts. Headed contexts will
1686        // often flush every so often, but headless contexts may not.
1687        unsafe { gl.flush() };
1688
1689        Ok(())
1690    }
1691
1692    unsafe fn present(
1693        &self,
1694        surface: &super::Surface,
1695        texture: super::Texture,
1696    ) -> Result<(), crate::SurfaceError> {
1697        unsafe { surface.present(texture, &self.shared.context) }
1698    }
1699
1700    unsafe fn get_timestamp_period(&self) -> f32 {
1701        1.0
1702    }
1703
1704    unsafe fn wait_for_idle(&self) -> Result<(), crate::DeviceError> {
1705        let gl = &self.shared.context.lock();
1706        unsafe { gl.finish() };
1707        Ok(())
1708    }
1709}
1710
1711#[cfg(send_sync)]
1712unsafe impl Sync for super::Queue {}
1713#[cfg(send_sync)]
1714unsafe impl Send for super::Queue {}
1715
1716/// Sets `uniform` from its words at `offset` in `data`.
1717unsafe fn set_immediate(
1718    gl: &glow::Context,
1719    uniform: &super::ImmediateDesc,
1720    data_bytes: &[u8],
1721    offset: u32,
1722) {
1723    fn get_data<T, const COUNT: usize>(data: &[u8], offset: u32) -> [T; COUNT]
1724    where
1725        [T; COUNT]: bytemuck::AnyBitPattern,
1726    {
1727        let data_required = size_of::<T>() * COUNT;
1728        let raw = &data[(offset as usize)..][..data_required];
1729        bytemuck::pod_read_unaligned(raw)
1730    }
1731
1732    let location = Some(&uniform.location);
1733    use nt::glsl::{GlslScalar, GlslUniformType, GlslVectorSize};
1734    match uniform.ty {
1735        //
1736        // --- Float 1-4 Component ---
1737        //
1738        GlslUniformType::Scalar(GlslScalar::F32) => {
1739            let data = get_data::<f32, 1>(data_bytes, offset)[0];
1740            unsafe { gl.uniform_1_f32(location, data) };
1741        }
1742        GlslUniformType::Vector {
1743            size: GlslVectorSize::Bi,
1744            scalar: GlslScalar::F32,
1745        } => {
1746            let data = &get_data::<f32, 2>(data_bytes, offset);
1747            unsafe { gl.uniform_2_f32_slice(location, data) };
1748        }
1749        GlslUniformType::Vector {
1750            size: GlslVectorSize::Tri,
1751            scalar: GlslScalar::F32,
1752        } => {
1753            let data = &get_data::<f32, 3>(data_bytes, offset);
1754            unsafe { gl.uniform_3_f32_slice(location, data) };
1755        }
1756        GlslUniformType::Vector {
1757            size: GlslVectorSize::Quad,
1758            scalar: GlslScalar::F32,
1759        } => {
1760            let data = &get_data::<f32, 4>(data_bytes, offset);
1761            unsafe { gl.uniform_4_f32_slice(location, data) };
1762        }
1763
1764        //
1765        // --- Int 1-4 Component ---
1766        //
1767        GlslUniformType::Scalar(GlslScalar::I32) => {
1768            let data = get_data::<i32, 1>(data_bytes, offset)[0];
1769            unsafe { gl.uniform_1_i32(location, data) };
1770        }
1771        GlslUniformType::Vector {
1772            size: GlslVectorSize::Bi,
1773            scalar: GlslScalar::I32,
1774        } => {
1775            let data = &get_data::<i32, 2>(data_bytes, offset);
1776            unsafe { gl.uniform_2_i32_slice(location, data) };
1777        }
1778        GlslUniformType::Vector {
1779            size: GlslVectorSize::Tri,
1780            scalar: GlslScalar::I32,
1781        } => {
1782            let data = &get_data::<i32, 3>(data_bytes, offset);
1783            unsafe { gl.uniform_3_i32_slice(location, data) };
1784        }
1785        GlslUniformType::Vector {
1786            size: GlslVectorSize::Quad,
1787            scalar: GlslScalar::I32,
1788        } => {
1789            let data = &get_data::<i32, 4>(data_bytes, offset);
1790            unsafe { gl.uniform_4_i32_slice(location, data) };
1791        }
1792
1793        //
1794        // --- Uint 1-4 Component ---
1795        //
1796        GlslUniformType::Scalar(GlslScalar::U32) => {
1797            let data = get_data::<u32, 1>(data_bytes, offset)[0];
1798            unsafe { gl.uniform_1_u32(location, data) };
1799        }
1800        GlslUniformType::Vector {
1801            size: GlslVectorSize::Bi,
1802            scalar: GlslScalar::U32,
1803        } => {
1804            let data = &get_data::<u32, 2>(data_bytes, offset);
1805            unsafe { gl.uniform_2_u32_slice(location, data) };
1806        }
1807        GlslUniformType::Vector {
1808            size: GlslVectorSize::Tri,
1809            scalar: GlslScalar::U32,
1810        } => {
1811            let data = &get_data::<u32, 3>(data_bytes, offset);
1812            unsafe { gl.uniform_3_u32_slice(location, data) };
1813        }
1814        GlslUniformType::Vector {
1815            size: GlslVectorSize::Quad,
1816            scalar: GlslScalar::U32,
1817        } => {
1818            let data = &get_data::<u32, 4>(data_bytes, offset);
1819            unsafe { gl.uniform_4_u32_slice(location, data) };
1820        }
1821
1822        //
1823        // --- Matrix 2xR ---
1824        //
1825        GlslUniformType::Matrix {
1826            columns: GlslVectorSize::Bi,
1827            rows: GlslVectorSize::Bi,
1828            scalar: GlslScalar::F32,
1829        } => {
1830            let data = &get_data::<f32, 4>(data_bytes, offset);
1831            unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) };
1832        }
1833        GlslUniformType::Matrix {
1834            columns: GlslVectorSize::Bi,
1835            rows: GlslVectorSize::Tri,
1836            scalar: GlslScalar::F32,
1837        } => {
1838            // repack 2 vec3s into 6 values.
1839            let unpacked_data = &get_data::<f32, 8>(data_bytes, offset);
1840            #[rustfmt::skip]
1841            let packed_data = [
1842                unpacked_data[0], unpacked_data[1], unpacked_data[2],
1843                unpacked_data[4], unpacked_data[5], unpacked_data[6],
1844            ];
1845            unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) };
1846        }
1847        GlslUniformType::Matrix {
1848            columns: GlslVectorSize::Bi,
1849            rows: GlslVectorSize::Quad,
1850            scalar: GlslScalar::F32,
1851        } => {
1852            let data = &get_data::<f32, 8>(data_bytes, offset);
1853            unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) };
1854        }
1855
1856        //
1857        // --- Matrix 3xR ---
1858        //
1859        GlslUniformType::Matrix {
1860            columns: GlslVectorSize::Tri,
1861            rows: GlslVectorSize::Bi,
1862            scalar: GlslScalar::F32,
1863        } => {
1864            let data = &get_data::<f32, 6>(data_bytes, offset);
1865            unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) };
1866        }
1867        GlslUniformType::Matrix {
1868            columns: GlslVectorSize::Tri,
1869            rows: GlslVectorSize::Tri,
1870            scalar: GlslScalar::F32,
1871        } => {
1872            // repack 3 vec3s into 9 values.
1873            let unpacked_data = &get_data::<f32, 12>(data_bytes, offset);
1874            #[rustfmt::skip]
1875            let packed_data = [
1876                unpacked_data[0], unpacked_data[1], unpacked_data[2],
1877                unpacked_data[4], unpacked_data[5], unpacked_data[6],
1878                unpacked_data[8], unpacked_data[9], unpacked_data[10],
1879            ];
1880            unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) };
1881        }
1882        GlslUniformType::Matrix {
1883            columns: GlslVectorSize::Tri,
1884            rows: GlslVectorSize::Quad,
1885            scalar: GlslScalar::F32,
1886        } => {
1887            let data = &get_data::<f32, 12>(data_bytes, offset);
1888            unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) };
1889        }
1890
1891        //
1892        // --- Matrix 4xR ---
1893        //
1894        GlslUniformType::Matrix {
1895            columns: GlslVectorSize::Quad,
1896            rows: GlslVectorSize::Bi,
1897            scalar: GlslScalar::F32,
1898        } => {
1899            let data = &get_data::<f32, 8>(data_bytes, offset);
1900            unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) };
1901        }
1902        GlslUniformType::Matrix {
1903            columns: GlslVectorSize::Quad,
1904            rows: GlslVectorSize::Tri,
1905            scalar: GlslScalar::F32,
1906        } => {
1907            // repack 4 vec3s into 12 values.
1908            let unpacked_data = &get_data::<f32, 16>(data_bytes, offset);
1909            #[rustfmt::skip]
1910            let packed_data = [
1911                unpacked_data[0], unpacked_data[1], unpacked_data[2],
1912                unpacked_data[4], unpacked_data[5], unpacked_data[6],
1913                unpacked_data[8], unpacked_data[9], unpacked_data[10],
1914                unpacked_data[12], unpacked_data[13], unpacked_data[14],
1915            ];
1916            unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) };
1917        }
1918        GlslUniformType::Matrix {
1919            columns: GlslVectorSize::Quad,
1920            rows: GlslVectorSize::Quad,
1921            scalar: GlslScalar::F32,
1922        } => {
1923            let data = &get_data::<f32, 16>(data_bytes, offset);
1924            unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) };
1925        }
1926        _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
1927    }
1928}