Skip to main content

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