wgpu_hal/gles/
mod.rs

1/*!
2# OpenGL ES3 API (aka GLES3).
3
4Designed to work on Linux and Android, with context provided by EGL.
5
6## Texture views
7
8GLES3 doesn't really have separate texture view objects. We have to remember the
9original texture and the sub-range into it. Problem is, however, that there is
10no way to expose a subset of array layers or mip levels of a sampled texture.
11
12## Binding model
13
14Binding model is very different from WebGPU, especially with regards to samplers.
15GLES3 has sampler objects, but they aren't separately bindable to the shaders.
16Each sampled texture is exposed to the shader as a combined texture-sampler binding.
17
18When building the pipeline layout, we linearize binding entries based on the groups
19(uniform/storage buffers, uniform/storage textures), and record the mapping into
20`BindGroupLayoutInfo`.
21When a pipeline gets created, and we track all the texture-sampler associations
22from the static use in the shader.
23We only support at most one sampler used with each texture so far. The linear index
24of this sampler is stored per texture slot in `SamplerBindMap` array.
25
26The texture-sampler pairs get potentially invalidated in 2 places:
27  - when a new pipeline is set, we update the linear indices of associated samplers
28  - when a new bind group is set, we update both the textures and the samplers
29
30We expect that the changes to sampler states between any 2 pipelines of the same layout
31will be minimal, if any.
32
33## Vertex data
34
35Generally, vertex buffers are marked as dirty and lazily bound on draw.
36
37GLES3 doesn't support `first_instance` semantics. However, it's easy to support,
38since we are forced to do late binding anyway. We just adjust the offsets
39into the vertex data.
40
41### Old path
42
43In GLES-3.0 and WebGL2, vertex buffer layout is provided
44together with the actual buffer binding.
45We invalidate the attributes on the vertex buffer change, and re-bind them.
46
47### New path
48
49In GLES-3.1 and higher, the vertex buffer layout can be declared separately
50from the vertex data itself. This mostly matches WebGPU, however there is a catch:
51`stride` needs to be specified with the data, not as a part of the layout.
52
53To address this, we invalidate the vertex buffers based on:
54  - whether or not `first_instance` is used
55  - stride has changed
56
57## Handling of `base_vertex`, `first_instance`, and `first_vertex`
58
59Between indirect, the lack of `first_instance` semantics, and the availability of `gl_BaseInstance`
60in shaders, getting buffers and builtins to work correctly is a bit tricky.
61
62We never emulate `base_vertex` and gl_VertexID behaves as `@builtin(vertex_index)` does, so we
63never need to do anything about that.
64
65We always advertise support for `VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW`.
66
67### GL 4.2+ with ARB_shader_draw_parameters
68
69- `@builtin(instance_index)` translates to `gl_InstanceID + gl_BaseInstance`
70- We bind instance buffers without any offset emulation.
71- We advertise support for the `INDIRECT_FIRST_INSTANCE` feature.
72
73While we can theoretically have a card with 4.2+ support but without ARB_shader_draw_parameters,
74we don't bother with that combination.
75
76### GLES & GL 4.1
77
78- `@builtin(instance_index)` translates to `gl_InstanceID + naga_vs_first_instance`
79- We bind instance buffers with offset emulation.
80- We _do not_ advertise support for `INDIRECT_FIRST_INSTANCE` and cpu-side pretend the `first_instance` is 0 on indirect calls.
81
82*/
83
84///cbindgen:ignore
85#[cfg(not(any(windows, webgl)))]
86mod egl;
87#[cfg(Emscripten)]
88mod emscripten;
89#[cfg(webgl)]
90mod web;
91#[cfg(windows)]
92mod wgl;
93
94mod adapter;
95mod command;
96mod conv;
97mod device;
98mod fence;
99mod queue;
100
101pub use fence::Fence;
102
103#[cfg(not(any(windows, webgl)))]
104pub use self::egl::{AdapterContext, AdapterContextLock};
105#[cfg(not(any(windows, webgl)))]
106use self::egl::{Instance, Surface};
107
108#[cfg(webgl)]
109pub use self::web::AdapterContext;
110#[cfg(webgl)]
111use self::web::{Instance, Surface};
112
113#[cfg(windows)]
114use self::wgl::AdapterContext;
115#[cfg(windows)]
116use self::wgl::{Instance, Surface};
117
118use alloc::{boxed::Box, string::String, string::ToString as _, sync::Arc, vec::Vec};
119use core::{
120    fmt,
121    ops::Range,
122    sync::atomic::{AtomicU32, AtomicU8},
123};
124use parking_lot::Mutex;
125
126use arrayvec::ArrayVec;
127use glow::HasContext;
128use naga::FastHashMap;
129
130use crate::{CopyExtent, TextureDescriptor};
131
132#[derive(Clone, Debug)]
133pub struct Api;
134
135//Note: we can support more samplers if not every one of them is used at a time,
136// but it probably doesn't worth it.
137const MAX_TEXTURE_SLOTS: usize = 16;
138const MAX_SAMPLERS: usize = 16;
139const MAX_VERTEX_ATTRIBUTES: usize = 16;
140const ZERO_BUFFER_SIZE: usize = 256 << 10;
141const MAX_PUSH_CONSTANTS: usize = 64;
142// We have to account for each push constant may need to be set for every shader.
143const MAX_PUSH_CONSTANT_COMMANDS: usize = MAX_PUSH_CONSTANTS * crate::MAX_CONCURRENT_SHADER_STAGES;
144
145impl crate::Api for Api {
146    type Instance = Instance;
147    type Surface = Surface;
148    type Adapter = Adapter;
149    type Device = Device;
150
151    type Queue = Queue;
152    type CommandEncoder = CommandEncoder;
153    type CommandBuffer = CommandBuffer;
154
155    type Buffer = Buffer;
156    type Texture = Texture;
157    type SurfaceTexture = Texture;
158    type TextureView = TextureView;
159    type Sampler = Sampler;
160    type QuerySet = QuerySet;
161    type Fence = Fence;
162    type AccelerationStructure = AccelerationStructure;
163    type PipelineCache = PipelineCache;
164
165    type BindGroupLayout = BindGroupLayout;
166    type BindGroup = BindGroup;
167    type PipelineLayout = PipelineLayout;
168    type ShaderModule = ShaderModule;
169    type RenderPipeline = RenderPipeline;
170    type ComputePipeline = ComputePipeline;
171}
172
173crate::impl_dyn_resource!(
174    Adapter,
175    AccelerationStructure,
176    BindGroup,
177    BindGroupLayout,
178    Buffer,
179    CommandBuffer,
180    CommandEncoder,
181    ComputePipeline,
182    Device,
183    Fence,
184    Instance,
185    PipelineCache,
186    PipelineLayout,
187    QuerySet,
188    Queue,
189    RenderPipeline,
190    Sampler,
191    ShaderModule,
192    Surface,
193    Texture,
194    TextureView
195);
196
197bitflags::bitflags! {
198    /// Flags that affect internal code paths but do not
199    /// change the exposed feature set.
200    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
201    struct PrivateCapabilities: u32 {
202        /// Indicates support for `glBufferStorage` allocation.
203        const BUFFER_ALLOCATION = 1 << 0;
204        /// Support explicit layouts in shader.
205        const SHADER_BINDING_LAYOUT = 1 << 1;
206        /// Support extended shadow sampling instructions.
207        const SHADER_TEXTURE_SHADOW_LOD = 1 << 2;
208        /// Support memory barriers.
209        const MEMORY_BARRIERS = 1 << 3;
210        /// Vertex buffer layouts separate from the data.
211        const VERTEX_BUFFER_LAYOUT = 1 << 4;
212        /// Indicates that buffers used as `GL_ELEMENT_ARRAY_BUFFER` may be created / initialized / used
213        /// as other targets, if not present they must not be mixed with other targets.
214        const INDEX_BUFFER_ROLE_CHANGE = 1 << 5;
215        /// Supports `glGetBufferSubData`
216        const GET_BUFFER_SUB_DATA = 1 << 7;
217        /// Supports `f16` color buffers
218        const COLOR_BUFFER_HALF_FLOAT = 1 << 8;
219        /// Supports `f11/f10` and `f32` color buffers
220        const COLOR_BUFFER_FLOAT = 1 << 9;
221        /// Supports query buffer objects.
222        const QUERY_BUFFERS = 1 << 11;
223        /// Supports 64 bit queries via `glGetQueryObjectui64v`
224        const QUERY_64BIT = 1 << 12;
225        /// Supports `glTexStorage2D`, etc.
226        const TEXTURE_STORAGE = 1 << 13;
227        /// Supports `push_debug_group`, `pop_debug_group` and `debug_message_insert`.
228        const DEBUG_FNS = 1 << 14;
229        /// Supports framebuffer invalidation.
230        const INVALIDATE_FRAMEBUFFER = 1 << 15;
231        /// Indicates support for `glDrawElementsInstancedBaseVertexBaseInstance` and `ARB_shader_draw_parameters`
232        ///
233        /// When this is true, instance offset emulation via vertex buffer rebinding and a shader uniform will be disabled.
234        const FULLY_FEATURED_INSTANCING = 1 << 16;
235    }
236}
237
238bitflags::bitflags! {
239    /// Flags that indicate necessary workarounds for specific devices or driver bugs
240    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
241    struct Workarounds: u32 {
242        // Needs workaround for Intel Mesa bug:
243        // https://gitlab.freedesktop.org/mesa/mesa/-/issues/2565.
244        //
245        // This comment
246        // (https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4972/diffs?diff_id=75888#22f5d1004713c9bbf857988c7efb81631ab88f99_323_327)
247        // seems to indicate all skylake models are effected.
248        const MESA_I915_SRGB_SHADER_CLEAR = 1 << 0;
249        /// Buffer map must emulated because it is not supported natively
250        const EMULATE_BUFFER_MAP = 1 << 1;
251    }
252}
253
254type BindTarget = u32;
255
256#[derive(Debug, Clone, Copy)]
257enum VertexAttribKind {
258    Float, // glVertexAttribPointer
259    Integer, // glVertexAttribIPointer
260           //Double,  // glVertexAttribLPointer
261}
262
263impl Default for VertexAttribKind {
264    fn default() -> Self {
265        Self::Float
266    }
267}
268
269#[derive(Clone, Debug)]
270pub struct TextureFormatDesc {
271    pub internal: u32,
272    pub external: u32,
273    pub data_type: u32,
274}
275
276struct AdapterShared {
277    context: AdapterContext,
278    private_caps: PrivateCapabilities,
279    features: wgt::Features,
280    limits: wgt::Limits,
281    workarounds: Workarounds,
282    options: wgt::GlBackendOptions,
283    shading_language_version: naga::back::glsl::Version,
284    next_shader_id: AtomicU32,
285    program_cache: Mutex<ProgramCache>,
286    es: bool,
287
288    /// Result of `gl.get_parameter_i32(glow::MAX_SAMPLES)`.
289    /// Cached here so it doesn't need to be queried every time texture format capabilities are requested.
290    /// (this has been shown to be a significant enough overhead)
291    max_msaa_samples: i32,
292}
293
294pub struct Adapter {
295    shared: Arc<AdapterShared>,
296}
297
298pub struct Device {
299    shared: Arc<AdapterShared>,
300    main_vao: glow::VertexArray,
301    #[cfg(all(native, feature = "renderdoc"))]
302    render_doc: crate::auxil::renderdoc::RenderDoc,
303    counters: Arc<wgt::HalCounters>,
304}
305
306impl Drop for Device {
307    fn drop(&mut self) {
308        let gl = &self.shared.context.lock();
309        unsafe { gl.delete_vertex_array(self.main_vao) };
310    }
311}
312
313pub struct ShaderClearProgram {
314    pub program: glow::Program,
315    pub color_uniform_location: glow::UniformLocation,
316}
317
318pub struct Queue {
319    shared: Arc<AdapterShared>,
320    features: wgt::Features,
321    draw_fbo: glow::Framebuffer,
322    copy_fbo: glow::Framebuffer,
323    /// Shader program used to clear the screen for [`Workarounds::MESA_I915_SRGB_SHADER_CLEAR`]
324    /// devices.
325    shader_clear_program: Option<ShaderClearProgram>,
326    /// Keep a reasonably large buffer filled with zeroes, so that we can implement `ClearBuffer` of
327    /// zeroes by copying from it.
328    zero_buffer: glow::Buffer,
329    temp_query_results: Mutex<Vec<u64>>,
330    draw_buffer_count: AtomicU8,
331    current_index_buffer: Mutex<Option<glow::Buffer>>,
332}
333
334impl Drop for Queue {
335    fn drop(&mut self) {
336        let gl = &self.shared.context.lock();
337        unsafe { gl.delete_framebuffer(self.draw_fbo) };
338        unsafe { gl.delete_framebuffer(self.copy_fbo) };
339        unsafe { gl.delete_buffer(self.zero_buffer) };
340    }
341}
342
343#[derive(Clone, Debug)]
344pub struct Buffer {
345    raw: Option<glow::Buffer>,
346    target: BindTarget,
347    size: wgt::BufferAddress,
348    map_flags: u32,
349    data: Option<Arc<MaybeMutex<Vec<u8>>>>,
350    offset_of_current_mapping: Arc<MaybeMutex<wgt::BufferAddress>>,
351}
352
353#[cfg(send_sync)]
354unsafe impl Sync for Buffer {}
355#[cfg(send_sync)]
356unsafe impl Send for Buffer {}
357
358impl crate::DynBuffer for Buffer {}
359
360#[derive(Clone, Debug)]
361pub enum TextureInner {
362    Renderbuffer {
363        raw: glow::Renderbuffer,
364    },
365    DefaultRenderbuffer,
366    Texture {
367        raw: glow::Texture,
368        target: BindTarget,
369    },
370    #[cfg(webgl)]
371    ExternalFramebuffer {
372        inner: web_sys::WebGlFramebuffer,
373    },
374}
375
376#[cfg(send_sync)]
377unsafe impl Sync for TextureInner {}
378#[cfg(send_sync)]
379unsafe impl Send for TextureInner {}
380
381impl TextureInner {
382    fn as_native(&self) -> (glow::Texture, BindTarget) {
383        match *self {
384            Self::Renderbuffer { .. } | Self::DefaultRenderbuffer => {
385                panic!("Unexpected renderbuffer");
386            }
387            Self::Texture { raw, target } => (raw, target),
388            #[cfg(webgl)]
389            Self::ExternalFramebuffer { .. } => panic!("Unexpected external framebuffer"),
390        }
391    }
392}
393
394#[derive(Debug)]
395pub struct Texture {
396    pub inner: TextureInner,
397    pub drop_guard: Option<crate::DropGuard>,
398    pub mip_level_count: u32,
399    pub array_layer_count: u32,
400    pub format: wgt::TextureFormat,
401    #[allow(unused)]
402    pub format_desc: TextureFormatDesc,
403    pub copy_size: CopyExtent,
404}
405
406impl crate::DynTexture for Texture {}
407impl crate::DynSurfaceTexture for Texture {}
408
409impl core::borrow::Borrow<dyn crate::DynTexture> for Texture {
410    fn borrow(&self) -> &dyn crate::DynTexture {
411        self
412    }
413}
414
415impl Texture {
416    pub fn default_framebuffer(format: wgt::TextureFormat) -> Self {
417        Self {
418            inner: TextureInner::DefaultRenderbuffer,
419            drop_guard: None,
420            mip_level_count: 1,
421            array_layer_count: 1,
422            format,
423            format_desc: TextureFormatDesc {
424                internal: 0,
425                external: 0,
426                data_type: 0,
427            },
428            copy_size: CopyExtent {
429                width: 0,
430                height: 0,
431                depth: 0,
432            },
433        }
434    }
435
436    /// Returns the `target`, whether the image is 3d and whether the image is a cubemap.
437    fn get_info_from_desc(desc: &TextureDescriptor) -> u32 {
438        match desc.dimension {
439            // WebGL (1 and 2) as well as some GLES versions do not have 1D textures, so we are
440            // doing `TEXTURE_2D` instead
441            wgt::TextureDimension::D1 => glow::TEXTURE_2D,
442            wgt::TextureDimension::D2 => {
443                // HACK: detect a cube map; forces cube compatible textures to be cube textures
444                match (desc.is_cube_compatible(), desc.size.depth_or_array_layers) {
445                    (false, 1) => glow::TEXTURE_2D,
446                    (false, _) => glow::TEXTURE_2D_ARRAY,
447                    (true, 6) => glow::TEXTURE_CUBE_MAP,
448                    (true, _) => glow::TEXTURE_CUBE_MAP_ARRAY,
449                }
450            }
451            wgt::TextureDimension::D3 => glow::TEXTURE_3D,
452        }
453    }
454
455    /// More information can be found in issues #1614 and #1574
456    fn log_failing_target_heuristics(view_dimension: wgt::TextureViewDimension, target: u32) {
457        let expected_target = match view_dimension {
458            wgt::TextureViewDimension::D1 => glow::TEXTURE_2D,
459            wgt::TextureViewDimension::D2 => glow::TEXTURE_2D,
460            wgt::TextureViewDimension::D2Array => glow::TEXTURE_2D_ARRAY,
461            wgt::TextureViewDimension::Cube => glow::TEXTURE_CUBE_MAP,
462            wgt::TextureViewDimension::CubeArray => glow::TEXTURE_CUBE_MAP_ARRAY,
463            wgt::TextureViewDimension::D3 => glow::TEXTURE_3D,
464        };
465
466        if expected_target == target {
467            return;
468        }
469
470        let buffer;
471        let got = match target {
472            glow::TEXTURE_2D => "D2",
473            glow::TEXTURE_2D_ARRAY => "D2Array",
474            glow::TEXTURE_CUBE_MAP => "Cube",
475            glow::TEXTURE_CUBE_MAP_ARRAY => "CubeArray",
476            glow::TEXTURE_3D => "D3",
477            target => {
478                buffer = target.to_string();
479                &buffer
480            }
481        };
482
483        log::error!(
484            concat!(
485                "wgpu-hal heuristics assumed that ",
486                "the view dimension will be equal to `{}` rather than `{:?}`.\n",
487                "`D2` textures with ",
488                "`depth_or_array_layers == 1` ",
489                "are assumed to have view dimension `D2`\n",
490                "`D2` textures with ",
491                "`depth_or_array_layers > 1` ",
492                "are assumed to have view dimension `D2Array`\n",
493                "`D2` textures with ",
494                "`depth_or_array_layers == 6` ",
495                "are assumed to have view dimension `Cube`\n",
496                "`D2` textures with ",
497                "`depth_or_array_layers > 6 && depth_or_array_layers % 6 == 0` ",
498                "are assumed to have view dimension `CubeArray`\n",
499            ),
500            got,
501            view_dimension,
502        );
503    }
504}
505
506#[derive(Clone, Debug)]
507pub struct TextureView {
508    inner: TextureInner,
509    aspects: crate::FormatAspects,
510    mip_levels: Range<u32>,
511    array_layers: Range<u32>,
512    format: wgt::TextureFormat,
513}
514
515impl crate::DynTextureView for TextureView {}
516
517#[derive(Debug)]
518pub struct Sampler {
519    raw: glow::Sampler,
520}
521
522impl crate::DynSampler for Sampler {}
523
524#[derive(Debug)]
525pub struct BindGroupLayout {
526    entries: Arc<[wgt::BindGroupLayoutEntry]>,
527}
528
529impl crate::DynBindGroupLayout for BindGroupLayout {}
530
531#[derive(Debug)]
532struct BindGroupLayoutInfo {
533    entries: Arc<[wgt::BindGroupLayoutEntry]>,
534    /// Mapping of resources, indexed by `binding`, into the whole layout space.
535    /// For texture resources, the value is the texture slot index.
536    /// For sampler resources, the value is the index of the sampler in the whole layout.
537    /// For buffers, the value is the uniform or storage slot index.
538    /// For unused bindings, the value is `!0`
539    binding_to_slot: Box<[u8]>,
540}
541
542#[derive(Debug)]
543pub struct PipelineLayout {
544    group_infos: Box<[BindGroupLayoutInfo]>,
545    naga_options: naga::back::glsl::Options,
546}
547
548impl crate::DynPipelineLayout for PipelineLayout {}
549
550impl PipelineLayout {
551    fn get_slot(&self, br: &naga::ResourceBinding) -> u8 {
552        let group_info = &self.group_infos[br.group as usize];
553        group_info.binding_to_slot[br.binding as usize]
554    }
555}
556
557#[derive(Debug)]
558enum BindingRegister {
559    UniformBuffers,
560    StorageBuffers,
561    Textures,
562    Images,
563}
564
565#[derive(Debug)]
566enum RawBinding {
567    Buffer {
568        raw: glow::Buffer,
569        offset: i32,
570        size: i32,
571    },
572    Texture {
573        raw: glow::Texture,
574        target: BindTarget,
575        aspects: crate::FormatAspects,
576        mip_levels: Range<u32>,
577        //TODO: array layers
578    },
579    Image(ImageBinding),
580    Sampler(glow::Sampler),
581}
582
583#[derive(Debug)]
584pub struct BindGroup {
585    contents: Box<[RawBinding]>,
586}
587
588impl crate::DynBindGroup for BindGroup {}
589
590type ShaderId = u32;
591
592#[derive(Debug)]
593pub struct ShaderModule {
594    naga: crate::NagaShader,
595    label: Option<String>,
596    id: ShaderId,
597}
598
599impl crate::DynShaderModule for ShaderModule {}
600
601#[derive(Clone, Debug, Default)]
602struct VertexFormatDesc {
603    element_count: i32,
604    element_format: u32,
605    attrib_kind: VertexAttribKind,
606}
607
608#[derive(Clone, Debug, Default)]
609struct AttributeDesc {
610    location: u32,
611    offset: u32,
612    buffer_index: u32,
613    format_desc: VertexFormatDesc,
614}
615
616#[derive(Clone, Debug)]
617struct BufferBinding {
618    raw: glow::Buffer,
619    offset: wgt::BufferAddress,
620}
621
622#[derive(Clone, Debug)]
623struct ImageBinding {
624    raw: glow::Texture,
625    mip_level: u32,
626    array_layer: Option<u32>,
627    access: u32,
628    format: u32,
629}
630
631#[derive(Clone, Debug, Default, PartialEq)]
632struct VertexBufferDesc {
633    step: wgt::VertexStepMode,
634    stride: u32,
635}
636
637#[derive(Clone, Debug)]
638struct PushConstantDesc {
639    location: glow::UniformLocation,
640    ty: naga::TypeInner,
641    offset: u32,
642    size_bytes: u32,
643}
644
645#[cfg(send_sync)]
646unsafe impl Sync for PushConstantDesc {}
647#[cfg(send_sync)]
648unsafe impl Send for PushConstantDesc {}
649
650/// For each texture in the pipeline layout, store the index of the only
651/// sampler (in this layout) that the texture is used with.
652type SamplerBindMap = [Option<u8>; MAX_TEXTURE_SLOTS];
653
654#[derive(Debug)]
655struct PipelineInner {
656    program: glow::Program,
657    sampler_map: SamplerBindMap,
658    first_instance_location: Option<glow::UniformLocation>,
659    push_constant_descs: ArrayVec<PushConstantDesc, MAX_PUSH_CONSTANT_COMMANDS>,
660}
661
662#[derive(Clone, Debug)]
663struct DepthState {
664    function: u32,
665    mask: bool,
666}
667
668#[derive(Clone, Debug, PartialEq)]
669struct BlendComponent {
670    src: u32,
671    dst: u32,
672    equation: u32,
673}
674
675#[derive(Clone, Debug, PartialEq)]
676struct BlendDesc {
677    alpha: BlendComponent,
678    color: BlendComponent,
679}
680
681#[derive(Clone, Debug, Default, PartialEq)]
682struct ColorTargetDesc {
683    mask: wgt::ColorWrites,
684    blend: Option<BlendDesc>,
685}
686
687#[derive(PartialEq, Eq, Hash)]
688struct ProgramStage {
689    naga_stage: naga::ShaderStage,
690    shader_id: ShaderId,
691    entry_point: String,
692    zero_initialize_workgroup_memory: bool,
693}
694
695#[derive(PartialEq, Eq, Hash)]
696struct ProgramCacheKey {
697    stages: ArrayVec<ProgramStage, 3>,
698    group_to_binding_to_slot: Box<[Box<[u8]>]>,
699}
700
701type ProgramCache = FastHashMap<ProgramCacheKey, Result<Arc<PipelineInner>, crate::PipelineError>>;
702
703#[derive(Debug)]
704pub struct RenderPipeline {
705    inner: Arc<PipelineInner>,
706    primitive: wgt::PrimitiveState,
707    vertex_buffers: Box<[VertexBufferDesc]>,
708    vertex_attributes: Box<[AttributeDesc]>,
709    color_targets: Box<[ColorTargetDesc]>,
710    depth: Option<DepthState>,
711    depth_bias: wgt::DepthBiasState,
712    stencil: Option<StencilState>,
713    alpha_to_coverage_enabled: bool,
714}
715
716impl crate::DynRenderPipeline for RenderPipeline {}
717
718#[cfg(send_sync)]
719unsafe impl Sync for RenderPipeline {}
720#[cfg(send_sync)]
721unsafe impl Send for RenderPipeline {}
722
723#[derive(Debug)]
724pub struct ComputePipeline {
725    inner: Arc<PipelineInner>,
726}
727
728impl crate::DynComputePipeline for ComputePipeline {}
729
730#[cfg(send_sync)]
731unsafe impl Sync for ComputePipeline {}
732#[cfg(send_sync)]
733unsafe impl Send for ComputePipeline {}
734
735#[derive(Debug)]
736pub struct QuerySet {
737    queries: Box<[glow::Query]>,
738    target: BindTarget,
739}
740
741impl crate::DynQuerySet for QuerySet {}
742
743#[derive(Debug)]
744pub struct AccelerationStructure;
745
746impl crate::DynAccelerationStructure for AccelerationStructure {}
747
748#[derive(Debug)]
749pub struct PipelineCache;
750
751impl crate::DynPipelineCache for PipelineCache {}
752
753#[derive(Clone, Debug, PartialEq)]
754struct StencilOps {
755    pass: u32,
756    fail: u32,
757    depth_fail: u32,
758}
759
760impl Default for StencilOps {
761    fn default() -> Self {
762        Self {
763            pass: glow::KEEP,
764            fail: glow::KEEP,
765            depth_fail: glow::KEEP,
766        }
767    }
768}
769
770#[derive(Clone, Debug, PartialEq)]
771struct StencilSide {
772    function: u32,
773    mask_read: u32,
774    mask_write: u32,
775    reference: u32,
776    ops: StencilOps,
777}
778
779impl Default for StencilSide {
780    fn default() -> Self {
781        Self {
782            function: glow::ALWAYS,
783            mask_read: 0xFF,
784            mask_write: 0xFF,
785            reference: 0,
786            ops: StencilOps::default(),
787        }
788    }
789}
790
791#[derive(Debug, Clone, Default)]
792struct StencilState {
793    front: StencilSide,
794    back: StencilSide,
795}
796
797#[derive(Clone, Debug, Default, PartialEq)]
798struct PrimitiveState {
799    front_face: u32,
800    cull_face: u32,
801    unclipped_depth: bool,
802    polygon_mode: u32,
803}
804
805type InvalidatedAttachments = ArrayVec<u32, { crate::MAX_COLOR_ATTACHMENTS + 2 }>;
806
807#[derive(Debug)]
808enum Command {
809    Draw {
810        topology: u32,
811        first_vertex: u32,
812        vertex_count: u32,
813        first_instance: u32,
814        instance_count: u32,
815        first_instance_location: Option<glow::UniformLocation>,
816    },
817    DrawIndexed {
818        topology: u32,
819        index_type: u32,
820        index_count: u32,
821        index_offset: wgt::BufferAddress,
822        base_vertex: i32,
823        first_instance: u32,
824        instance_count: u32,
825        first_instance_location: Option<glow::UniformLocation>,
826    },
827    DrawIndirect {
828        topology: u32,
829        indirect_buf: glow::Buffer,
830        indirect_offset: wgt::BufferAddress,
831        first_instance_location: Option<glow::UniformLocation>,
832    },
833    DrawIndexedIndirect {
834        topology: u32,
835        index_type: u32,
836        indirect_buf: glow::Buffer,
837        indirect_offset: wgt::BufferAddress,
838        first_instance_location: Option<glow::UniformLocation>,
839    },
840    Dispatch([u32; 3]),
841    DispatchIndirect {
842        indirect_buf: glow::Buffer,
843        indirect_offset: wgt::BufferAddress,
844    },
845    ClearBuffer {
846        dst: Buffer,
847        dst_target: BindTarget,
848        range: crate::MemoryRange,
849    },
850    CopyBufferToBuffer {
851        src: Buffer,
852        src_target: BindTarget,
853        dst: Buffer,
854        dst_target: BindTarget,
855        copy: crate::BufferCopy,
856    },
857    #[cfg(webgl)]
858    CopyExternalImageToTexture {
859        src: wgt::CopyExternalImageSourceInfo,
860        dst: glow::Texture,
861        dst_target: BindTarget,
862        dst_format: wgt::TextureFormat,
863        dst_premultiplication: bool,
864        copy: crate::TextureCopy,
865    },
866    CopyTextureToTexture {
867        src: glow::Texture,
868        src_target: BindTarget,
869        dst: glow::Texture,
870        dst_target: BindTarget,
871        copy: crate::TextureCopy,
872    },
873    CopyBufferToTexture {
874        src: Buffer,
875        #[allow(unused)]
876        src_target: BindTarget,
877        dst: glow::Texture,
878        dst_target: BindTarget,
879        dst_format: wgt::TextureFormat,
880        copy: crate::BufferTextureCopy,
881    },
882    CopyTextureToBuffer {
883        src: glow::Texture,
884        src_target: BindTarget,
885        src_format: wgt::TextureFormat,
886        dst: Buffer,
887        #[allow(unused)]
888        dst_target: BindTarget,
889        copy: crate::BufferTextureCopy,
890    },
891    SetIndexBuffer(glow::Buffer),
892    BeginQuery(glow::Query, BindTarget),
893    EndQuery(BindTarget),
894    TimestampQuery(glow::Query),
895    CopyQueryResults {
896        query_range: Range<u32>,
897        dst: Buffer,
898        dst_target: BindTarget,
899        dst_offset: wgt::BufferAddress,
900    },
901    ResetFramebuffer {
902        is_default: bool,
903    },
904    BindAttachment {
905        attachment: u32,
906        view: TextureView,
907    },
908    ResolveAttachment {
909        attachment: u32,
910        dst: TextureView,
911        size: wgt::Extent3d,
912    },
913    InvalidateAttachments(InvalidatedAttachments),
914    SetDrawColorBuffers(u8),
915    ClearColorF {
916        draw_buffer: u32,
917        color: [f32; 4],
918        is_srgb: bool,
919    },
920    ClearColorU(u32, [u32; 4]),
921    ClearColorI(u32, [i32; 4]),
922    ClearDepth(f32),
923    ClearStencil(u32),
924    // Clearing both the depth and stencil buffer individually appears to
925    // result in the stencil buffer failing to clear, atleast in WebGL.
926    // It is also more efficient to emit a single command instead of two for
927    // this.
928    ClearDepthAndStencil(f32, u32),
929    BufferBarrier(glow::Buffer, wgt::BufferUses),
930    TextureBarrier(wgt::TextureUses),
931    SetViewport {
932        rect: crate::Rect<i32>,
933        depth: Range<f32>,
934    },
935    SetScissor(crate::Rect<i32>),
936    SetStencilFunc {
937        face: u32,
938        function: u32,
939        reference: u32,
940        read_mask: u32,
941    },
942    SetStencilOps {
943        face: u32,
944        write_mask: u32,
945        ops: StencilOps,
946    },
947    SetDepth(DepthState),
948    SetDepthBias(wgt::DepthBiasState),
949    ConfigureDepthStencil(crate::FormatAspects),
950    SetAlphaToCoverage(bool),
951    SetVertexAttribute {
952        buffer: Option<glow::Buffer>,
953        buffer_desc: VertexBufferDesc,
954        attribute_desc: AttributeDesc,
955    },
956    UnsetVertexAttribute(u32),
957    SetVertexBuffer {
958        index: u32,
959        buffer: BufferBinding,
960        buffer_desc: VertexBufferDesc,
961    },
962    SetProgram(glow::Program),
963    SetPrimitive(PrimitiveState),
964    SetBlendConstant([f32; 4]),
965    SetColorTarget {
966        draw_buffer_index: Option<u32>,
967        desc: ColorTargetDesc,
968    },
969    BindBuffer {
970        target: BindTarget,
971        slot: u32,
972        buffer: glow::Buffer,
973        offset: i32,
974        size: i32,
975    },
976    BindSampler(u32, Option<glow::Sampler>),
977    BindTexture {
978        slot: u32,
979        texture: glow::Texture,
980        target: BindTarget,
981        aspects: crate::FormatAspects,
982        mip_levels: Range<u32>,
983    },
984    BindImage {
985        slot: u32,
986        binding: ImageBinding,
987    },
988    InsertDebugMarker(Range<u32>),
989    PushDebugGroup(Range<u32>),
990    PopDebugGroup,
991    SetPushConstants {
992        uniform: PushConstantDesc,
993        /// Offset from the start of the `data_bytes`
994        offset: u32,
995    },
996}
997
998#[derive(Default)]
999pub struct CommandBuffer {
1000    label: Option<String>,
1001    commands: Vec<Command>,
1002    data_bytes: Vec<u8>,
1003    queries: Vec<glow::Query>,
1004}
1005
1006impl crate::DynCommandBuffer for CommandBuffer {}
1007
1008impl fmt::Debug for CommandBuffer {
1009    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1010        let mut builder = f.debug_struct("CommandBuffer");
1011        if let Some(ref label) = self.label {
1012            builder.field("label", label);
1013        }
1014        builder.finish()
1015    }
1016}
1017
1018#[cfg(send_sync)]
1019unsafe impl Sync for CommandBuffer {}
1020#[cfg(send_sync)]
1021unsafe impl Send for CommandBuffer {}
1022
1023//TODO: we would have something like `Arc<typed_arena::Arena>`
1024// here and in the command buffers. So that everything grows
1025// inside the encoder and stays there until `reset_all`.
1026
1027pub struct CommandEncoder {
1028    cmd_buffer: CommandBuffer,
1029    state: command::State,
1030    private_caps: PrivateCapabilities,
1031    counters: Arc<wgt::HalCounters>,
1032}
1033
1034impl fmt::Debug for CommandEncoder {
1035    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1036        f.debug_struct("CommandEncoder")
1037            .field("cmd_buffer", &self.cmd_buffer)
1038            .finish()
1039    }
1040}
1041
1042#[cfg(send_sync)]
1043unsafe impl Sync for CommandEncoder {}
1044#[cfg(send_sync)]
1045unsafe impl Send for CommandEncoder {}
1046
1047#[cfg(not(webgl))]
1048fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
1049    let source_str = match source {
1050        glow::DEBUG_SOURCE_API => "API",
1051        glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
1052        glow::DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
1053        glow::DEBUG_SOURCE_THIRD_PARTY => "Third Party",
1054        glow::DEBUG_SOURCE_APPLICATION => "Application",
1055        glow::DEBUG_SOURCE_OTHER => "Other",
1056        _ => unreachable!(),
1057    };
1058
1059    let log_severity = match severity {
1060        glow::DEBUG_SEVERITY_HIGH => log::Level::Error,
1061        glow::DEBUG_SEVERITY_MEDIUM => log::Level::Warn,
1062        glow::DEBUG_SEVERITY_LOW => log::Level::Info,
1063        glow::DEBUG_SEVERITY_NOTIFICATION => log::Level::Trace,
1064        _ => unreachable!(),
1065    };
1066
1067    let type_str = match gltype {
1068        glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior",
1069        glow::DEBUG_TYPE_ERROR => "Error",
1070        glow::DEBUG_TYPE_MARKER => "Marker",
1071        glow::DEBUG_TYPE_OTHER => "Other",
1072        glow::DEBUG_TYPE_PERFORMANCE => "Performance",
1073        glow::DEBUG_TYPE_POP_GROUP => "Pop Group",
1074        glow::DEBUG_TYPE_PORTABILITY => "Portability",
1075        glow::DEBUG_TYPE_PUSH_GROUP => "Push Group",
1076        glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior",
1077        _ => unreachable!(),
1078    };
1079
1080    let _ = std::panic::catch_unwind(|| {
1081        log::log!(
1082            log_severity,
1083            "GLES: [{}/{}] ID {} : {}",
1084            source_str,
1085            type_str,
1086            id,
1087            message
1088        );
1089    });
1090
1091    if cfg!(debug_assertions) && log_severity == log::Level::Error {
1092        // Set canary and continue
1093        crate::VALIDATION_CANARY.add(message.to_string());
1094    }
1095}
1096
1097// If we are using `std`, then use `Mutex` to provide `Send` and `Sync`
1098cfg_if::cfg_if! {
1099    if #[cfg(gles_with_std)] {
1100        type MaybeMutex<T> = std::sync::Mutex<T>;
1101
1102        fn lock<T>(mutex: &MaybeMutex<T>) -> std::sync::MutexGuard<'_, T> {
1103            mutex.lock().unwrap()
1104        }
1105    } else {
1106        // It should be impossible for any build configuration to trigger this error
1107        // It is intended only as a guard against changes elsewhere causing the use of
1108        // `RefCell` here to become unsound.
1109        #[cfg(all(send_sync, not(feature = "fragile-send-sync-non-atomic-wasm")))]
1110        compile_error!("cannot provide non-fragile Send+Sync without std");
1111
1112        type MaybeMutex<T> = core::cell::RefCell<T>;
1113
1114        fn lock<T>(mutex: &MaybeMutex<T>) -> core::cell::RefMut<'_, T> {
1115            mutex.borrow_mut()
1116        }
1117    }
1118}