li_wgpu_hal/gles/
queue.rs

1use super::{conv::is_layered_target, Command as C, PrivateCapabilities};
2use arrayvec::ArrayVec;
3use glow::HasContext;
4use std::{mem, slice, sync::Arc};
5
6#[cfg(not(target_arch = "wasm32"))]
7const DEBUG_ID: u32 = 0;
8
9#[cfg(not(target_arch = "wasm32"))]
10fn extract_marker<'a>(data: &'a [u8], range: &std::ops::Range<u32>) -> &'a str {
11    std::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap()
12}
13
14fn get_2d_target(target: u32, array_layer: u32) -> u32 {
15    const CUBEMAP_FACES: [u32; 6] = [
16        glow::TEXTURE_CUBE_MAP_POSITIVE_X,
17        glow::TEXTURE_CUBE_MAP_NEGATIVE_X,
18        glow::TEXTURE_CUBE_MAP_POSITIVE_Y,
19        glow::TEXTURE_CUBE_MAP_NEGATIVE_Y,
20        glow::TEXTURE_CUBE_MAP_POSITIVE_Z,
21        glow::TEXTURE_CUBE_MAP_NEGATIVE_Z,
22    ];
23
24    match target {
25        glow::TEXTURE_2D => target,
26        glow::TEXTURE_CUBE_MAP => CUBEMAP_FACES[array_layer as usize],
27        _ => unreachable!(),
28    }
29}
30
31fn get_z_offset(target: u32, base: &crate::TextureCopyBase) -> u32 {
32    match target {
33        glow::TEXTURE_2D_ARRAY | glow::TEXTURE_CUBE_MAP_ARRAY => base.array_layer,
34        glow::TEXTURE_3D => base.origin.z,
35        _ => unreachable!(),
36    }
37}
38
39impl super::Queue {
40    /// Performs a manual shader clear, used as a workaround for a clearing bug on mesa
41    unsafe fn perform_shader_clear(&self, gl: &glow::Context, draw_buffer: u32, color: [f32; 4]) {
42        unsafe { gl.use_program(Some(self.shader_clear_program)) };
43        unsafe {
44            gl.uniform_4_f32(
45                Some(&self.shader_clear_program_color_uniform_location),
46                color[0],
47                color[1],
48                color[2],
49                color[3],
50            )
51        };
52        unsafe { gl.disable(glow::DEPTH_TEST) };
53        unsafe { gl.disable(glow::STENCIL_TEST) };
54        unsafe { gl.disable(glow::SCISSOR_TEST) };
55        unsafe { gl.disable(glow::BLEND) };
56        unsafe { gl.disable(glow::CULL_FACE) };
57        unsafe { gl.draw_buffers(&[glow::COLOR_ATTACHMENT0 + draw_buffer]) };
58        unsafe { gl.draw_arrays(glow::TRIANGLES, 0, 3) };
59
60        if self.draw_buffer_count != 0 {
61            // Reset the draw buffers to what they were before the clear
62            let indices = (0..self.draw_buffer_count as u32)
63                .map(|i| glow::COLOR_ATTACHMENT0 + i)
64                .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
65            unsafe { gl.draw_buffers(&indices) };
66        }
67    }
68
69    unsafe fn reset_state(&mut self, gl: &glow::Context) {
70        unsafe { gl.use_program(None) };
71        unsafe { gl.bind_framebuffer(glow::FRAMEBUFFER, None) };
72        unsafe { gl.disable(glow::DEPTH_TEST) };
73        unsafe { gl.disable(glow::STENCIL_TEST) };
74        unsafe { gl.disable(glow::SCISSOR_TEST) };
75        unsafe { gl.disable(glow::BLEND) };
76        unsafe { gl.disable(glow::CULL_FACE) };
77        unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
78        unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
79        if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
80            unsafe { gl.disable(glow::DEPTH_CLAMP) };
81        }
82
83        unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None) };
84        self.current_index_buffer = None;
85    }
86
87    unsafe fn set_attachment(
88        &self,
89        gl: &glow::Context,
90        fbo_target: u32,
91        attachment: u32,
92        view: &super::TextureView,
93    ) {
94        match view.inner {
95            super::TextureInner::Renderbuffer { raw } => {
96                unsafe {
97                    gl.framebuffer_renderbuffer(
98                        fbo_target,
99                        attachment,
100                        glow::RENDERBUFFER,
101                        Some(raw),
102                    )
103                };
104            }
105            super::TextureInner::DefaultRenderbuffer => panic!("Unexpected default RBO"),
106            super::TextureInner::Texture { raw, target } => {
107                let num_layers = view.array_layers.end - view.array_layers.start;
108                if num_layers > 1 {
109                    #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
110                    unsafe {
111                        gl.framebuffer_texture_multiview_ovr(
112                            fbo_target,
113                            attachment,
114                            Some(raw),
115                            view.mip_levels.start as i32,
116                            view.array_layers.start as i32,
117                            num_layers as i32,
118                        )
119                    };
120                } else if is_layered_target(target) {
121                    unsafe {
122                        gl.framebuffer_texture_layer(
123                            fbo_target,
124                            attachment,
125                            Some(raw),
126                            view.mip_levels.start as i32,
127                            view.array_layers.start as i32,
128                        )
129                    };
130                } else {
131                    unsafe {
132                        gl.framebuffer_texture_2d(
133                            fbo_target,
134                            attachment,
135                            get_2d_target(target, view.array_layers.start),
136                            Some(raw),
137                            view.mip_levels.start as i32,
138                        )
139                    };
140                }
141            }
142            #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
143            super::TextureInner::ExternalFramebuffer { ref inner } => unsafe {
144                gl.bind_external_framebuffer(glow::FRAMEBUFFER, inner);
145            },
146        }
147    }
148
149    unsafe fn process(
150        &mut self,
151        gl: &glow::Context,
152        command: &C,
153        #[cfg_attr(target_arch = "wasm32", allow(unused))] data_bytes: &[u8],
154        queries: &[glow::Query],
155    ) {
156        match *command {
157            C::Draw {
158                topology,
159                start_vertex,
160                vertex_count,
161                instance_count,
162            } => {
163                // Don't use `gl.draw_arrays` for `instance_count == 1`.
164                // Angle has a bug where it doesn't consider the instance divisor when `DYNAMIC_DRAW` is used in `draw_arrays`.
165                // See https://github.com/gfx-rs/wgpu/issues/3578
166                unsafe {
167                    gl.draw_arrays_instanced(
168                        topology,
169                        start_vertex as i32,
170                        vertex_count as i32,
171                        instance_count as i32,
172                    )
173                };
174            }
175            C::DrawIndexed {
176                topology,
177                index_type,
178                index_count,
179                index_offset,
180                base_vertex,
181                instance_count,
182            } => {
183                match base_vertex {
184                    // Don't use `gl.draw_elements`/`gl.draw_elements_base_vertex` for `instance_count == 1`.
185                    // 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`.
186                    // See https://github.com/gfx-rs/wgpu/issues/3578
187                    0 => unsafe {
188                        gl.draw_elements_instanced(
189                            topology,
190                            index_count as i32,
191                            index_type,
192                            index_offset as i32,
193                            instance_count as i32,
194                        )
195                    },
196                    _ => unsafe {
197                        gl.draw_elements_instanced_base_vertex(
198                            topology,
199                            index_count as _,
200                            index_type,
201                            index_offset as i32,
202                            instance_count as i32,
203                            base_vertex,
204                        )
205                    },
206                }
207            }
208            C::DrawIndirect {
209                topology,
210                indirect_buf,
211                indirect_offset,
212            } => {
213                unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)) };
214                unsafe { gl.draw_arrays_indirect_offset(topology, indirect_offset as i32) };
215            }
216            C::DrawIndexedIndirect {
217                topology,
218                index_type,
219                indirect_buf,
220                indirect_offset,
221            } => {
222                unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)) };
223                unsafe {
224                    gl.draw_elements_indirect_offset(topology, index_type, indirect_offset as i32)
225                };
226            }
227            C::Dispatch(group_counts) => {
228                unsafe { gl.dispatch_compute(group_counts[0], group_counts[1], group_counts[2]) };
229            }
230            C::DispatchIndirect {
231                indirect_buf,
232                indirect_offset,
233            } => {
234                unsafe { gl.bind_buffer(glow::DISPATCH_INDIRECT_BUFFER, Some(indirect_buf)) };
235                unsafe { gl.dispatch_compute_indirect(indirect_offset as i32) };
236            }
237            C::ClearBuffer {
238                ref dst,
239                dst_target,
240                ref range,
241            } => match dst.raw {
242                Some(buffer) => {
243                    // When `INDEX_BUFFER_ROLE_CHANGE` isn't available, we can't copy into the
244                    // index buffer from the zero buffer. This would fail in Chrome with the
245                    // following message:
246                    //
247                    // > Cannot copy into an element buffer destination from a non-element buffer
248                    // > source
249                    //
250                    // Instead, we'll upload zeroes into the buffer.
251                    let can_use_zero_buffer = self
252                        .shared
253                        .private_caps
254                        .contains(super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
255                        || dst_target != glow::ELEMENT_ARRAY_BUFFER;
256
257                    if can_use_zero_buffer {
258                        unsafe { gl.bind_buffer(glow::COPY_READ_BUFFER, Some(self.zero_buffer)) };
259                        unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
260                        let mut dst_offset = range.start;
261                        while dst_offset < range.end {
262                            let size = (range.end - dst_offset).min(super::ZERO_BUFFER_SIZE as u64);
263                            unsafe {
264                                gl.copy_buffer_sub_data(
265                                    glow::COPY_READ_BUFFER,
266                                    dst_target,
267                                    0,
268                                    dst_offset as i32,
269                                    size as i32,
270                                )
271                            };
272                            dst_offset += size;
273                        }
274                    } else {
275                        unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
276                        let zeroes = vec![0u8; (range.end - range.start) as usize];
277                        unsafe {
278                            gl.buffer_sub_data_u8_slice(dst_target, range.start as i32, &zeroes)
279                        };
280                    }
281                }
282                None => {
283                    dst.data.as_ref().unwrap().lock().unwrap().as_mut_slice()
284                        [range.start as usize..range.end as usize]
285                        .fill(0);
286                }
287            },
288            C::CopyBufferToBuffer {
289                ref src,
290                src_target,
291                ref dst,
292                dst_target,
293                copy,
294            } => {
295                let copy_src_target = glow::COPY_READ_BUFFER;
296                let is_index_buffer_only_element_dst = !self
297                    .shared
298                    .private_caps
299                    .contains(super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
300                    && dst_target == glow::ELEMENT_ARRAY_BUFFER
301                    || src_target == glow::ELEMENT_ARRAY_BUFFER;
302
303                // WebGL not allowed to copy data from other targets to element buffer and can't copy element data to other buffers
304                let copy_dst_target = if is_index_buffer_only_element_dst {
305                    glow::ELEMENT_ARRAY_BUFFER
306                } else {
307                    glow::COPY_WRITE_BUFFER
308                };
309                let size = copy.size.get() as usize;
310                match (src.raw, dst.raw) {
311                    (Some(ref src), Some(ref dst)) => {
312                        unsafe { gl.bind_buffer(copy_src_target, Some(*src)) };
313                        unsafe { gl.bind_buffer(copy_dst_target, Some(*dst)) };
314                        unsafe {
315                            gl.copy_buffer_sub_data(
316                                copy_src_target,
317                                copy_dst_target,
318                                copy.src_offset as _,
319                                copy.dst_offset as _,
320                                copy.size.get() as _,
321                            )
322                        };
323                    }
324                    (Some(src), None) => {
325                        let mut data = dst.data.as_ref().unwrap().lock().unwrap();
326                        let dst_data = &mut data.as_mut_slice()
327                            [copy.dst_offset as usize..copy.dst_offset as usize + size];
328
329                        unsafe { gl.bind_buffer(copy_src_target, Some(src)) };
330                        unsafe {
331                            self.shared.get_buffer_sub_data(
332                                gl,
333                                copy_src_target,
334                                copy.src_offset as i32,
335                                dst_data,
336                            )
337                        };
338                    }
339                    (None, Some(dst)) => {
340                        let data = src.data.as_ref().unwrap().lock().unwrap();
341                        let src_data = &data.as_slice()
342                            [copy.src_offset as usize..copy.src_offset as usize + size];
343                        unsafe { gl.bind_buffer(copy_dst_target, Some(dst)) };
344                        unsafe {
345                            gl.buffer_sub_data_u8_slice(
346                                copy_dst_target,
347                                copy.dst_offset as i32,
348                                src_data,
349                            )
350                        };
351                    }
352                    (None, None) => {
353                        todo!()
354                    }
355                }
356                unsafe { gl.bind_buffer(copy_src_target, None) };
357                if is_index_buffer_only_element_dst {
358                    unsafe {
359                        gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, self.current_index_buffer)
360                    };
361                } else {
362                    unsafe { gl.bind_buffer(copy_dst_target, None) };
363                }
364            }
365            #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
366            C::CopyExternalImageToTexture {
367                ref src,
368                dst,
369                dst_target,
370                dst_format,
371                dst_premultiplication,
372                ref copy,
373            } => {
374                const UNPACK_FLIP_Y_WEBGL: u32 =
375                    web_sys::WebGl2RenderingContext::UNPACK_FLIP_Y_WEBGL;
376                const UNPACK_PREMULTIPLY_ALPHA_WEBGL: u32 =
377                    web_sys::WebGl2RenderingContext::UNPACK_PREMULTIPLY_ALPHA_WEBGL;
378
379                unsafe {
380                    if src.flip_y {
381                        gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, true);
382                    }
383                    if dst_premultiplication {
384                        gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
385                    }
386                }
387
388                unsafe { gl.bind_texture(dst_target, Some(dst)) };
389                let format_desc = self.shared.describe_texture_format(dst_format);
390                if is_layered_target(dst_target) {
391                    let z_offset = get_z_offset(dst_target, &copy.dst_base);
392
393                    match src.source {
394                        wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
395                            gl.tex_sub_image_3d_with_image_bitmap(
396                                dst_target,
397                                copy.dst_base.mip_level as i32,
398                                copy.dst_base.origin.x as i32,
399                                copy.dst_base.origin.y as i32,
400                                z_offset as i32,
401                                copy.size.width as i32,
402                                copy.size.height as i32,
403                                copy.size.depth as i32,
404                                format_desc.external,
405                                format_desc.data_type,
406                                b,
407                            );
408                        },
409                        wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
410                            gl.tex_sub_image_3d_with_html_video_element(
411                                dst_target,
412                                copy.dst_base.mip_level as i32,
413                                copy.dst_base.origin.x as i32,
414                                copy.dst_base.origin.y as i32,
415                                z_offset as i32,
416                                copy.size.width as i32,
417                                copy.size.height as i32,
418                                copy.size.depth as i32,
419                                format_desc.external,
420                                format_desc.data_type,
421                                v,
422                            );
423                        },
424                        wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
425                            gl.tex_sub_image_3d_with_html_canvas_element(
426                                dst_target,
427                                copy.dst_base.mip_level as i32,
428                                copy.dst_base.origin.x as i32,
429                                copy.dst_base.origin.y as i32,
430                                z_offset as i32,
431                                copy.size.width as i32,
432                                copy.size.height as i32,
433                                copy.size.depth as i32,
434                                format_desc.external,
435                                format_desc.data_type,
436                                c,
437                            );
438                        },
439                        wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
440                    }
441                } else {
442                    let dst_target = get_2d_target(dst_target, copy.dst_base.array_layer);
443
444                    match src.source {
445                        wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
446                            gl.tex_sub_image_2d_with_image_bitmap_and_width_and_height(
447                                dst_target,
448                                copy.dst_base.mip_level as i32,
449                                copy.dst_base.origin.x as i32,
450                                copy.dst_base.origin.y as i32,
451                                copy.size.width as i32,
452                                copy.size.height as i32,
453                                format_desc.external,
454                                format_desc.data_type,
455                                b,
456                            );
457                        },
458                        wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
459                            gl.tex_sub_image_2d_with_html_video_and_width_and_height(
460                                dst_target,
461                                copy.dst_base.mip_level as i32,
462                                copy.dst_base.origin.x as i32,
463                                copy.dst_base.origin.y as i32,
464                                copy.size.width as i32,
465                                copy.size.height as i32,
466                                format_desc.external,
467                                format_desc.data_type,
468                                v,
469                            )
470                        },
471                        wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
472                            gl.tex_sub_image_2d_with_html_canvas_and_width_and_height(
473                                dst_target,
474                                copy.dst_base.mip_level as i32,
475                                copy.dst_base.origin.x as i32,
476                                copy.dst_base.origin.y as i32,
477                                copy.size.width as i32,
478                                copy.size.height as i32,
479                                format_desc.external,
480                                format_desc.data_type,
481                                c,
482                            )
483                        },
484                        wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
485                    }
486                }
487
488                unsafe {
489                    if src.flip_y {
490                        gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, false);
491                    }
492                    if dst_premultiplication {
493                        gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
494                    }
495                }
496            }
497            C::CopyTextureToTexture {
498                src,
499                src_target,
500                dst,
501                dst_target,
502                ref copy,
503            } => {
504                //TODO: handle 3D copies
505                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
506                if is_layered_target(src_target) {
507                    //TODO: handle GLES without framebuffer_texture_3d
508                    unsafe {
509                        gl.framebuffer_texture_layer(
510                            glow::READ_FRAMEBUFFER,
511                            glow::COLOR_ATTACHMENT0,
512                            Some(src),
513                            copy.src_base.mip_level as i32,
514                            copy.src_base.array_layer as i32,
515                        )
516                    };
517                } else {
518                    unsafe {
519                        gl.framebuffer_texture_2d(
520                            glow::READ_FRAMEBUFFER,
521                            glow::COLOR_ATTACHMENT0,
522                            src_target,
523                            Some(src),
524                            copy.src_base.mip_level as i32,
525                        )
526                    };
527                }
528
529                unsafe { gl.bind_texture(dst_target, Some(dst)) };
530                if is_layered_target(dst_target) {
531                    unsafe {
532                        gl.copy_tex_sub_image_3d(
533                            dst_target,
534                            copy.dst_base.mip_level as i32,
535                            copy.dst_base.origin.x as i32,
536                            copy.dst_base.origin.y as i32,
537                            get_z_offset(dst_target, &copy.dst_base) as i32,
538                            copy.src_base.origin.x as i32,
539                            copy.src_base.origin.y as i32,
540                            copy.size.width as i32,
541                            copy.size.height as i32,
542                        )
543                    };
544                } else {
545                    unsafe {
546                        gl.copy_tex_sub_image_2d(
547                            get_2d_target(dst_target, copy.dst_base.array_layer),
548                            copy.dst_base.mip_level as i32,
549                            copy.dst_base.origin.x as i32,
550                            copy.dst_base.origin.y as i32,
551                            copy.src_base.origin.x as i32,
552                            copy.src_base.origin.y as i32,
553                            copy.size.width as i32,
554                            copy.size.height as i32,
555                        )
556                    };
557                }
558            }
559            C::CopyBufferToTexture {
560                ref src,
561                src_target: _,
562                dst,
563                dst_target,
564                dst_format,
565                ref copy,
566            } => {
567                let (block_width, block_height) = dst_format.block_dimensions();
568                let block_size = dst_format.block_size(None).unwrap();
569                let format_desc = self.shared.describe_texture_format(dst_format);
570                let row_texels = copy
571                    .buffer_layout
572                    .bytes_per_row
573                    .map_or(0, |bpr| block_width * bpr / block_size);
574                let column_texels = copy
575                    .buffer_layout
576                    .rows_per_image
577                    .map_or(0, |rpi| block_height * rpi);
578
579                unsafe { gl.bind_texture(dst_target, Some(dst)) };
580                unsafe { gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32) };
581                unsafe { gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32) };
582                let mut unbind_unpack_buffer = false;
583                if !dst_format.is_compressed() {
584                    let buffer_data;
585                    let unpack_data = match src.raw {
586                        Some(buffer) => {
587                            unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
588                            unbind_unpack_buffer = true;
589                            glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32)
590                        }
591                        None => {
592                            buffer_data = src.data.as_ref().unwrap().lock().unwrap();
593                            let src_data =
594                                &buffer_data.as_slice()[copy.buffer_layout.offset as usize..];
595                            glow::PixelUnpackData::Slice(src_data)
596                        }
597                    };
598                    if is_layered_target(dst_target) {
599                        unsafe {
600                            gl.tex_sub_image_3d(
601                                dst_target,
602                                copy.texture_base.mip_level as i32,
603                                copy.texture_base.origin.x as i32,
604                                copy.texture_base.origin.y as i32,
605                                get_z_offset(dst_target, &copy.texture_base) as i32,
606                                copy.size.width as i32,
607                                copy.size.height as i32,
608                                copy.size.depth as i32,
609                                format_desc.external,
610                                format_desc.data_type,
611                                unpack_data,
612                            )
613                        };
614                    } else {
615                        unsafe {
616                            gl.tex_sub_image_2d(
617                                get_2d_target(dst_target, copy.texture_base.array_layer),
618                                copy.texture_base.mip_level as i32,
619                                copy.texture_base.origin.x as i32,
620                                copy.texture_base.origin.y as i32,
621                                copy.size.width as i32,
622                                copy.size.height as i32,
623                                format_desc.external,
624                                format_desc.data_type,
625                                unpack_data,
626                            )
627                        };
628                    }
629                } else {
630                    let bytes_per_row = copy
631                        .buffer_layout
632                        .bytes_per_row
633                        .unwrap_or(copy.size.width * block_size);
634                    let minimum_rows_per_image =
635                        (copy.size.height + block_height - 1) / block_height;
636                    let rows_per_image = copy
637                        .buffer_layout
638                        .rows_per_image
639                        .unwrap_or(minimum_rows_per_image);
640
641                    let bytes_per_image = bytes_per_row * rows_per_image;
642                    let minimum_bytes_per_image = bytes_per_row * minimum_rows_per_image;
643                    let bytes_in_upload =
644                        (bytes_per_image * (copy.size.depth - 1)) + minimum_bytes_per_image;
645                    let offset = copy.buffer_layout.offset as u32;
646
647                    let buffer_data;
648                    let unpack_data = match src.raw {
649                        Some(buffer) => {
650                            unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)) };
651                            unbind_unpack_buffer = true;
652                            glow::CompressedPixelUnpackData::BufferRange(
653                                offset..offset + bytes_in_upload,
654                            )
655                        }
656                        None => {
657                            buffer_data = src.data.as_ref().unwrap().lock().unwrap();
658                            let src_data = &buffer_data.as_slice()
659                                [(offset as usize)..(offset + bytes_in_upload) as usize];
660                            glow::CompressedPixelUnpackData::Slice(src_data)
661                        }
662                    };
663
664                    if is_layered_target(dst_target) {
665                        unsafe {
666                            gl.compressed_tex_sub_image_3d(
667                                dst_target,
668                                copy.texture_base.mip_level as i32,
669                                copy.texture_base.origin.x as i32,
670                                copy.texture_base.origin.y as i32,
671                                get_z_offset(dst_target, &copy.texture_base) as i32,
672                                copy.size.width as i32,
673                                copy.size.height as i32,
674                                copy.size.depth as i32,
675                                format_desc.internal,
676                                unpack_data,
677                            )
678                        };
679                    } else {
680                        unsafe {
681                            gl.compressed_tex_sub_image_2d(
682                                get_2d_target(dst_target, copy.texture_base.array_layer),
683                                copy.texture_base.mip_level as i32,
684                                copy.texture_base.origin.x as i32,
685                                copy.texture_base.origin.y as i32,
686                                copy.size.width as i32,
687                                copy.size.height as i32,
688                                format_desc.internal,
689                                unpack_data,
690                            )
691                        };
692                    }
693                }
694                if unbind_unpack_buffer {
695                    unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None) };
696                }
697            }
698            C::CopyTextureToBuffer {
699                src,
700                src_target,
701                src_format,
702                ref dst,
703                dst_target: _,
704                ref copy,
705            } => {
706                let block_size = src_format.block_size(None).unwrap();
707                if src_format.is_compressed() {
708                    log::error!("Not implemented yet: compressed texture copy to buffer");
709                    return;
710                }
711                if src_target == glow::TEXTURE_CUBE_MAP
712                    || src_target == glow::TEXTURE_CUBE_MAP_ARRAY
713                {
714                    log::error!("Not implemented yet: cubemap texture copy to buffer");
715                    return;
716                }
717                let format_desc = self.shared.describe_texture_format(src_format);
718                let row_texels = copy
719                    .buffer_layout
720                    .bytes_per_row
721                    .map_or(copy.size.width, |bpr| bpr / block_size);
722                let column_texels = copy
723                    .buffer_layout
724                    .rows_per_image
725                    .unwrap_or(copy.size.height);
726
727                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) };
728
729                let read_pixels = |offset| {
730                    let mut buffer_data;
731                    let unpack_data = match dst.raw {
732                        Some(buffer) => {
733                            unsafe { gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32) };
734                            unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(buffer)) };
735                            glow::PixelPackData::BufferOffset(offset as u32)
736                        }
737                        None => {
738                            buffer_data = dst.data.as_ref().unwrap().lock().unwrap();
739                            let dst_data = &mut buffer_data.as_mut_slice()[offset as usize..];
740                            glow::PixelPackData::Slice(dst_data)
741                        }
742                    };
743                    unsafe {
744                        gl.read_pixels(
745                            copy.texture_base.origin.x as i32,
746                            copy.texture_base.origin.y as i32,
747                            copy.size.width as i32,
748                            copy.size.height as i32,
749                            format_desc.external,
750                            format_desc.data_type,
751                            unpack_data,
752                        )
753                    };
754                };
755
756                match src_target {
757                    glow::TEXTURE_2D => {
758                        unsafe {
759                            gl.framebuffer_texture_2d(
760                                glow::READ_FRAMEBUFFER,
761                                glow::COLOR_ATTACHMENT0,
762                                src_target,
763                                Some(src),
764                                copy.texture_base.mip_level as i32,
765                            )
766                        };
767                        read_pixels(copy.buffer_layout.offset);
768                    }
769                    glow::TEXTURE_2D_ARRAY => {
770                        unsafe {
771                            gl.framebuffer_texture_layer(
772                                glow::READ_FRAMEBUFFER,
773                                glow::COLOR_ATTACHMENT0,
774                                Some(src),
775                                copy.texture_base.mip_level as i32,
776                                copy.texture_base.array_layer as i32,
777                            )
778                        };
779                        read_pixels(copy.buffer_layout.offset);
780                    }
781                    glow::TEXTURE_3D => {
782                        for z in copy.texture_base.origin.z..copy.size.depth {
783                            unsafe {
784                                gl.framebuffer_texture_layer(
785                                    glow::READ_FRAMEBUFFER,
786                                    glow::COLOR_ATTACHMENT0,
787                                    Some(src),
788                                    copy.texture_base.mip_level as i32,
789                                    z as i32,
790                                )
791                            };
792                            let offset = copy.buffer_layout.offset
793                                + (z * block_size * row_texels * column_texels) as u64;
794                            read_pixels(offset);
795                        }
796                    }
797                    glow::TEXTURE_CUBE_MAP | glow::TEXTURE_CUBE_MAP_ARRAY => unimplemented!(),
798                    _ => unreachable!(),
799                }
800            }
801            C::SetIndexBuffer(buffer) => {
802                unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)) };
803                self.current_index_buffer = Some(buffer);
804            }
805            C::BeginQuery(query, target) => {
806                unsafe { gl.begin_query(target, query) };
807            }
808            C::EndQuery(target) => {
809                unsafe { gl.end_query(target) };
810            }
811            C::TimestampQuery(query) => {
812                unsafe { gl.query_counter(query, glow::TIMESTAMP) };
813            }
814            C::CopyQueryResults {
815                ref query_range,
816                ref dst,
817                dst_target,
818                dst_offset,
819            } => {
820                if self
821                    .shared
822                    .private_caps
823                    .contains(PrivateCapabilities::QUERY_BUFFERS)
824                    && dst.raw.is_some()
825                {
826                    unsafe {
827                        // We're assuming that the only relevant queries are 8 byte timestamps or
828                        // occlusion tests.
829                        let query_size = 8;
830
831                        let query_range_size = query_size * query_range.len();
832
833                        let buffer = gl.create_buffer().ok();
834                        gl.bind_buffer(glow::QUERY_BUFFER, buffer);
835                        gl.buffer_data_size(
836                            glow::QUERY_BUFFER,
837                            query_range_size as _,
838                            glow::STREAM_COPY,
839                        );
840
841                        for (i, &query) in queries
842                            [query_range.start as usize..query_range.end as usize]
843                            .iter()
844                            .enumerate()
845                        {
846                            gl.get_query_parameter_u64_with_offset(
847                                query,
848                                glow::QUERY_RESULT,
849                                query_size * i,
850                            )
851                        }
852                        gl.bind_buffer(dst_target, dst.raw);
853                        gl.copy_buffer_sub_data(
854                            glow::QUERY_BUFFER,
855                            dst_target,
856                            0,
857                            dst_offset as _,
858                            query_range_size as _,
859                        );
860                        if let Some(buffer) = buffer {
861                            gl.delete_buffer(buffer)
862                        }
863                    }
864                } else {
865                    self.temp_query_results.clear();
866                    for &query in
867                        queries[query_range.start as usize..query_range.end as usize].iter()
868                    {
869                        let mut result: u64 = 0;
870                        unsafe {
871                            let result: *mut u64 = &mut result;
872                            gl.get_query_parameter_u64_with_offset(
873                                query,
874                                glow::QUERY_RESULT,
875                                result as usize,
876                            )
877                        };
878                        self.temp_query_results.push(result);
879                    }
880                    let query_data = unsafe {
881                        slice::from_raw_parts(
882                            self.temp_query_results.as_ptr() as *const u8,
883                            self.temp_query_results.len() * mem::size_of::<u64>(),
884                        )
885                    };
886                    match dst.raw {
887                        Some(buffer) => {
888                            unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
889                            unsafe {
890                                gl.buffer_sub_data_u8_slice(
891                                    dst_target,
892                                    dst_offset as i32,
893                                    query_data,
894                                )
895                            };
896                        }
897                        None => {
898                            let data = &mut dst.data.as_ref().unwrap().lock().unwrap();
899                            let len = query_data.len().min(data.len());
900                            data[..len].copy_from_slice(&query_data[..len]);
901                        }
902                    }
903                }
904            }
905            C::ResetFramebuffer { is_default } => {
906                if is_default {
907                    unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
908                } else {
909                    unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
910                    unsafe {
911                        gl.framebuffer_texture_2d(
912                            glow::DRAW_FRAMEBUFFER,
913                            glow::DEPTH_STENCIL_ATTACHMENT,
914                            glow::TEXTURE_2D,
915                            None,
916                            0,
917                        )
918                    };
919                    for i in 0..crate::MAX_COLOR_ATTACHMENTS {
920                        let target = glow::COLOR_ATTACHMENT0 + i as u32;
921                        unsafe {
922                            gl.framebuffer_texture_2d(
923                                glow::DRAW_FRAMEBUFFER,
924                                target,
925                                glow::TEXTURE_2D,
926                                None,
927                                0,
928                            )
929                        };
930                    }
931                }
932                unsafe { gl.color_mask(true, true, true, true) };
933                unsafe { gl.depth_mask(true) };
934                unsafe { gl.stencil_mask(!0) };
935                unsafe { gl.disable(glow::DEPTH_TEST) };
936                unsafe { gl.disable(glow::STENCIL_TEST) };
937                unsafe { gl.disable(glow::SCISSOR_TEST) };
938            }
939            C::BindAttachment {
940                attachment,
941                ref view,
942            } => {
943                unsafe { self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view) };
944            }
945            C::ResolveAttachment {
946                attachment,
947                ref dst,
948                ref size,
949            } => {
950                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)) };
951                unsafe { gl.read_buffer(attachment) };
952                unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
953                unsafe {
954                    self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, glow::COLOR_ATTACHMENT0, dst)
955                };
956                unsafe {
957                    gl.blit_framebuffer(
958                        0,
959                        0,
960                        size.width as i32,
961                        size.height as i32,
962                        0,
963                        0,
964                        size.width as i32,
965                        size.height as i32,
966                        glow::COLOR_BUFFER_BIT,
967                        glow::NEAREST,
968                    )
969                };
970                unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
971                unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)) };
972            }
973            C::InvalidateAttachments(ref list) => {
974                unsafe { gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list) };
975            }
976            C::SetDrawColorBuffers(count) => {
977                self.draw_buffer_count = count;
978                let indices = (0..count as u32)
979                    .map(|i| glow::COLOR_ATTACHMENT0 + i)
980                    .collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>();
981                unsafe { gl.draw_buffers(&indices) };
982            }
983            C::ClearColorF {
984                draw_buffer,
985                ref color,
986                is_srgb,
987            } => {
988                if self
989                    .shared
990                    .workarounds
991                    .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
992                    && is_srgb
993                {
994                    unsafe { self.perform_shader_clear(gl, draw_buffer, *color) };
995                } else {
996                    unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) };
997                }
998            }
999            C::ClearColorU(draw_buffer, ref color) => {
1000                unsafe { gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, color) };
1001            }
1002            C::ClearColorI(draw_buffer, ref color) => {
1003                unsafe { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color) };
1004            }
1005            C::ClearDepth(depth) => {
1006                unsafe { gl.clear_buffer_f32_slice(glow::DEPTH, 0, &[depth]) };
1007            }
1008            C::ClearStencil(value) => {
1009                unsafe { gl.clear_buffer_i32_slice(glow::STENCIL, 0, &[value as i32]) };
1010            }
1011            C::ClearDepthAndStencil(depth, stencil_value) => {
1012                unsafe {
1013                    gl.clear_buffer_depth_stencil(
1014                        glow::DEPTH_STENCIL,
1015                        0,
1016                        depth,
1017                        stencil_value as i32,
1018                    )
1019                };
1020            }
1021            C::BufferBarrier(raw, usage) => {
1022                let mut flags = 0;
1023                if usage.contains(crate::BufferUses::VERTEX) {
1024                    flags |= glow::VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1025                    unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, Some(raw)) };
1026                    unsafe { gl.vertex_attrib_pointer_f32(0, 1, glow::BYTE, true, 0, 0) };
1027                }
1028                if usage.contains(crate::BufferUses::INDEX) {
1029                    flags |= glow::ELEMENT_ARRAY_BARRIER_BIT;
1030                    unsafe { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(raw)) };
1031                }
1032                if usage.contains(crate::BufferUses::UNIFORM) {
1033                    flags |= glow::UNIFORM_BARRIER_BIT;
1034                }
1035                if usage.contains(crate::BufferUses::INDIRECT) {
1036                    flags |= glow::COMMAND_BARRIER_BIT;
1037                    unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(raw)) };
1038                }
1039                if usage.contains(crate::BufferUses::COPY_SRC) {
1040                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1041                    unsafe { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(raw)) };
1042                }
1043                if usage.contains(crate::BufferUses::COPY_DST) {
1044                    flags |= glow::PIXEL_BUFFER_BARRIER_BIT;
1045                    unsafe { gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(raw)) };
1046                }
1047                if usage.intersects(crate::BufferUses::MAP_READ | crate::BufferUses::MAP_WRITE) {
1048                    flags |= glow::BUFFER_UPDATE_BARRIER_BIT;
1049                }
1050                if usage.intersects(
1051                    crate::BufferUses::STORAGE_READ | crate::BufferUses::STORAGE_READ_WRITE,
1052                ) {
1053                    flags |= glow::SHADER_STORAGE_BARRIER_BIT;
1054                }
1055                unsafe { gl.memory_barrier(flags) };
1056            }
1057            C::TextureBarrier(usage) => {
1058                let mut flags = 0;
1059                if usage.contains(crate::TextureUses::RESOURCE) {
1060                    flags |= glow::TEXTURE_FETCH_BARRIER_BIT;
1061                }
1062                if usage.intersects(
1063                    crate::TextureUses::STORAGE_READ | crate::TextureUses::STORAGE_READ_WRITE,
1064                ) {
1065                    flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT;
1066                }
1067                if usage.contains(crate::TextureUses::COPY_DST) {
1068                    flags |= glow::TEXTURE_UPDATE_BARRIER_BIT;
1069                }
1070                if usage.intersects(
1071                    crate::TextureUses::COLOR_TARGET
1072                        | crate::TextureUses::DEPTH_STENCIL_READ
1073                        | crate::TextureUses::DEPTH_STENCIL_WRITE,
1074                ) {
1075                    flags |= glow::FRAMEBUFFER_BARRIER_BIT;
1076                }
1077                unsafe { gl.memory_barrier(flags) };
1078            }
1079            C::SetViewport {
1080                ref rect,
1081                ref depth,
1082            } => {
1083                unsafe { gl.viewport(rect.x, rect.y, rect.w, rect.h) };
1084                unsafe { gl.depth_range_f32(depth.start, depth.end) };
1085            }
1086            C::SetScissor(ref rect) => {
1087                unsafe { gl.scissor(rect.x, rect.y, rect.w, rect.h) };
1088                unsafe { gl.enable(glow::SCISSOR_TEST) };
1089            }
1090            C::SetStencilFunc {
1091                face,
1092                function,
1093                reference,
1094                read_mask,
1095            } => {
1096                unsafe { gl.stencil_func_separate(face, function, reference as i32, read_mask) };
1097            }
1098            C::SetStencilOps {
1099                face,
1100                write_mask,
1101                ref ops,
1102            } => {
1103                unsafe { gl.stencil_mask_separate(face, write_mask) };
1104                unsafe { gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass) };
1105            }
1106            C::SetVertexAttribute {
1107                buffer,
1108                ref buffer_desc,
1109                attribute_desc: ref vat,
1110            } => {
1111                unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, buffer) };
1112                unsafe { gl.enable_vertex_attrib_array(vat.location) };
1113
1114                if buffer.is_none() {
1115                    match vat.format_desc.attrib_kind {
1116                        super::VertexAttribKind::Float => unsafe {
1117                            gl.vertex_attrib_format_f32(
1118                                vat.location,
1119                                vat.format_desc.element_count,
1120                                vat.format_desc.element_format,
1121                                true, // always normalized
1122                                vat.offset,
1123                            )
1124                        },
1125                        super::VertexAttribKind::Integer => unsafe {
1126                            gl.vertex_attrib_format_i32(
1127                                vat.location,
1128                                vat.format_desc.element_count,
1129                                vat.format_desc.element_format,
1130                                vat.offset,
1131                            )
1132                        },
1133                    }
1134
1135                    //Note: there is apparently a bug on AMD 3500U:
1136                    // this call is ignored if the current array is disabled.
1137                    unsafe { gl.vertex_attrib_binding(vat.location, vat.buffer_index) };
1138                } else {
1139                    match vat.format_desc.attrib_kind {
1140                        super::VertexAttribKind::Float => unsafe {
1141                            gl.vertex_attrib_pointer_f32(
1142                                vat.location,
1143                                vat.format_desc.element_count,
1144                                vat.format_desc.element_format,
1145                                true, // always normalized
1146                                buffer_desc.stride as i32,
1147                                vat.offset as i32,
1148                            )
1149                        },
1150                        super::VertexAttribKind::Integer => unsafe {
1151                            gl.vertex_attrib_pointer_i32(
1152                                vat.location,
1153                                vat.format_desc.element_count,
1154                                vat.format_desc.element_format,
1155                                buffer_desc.stride as i32,
1156                                vat.offset as i32,
1157                            )
1158                        },
1159                    }
1160                    unsafe { gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32) };
1161                }
1162            }
1163            C::UnsetVertexAttribute(location) => {
1164                unsafe { gl.disable_vertex_attrib_array(location) };
1165            }
1166            C::SetVertexBuffer {
1167                index,
1168                ref buffer,
1169                ref buffer_desc,
1170            } => {
1171                unsafe { gl.vertex_binding_divisor(index, buffer_desc.step as u32) };
1172                unsafe {
1173                    gl.bind_vertex_buffer(
1174                        index,
1175                        Some(buffer.raw),
1176                        buffer.offset as i32,
1177                        buffer_desc.stride as i32,
1178                    )
1179                };
1180            }
1181            C::SetDepth(ref depth) => {
1182                unsafe { gl.depth_func(depth.function) };
1183                unsafe { gl.depth_mask(depth.mask) };
1184            }
1185            C::SetDepthBias(bias) => {
1186                if bias.is_enabled() {
1187                    unsafe { gl.enable(glow::POLYGON_OFFSET_FILL) };
1188                    unsafe { gl.polygon_offset(bias.slope_scale, bias.constant as f32) };
1189                } else {
1190                    unsafe { gl.disable(glow::POLYGON_OFFSET_FILL) };
1191                }
1192            }
1193            C::ConfigureDepthStencil(aspects) => {
1194                if aspects.contains(crate::FormatAspects::DEPTH) {
1195                    unsafe { gl.enable(glow::DEPTH_TEST) };
1196                } else {
1197                    unsafe { gl.disable(glow::DEPTH_TEST) };
1198                }
1199                if aspects.contains(crate::FormatAspects::STENCIL) {
1200                    unsafe { gl.enable(glow::STENCIL_TEST) };
1201                } else {
1202                    unsafe { gl.disable(glow::STENCIL_TEST) };
1203                }
1204            }
1205            C::SetAlphaToCoverage(enabled) => {
1206                if enabled {
1207                    unsafe { gl.enable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1208                } else {
1209                    unsafe { gl.disable(glow::SAMPLE_ALPHA_TO_COVERAGE) };
1210                }
1211            }
1212            C::SetProgram(program) => {
1213                unsafe { gl.use_program(Some(program)) };
1214            }
1215            C::SetPrimitive(ref state) => {
1216                unsafe { gl.front_face(state.front_face) };
1217                if state.cull_face != 0 {
1218                    unsafe { gl.enable(glow::CULL_FACE) };
1219                    unsafe { gl.cull_face(state.cull_face) };
1220                } else {
1221                    unsafe { gl.disable(glow::CULL_FACE) };
1222                }
1223                if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
1224                    //Note: this is a bit tricky, since we are controlling the clip, not the clamp.
1225                    if state.unclipped_depth {
1226                        unsafe { gl.enable(glow::DEPTH_CLAMP) };
1227                    } else {
1228                        unsafe { gl.disable(glow::DEPTH_CLAMP) };
1229                    }
1230                }
1231            }
1232            C::SetBlendConstant(c) => {
1233                unsafe { gl.blend_color(c[0], c[1], c[2], c[3]) };
1234            }
1235            C::SetColorTarget {
1236                draw_buffer_index,
1237                desc: super::ColorTargetDesc { mask, ref blend },
1238            } => {
1239                use wgt::ColorWrites as Cw;
1240                if let Some(index) = draw_buffer_index {
1241                    unsafe {
1242                        gl.color_mask_draw_buffer(
1243                            index,
1244                            mask.contains(Cw::RED),
1245                            mask.contains(Cw::GREEN),
1246                            mask.contains(Cw::BLUE),
1247                            mask.contains(Cw::ALPHA),
1248                        )
1249                    };
1250                    if let Some(ref blend) = *blend {
1251                        unsafe { gl.enable_draw_buffer(glow::BLEND, index) };
1252                        if blend.color != blend.alpha {
1253                            unsafe {
1254                                gl.blend_equation_separate_draw_buffer(
1255                                    index,
1256                                    blend.color.equation,
1257                                    blend.alpha.equation,
1258                                )
1259                            };
1260                            unsafe {
1261                                gl.blend_func_separate_draw_buffer(
1262                                    index,
1263                                    blend.color.src,
1264                                    blend.color.dst,
1265                                    blend.alpha.src,
1266                                    blend.alpha.dst,
1267                                )
1268                            };
1269                        } else {
1270                            unsafe { gl.blend_equation_draw_buffer(index, blend.color.equation) };
1271                            unsafe {
1272                                gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst)
1273                            };
1274                        }
1275                    } else {
1276                        unsafe { gl.disable_draw_buffer(glow::BLEND, index) };
1277                    }
1278                } else {
1279                    unsafe {
1280                        gl.color_mask(
1281                            mask.contains(Cw::RED),
1282                            mask.contains(Cw::GREEN),
1283                            mask.contains(Cw::BLUE),
1284                            mask.contains(Cw::ALPHA),
1285                        )
1286                    };
1287                    if let Some(ref blend) = *blend {
1288                        unsafe { gl.enable(glow::BLEND) };
1289                        if blend.color != blend.alpha {
1290                            unsafe {
1291                                gl.blend_equation_separate(
1292                                    blend.color.equation,
1293                                    blend.alpha.equation,
1294                                )
1295                            };
1296                            unsafe {
1297                                gl.blend_func_separate(
1298                                    blend.color.src,
1299                                    blend.color.dst,
1300                                    blend.alpha.src,
1301                                    blend.alpha.dst,
1302                                )
1303                            };
1304                        } else {
1305                            unsafe { gl.blend_equation(blend.color.equation) };
1306                            unsafe { gl.blend_func(blend.color.src, blend.color.dst) };
1307                        }
1308                    } else {
1309                        unsafe { gl.disable(glow::BLEND) };
1310                    }
1311                }
1312            }
1313            C::BindBuffer {
1314                target,
1315                slot,
1316                buffer,
1317                offset,
1318                size,
1319            } => {
1320                unsafe { gl.bind_buffer_range(target, slot, Some(buffer), offset, size) };
1321            }
1322            C::BindSampler(texture_index, sampler) => {
1323                unsafe { gl.bind_sampler(texture_index, sampler) };
1324            }
1325            C::BindTexture {
1326                slot,
1327                texture,
1328                target,
1329                aspects,
1330            } => {
1331                unsafe { gl.active_texture(glow::TEXTURE0 + slot) };
1332                unsafe { gl.bind_texture(target, Some(texture)) };
1333
1334                let version = gl.version();
1335                let is_min_es_3_1 = version.is_embedded && (version.major, version.minor) >= (3, 1);
1336                let is_min_4_3 = !version.is_embedded && (version.major, version.minor) >= (4, 3);
1337                if is_min_es_3_1 || is_min_4_3 {
1338                    let mode = match aspects {
1339                        crate::FormatAspects::DEPTH => Some(glow::DEPTH_COMPONENT),
1340                        crate::FormatAspects::STENCIL => Some(glow::STENCIL_INDEX),
1341                        _ => None,
1342                    };
1343                    if let Some(mode) = mode {
1344                        unsafe {
1345                            gl.tex_parameter_i32(
1346                                target,
1347                                glow::DEPTH_STENCIL_TEXTURE_MODE,
1348                                mode as _,
1349                            )
1350                        };
1351                    }
1352                }
1353            }
1354            C::BindImage { slot, ref binding } => {
1355                unsafe {
1356                    gl.bind_image_texture(
1357                        slot,
1358                        binding.raw,
1359                        binding.mip_level as i32,
1360                        binding.array_layer.is_none(),
1361                        binding.array_layer.unwrap_or_default() as i32,
1362                        binding.access,
1363                        binding.format,
1364                    )
1365                };
1366            }
1367            #[cfg(not(target_arch = "wasm32"))]
1368            C::InsertDebugMarker(ref range) => {
1369                let marker = extract_marker(data_bytes, range);
1370                unsafe {
1371                    gl.debug_message_insert(
1372                        glow::DEBUG_SOURCE_APPLICATION,
1373                        glow::DEBUG_TYPE_MARKER,
1374                        DEBUG_ID,
1375                        glow::DEBUG_SEVERITY_NOTIFICATION,
1376                        marker,
1377                    )
1378                };
1379            }
1380            #[cfg(target_arch = "wasm32")]
1381            C::InsertDebugMarker(_) => (),
1382            #[cfg_attr(target_arch = "wasm32", allow(unused))]
1383            C::PushDebugGroup(ref range) => {
1384                #[cfg(not(target_arch = "wasm32"))]
1385                let marker = extract_marker(data_bytes, range);
1386                #[cfg(not(target_arch = "wasm32"))]
1387                unsafe {
1388                    gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker)
1389                };
1390            }
1391            C::PopDebugGroup => {
1392                #[cfg(not(target_arch = "wasm32"))]
1393                unsafe {
1394                    gl.pop_debug_group()
1395                };
1396            }
1397            C::SetPushConstants {
1398                ref uniform,
1399                offset,
1400            } => {
1401                fn get_data<T>(data: &[u8], offset: u32) -> &[T] {
1402                    let raw = &data[(offset as usize)..];
1403                    unsafe {
1404                        slice::from_raw_parts(
1405                            raw.as_ptr() as *const _,
1406                            raw.len() / mem::size_of::<T>(),
1407                        )
1408                    }
1409                }
1410
1411                let location = uniform.location.as_ref();
1412
1413                match uniform.utype {
1414                    glow::FLOAT => {
1415                        let data = get_data::<f32>(data_bytes, offset)[0];
1416                        unsafe { gl.uniform_1_f32(location, data) };
1417                    }
1418                    glow::FLOAT_VEC2 => {
1419                        let data = get_data::<[f32; 2]>(data_bytes, offset)[0];
1420                        unsafe { gl.uniform_2_f32_slice(location, &data) };
1421                    }
1422                    glow::FLOAT_VEC3 => {
1423                        let data = get_data::<[f32; 3]>(data_bytes, offset)[0];
1424                        unsafe { gl.uniform_3_f32_slice(location, &data) };
1425                    }
1426                    glow::FLOAT_VEC4 => {
1427                        let data = get_data::<[f32; 4]>(data_bytes, offset)[0];
1428                        unsafe { gl.uniform_4_f32_slice(location, &data) };
1429                    }
1430                    glow::INT => {
1431                        let data = get_data::<i32>(data_bytes, offset)[0];
1432                        unsafe { gl.uniform_1_i32(location, data) };
1433                    }
1434                    glow::INT_VEC2 => {
1435                        let data = get_data::<[i32; 2]>(data_bytes, offset)[0];
1436                        unsafe { gl.uniform_2_i32_slice(location, &data) };
1437                    }
1438                    glow::INT_VEC3 => {
1439                        let data = get_data::<[i32; 3]>(data_bytes, offset)[0];
1440                        unsafe { gl.uniform_3_i32_slice(location, &data) };
1441                    }
1442                    glow::INT_VEC4 => {
1443                        let data = get_data::<[i32; 4]>(data_bytes, offset)[0];
1444                        unsafe { gl.uniform_4_i32_slice(location, &data) };
1445                    }
1446                    glow::FLOAT_MAT2 => {
1447                        let data = get_data::<[f32; 4]>(data_bytes, offset)[0];
1448                        unsafe { gl.uniform_matrix_2_f32_slice(location, false, &data) };
1449                    }
1450                    glow::FLOAT_MAT3 => {
1451                        let data = get_data::<[f32; 9]>(data_bytes, offset)[0];
1452                        unsafe { gl.uniform_matrix_3_f32_slice(location, false, &data) };
1453                    }
1454                    glow::FLOAT_MAT4 => {
1455                        let data = get_data::<[f32; 16]>(data_bytes, offset)[0];
1456                        unsafe { gl.uniform_matrix_4_f32_slice(location, false, &data) };
1457                    }
1458                    _ => panic!("Unsupported uniform datatype!"),
1459                }
1460            }
1461        }
1462    }
1463}
1464
1465impl crate::Queue<super::Api> for super::Queue {
1466    unsafe fn submit(
1467        &mut self,
1468        command_buffers: &[&super::CommandBuffer],
1469        signal_fence: Option<(&mut super::Fence, crate::FenceValue)>,
1470    ) -> Result<(), crate::DeviceError> {
1471        let shared = Arc::clone(&self.shared);
1472        let gl = &shared.context.lock();
1473        for cmd_buf in command_buffers.iter() {
1474            // The command encoder assumes a default state when encoding the command buffer.
1475            // Always reset the state between command_buffers to reflect this assumption. Do
1476            // this at the beginning of the loop in case something outside of wgpu modified
1477            // this state prior to commit.
1478            unsafe { self.reset_state(gl) };
1479            #[cfg(not(target_arch = "wasm32"))]
1480            if let Some(ref label) = cmd_buf.label {
1481                unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) };
1482            }
1483
1484            for command in cmd_buf.commands.iter() {
1485                unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
1486            }
1487
1488            #[cfg(not(target_arch = "wasm32"))]
1489            if cmd_buf.label.is_some() {
1490                unsafe { gl.pop_debug_group() };
1491            }
1492        }
1493
1494        if let Some((fence, value)) = signal_fence {
1495            fence.maintain(gl);
1496            let sync = unsafe { gl.fence_sync(glow::SYNC_GPU_COMMANDS_COMPLETE, 0) }
1497                .map_err(|_| crate::DeviceError::OutOfMemory)?;
1498            fence.pending.push((value, sync));
1499        }
1500
1501        Ok(())
1502    }
1503
1504    unsafe fn present(
1505        &mut self,
1506        surface: &mut super::Surface,
1507        texture: super::Texture,
1508    ) -> Result<(), crate::SurfaceError> {
1509        unsafe { surface.present(texture, &self.shared.context) }
1510    }
1511
1512    unsafe fn get_timestamp_period(&self) -> f32 {
1513        1.0
1514    }
1515}
1516
1517#[cfg(all(
1518    target_arch = "wasm32",
1519    feature = "fragile-send-sync-non-atomic-wasm",
1520    not(target_feature = "atomics")
1521))]
1522unsafe impl Sync for super::Queue {}
1523#[cfg(all(
1524    target_arch = "wasm32",
1525    feature = "fragile-send-sync-non-atomic-wasm",
1526    not(target_feature = "atomics")
1527))]
1528unsafe impl Send for super::Queue {}