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