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 "base 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 `start_instance` is used
55  - stride has changed
56
57*/
58
59///cbindgen:ignore
60#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
61mod egl;
62#[cfg(target_os = "emscripten")]
63mod emscripten;
64#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
65mod web;
66
67mod adapter;
68mod command;
69mod conv;
70mod device;
71mod queue;
72
73use crate::{CopyExtent, TextureDescriptor};
74
75#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
76pub use self::egl::{AdapterContext, AdapterContextLock};
77#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
78use self::egl::{Instance, Surface};
79
80#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
81pub use self::web::AdapterContext;
82#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
83use self::web::{Instance, Surface};
84
85use arrayvec::ArrayVec;
86
87use glow::HasContext;
88
89use naga::FastHashMap;
90use parking_lot::Mutex;
91use std::sync::atomic::AtomicU32;
92use std::{fmt, ops::Range, sync::Arc};
93
94#[derive(Clone)]
95pub struct Api;
96
97//Note: we can support more samplers if not every one of them is used at a time,
98// but it probably doesn't worth it.
99const MAX_TEXTURE_SLOTS: usize = 16;
100const MAX_SAMPLERS: usize = 16;
101const MAX_VERTEX_ATTRIBUTES: usize = 16;
102const ZERO_BUFFER_SIZE: usize = 256 << 10;
103const MAX_PUSH_CONSTANTS: usize = 64;
104
105impl crate::Api for Api {
106    type Instance = Instance;
107    type Surface = Surface;
108    type Adapter = Adapter;
109    type Device = Device;
110
111    type Queue = Queue;
112    type CommandEncoder = CommandEncoder;
113    type CommandBuffer = CommandBuffer;
114
115    type Buffer = Buffer;
116    type Texture = Texture;
117    type SurfaceTexture = Texture;
118    type TextureView = TextureView;
119    type Sampler = Sampler;
120    type QuerySet = QuerySet;
121    type Fence = Fence;
122
123    type BindGroupLayout = BindGroupLayout;
124    type BindGroup = BindGroup;
125    type PipelineLayout = PipelineLayout;
126    type ShaderModule = ShaderModule;
127    type RenderPipeline = RenderPipeline;
128    type ComputePipeline = ComputePipeline;
129}
130
131bitflags::bitflags! {
132    /// Flags that affect internal code paths but do not
133    /// change the exposed feature set.
134    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
135    struct PrivateCapabilities: u32 {
136        /// Indicates support for `glBufferStorage` allocation.
137        const BUFFER_ALLOCATION = 1 << 0;
138        /// Support explicit layouts in shader.
139        const SHADER_BINDING_LAYOUT = 1 << 1;
140        /// Support extended shadow sampling instructions.
141        const SHADER_TEXTURE_SHADOW_LOD = 1 << 2;
142        /// Support memory barriers.
143        const MEMORY_BARRIERS = 1 << 3;
144        /// Vertex buffer layouts separate from the data.
145        const VERTEX_BUFFER_LAYOUT = 1 << 4;
146        /// Indicates that buffers used as `GL_ELEMENT_ARRAY_BUFFER` may be created / initialized / used
147        /// as other targets, if not present they must not be mixed with other targets.
148        const INDEX_BUFFER_ROLE_CHANGE = 1 << 5;
149        /// Indicates that the device supports disabling draw buffers
150        const CAN_DISABLE_DRAW_BUFFER = 1 << 6;
151        /// Supports `glGetBufferSubData`
152        const GET_BUFFER_SUB_DATA = 1 << 7;
153        /// Supports `f16` color buffers
154        const COLOR_BUFFER_HALF_FLOAT = 1 << 8;
155        /// Supports `f11/f10` and `f32` color buffers
156        const COLOR_BUFFER_FLOAT = 1 << 9;
157        /// Supports linear flitering `f32` textures.
158        const TEXTURE_FLOAT_LINEAR = 1 << 10;
159    }
160}
161
162bitflags::bitflags! {
163    /// Flags that indicate necessary workarounds for specific devices or driver bugs
164    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
165    struct Workarounds: u32 {
166        // Needs workaround for Intel Mesa bug:
167        // https://gitlab.freedesktop.org/mesa/mesa/-/issues/2565.
168        //
169        // This comment
170        // (https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4972/diffs?diff_id=75888#22f5d1004713c9bbf857988c7efb81631ab88f99_323_327)
171        // seems to indicate all skylake models are effected.
172        const MESA_I915_SRGB_SHADER_CLEAR = 1 << 0;
173        /// Buffer map must emulated becuase it is not supported natively
174        const EMULATE_BUFFER_MAP = 1 << 1;
175    }
176}
177
178type BindTarget = u32;
179
180#[derive(Debug, Clone, Copy)]
181enum VertexAttribKind {
182    Float, // glVertexAttribPointer
183    Integer, // glVertexAttribIPointer
184           //Double,  // glVertexAttribLPointer
185}
186
187impl Default for VertexAttribKind {
188    fn default() -> Self {
189        Self::Float
190    }
191}
192
193#[derive(Clone, Debug)]
194pub struct TextureFormatDesc {
195    pub internal: u32,
196    pub external: u32,
197    pub data_type: u32,
198}
199
200struct AdapterShared {
201    context: AdapterContext,
202    private_caps: PrivateCapabilities,
203    features: wgt::Features,
204    workarounds: Workarounds,
205    shading_language_version: naga::back::glsl::Version,
206    max_texture_size: u32,
207    next_shader_id: AtomicU32,
208    program_cache: Mutex<ProgramCache>,
209}
210
211pub struct Adapter {
212    shared: Arc<AdapterShared>,
213}
214
215pub struct Device {
216    shared: Arc<AdapterShared>,
217    main_vao: glow::VertexArray,
218    #[cfg(all(not(target_arch = "wasm32"), feature = "renderdoc"))]
219    render_doc: crate::auxil::renderdoc::RenderDoc,
220}
221
222pub struct Queue {
223    shared: Arc<AdapterShared>,
224    features: wgt::Features,
225    draw_fbo: glow::Framebuffer,
226    copy_fbo: glow::Framebuffer,
227    /// Shader program used to clear the screen for [`Workarounds::MESA_I915_SRGB_SHADER_CLEAR`]
228    /// devices.
229    shader_clear_program: glow::Program,
230    /// The uniform location of the color uniform in the shader clear program
231    shader_clear_program_color_uniform_location: glow::UniformLocation,
232    /// Keep a reasonably large buffer filled with zeroes, so that we can implement `ClearBuffer` of
233    /// zeroes by copying from it.
234    zero_buffer: glow::Buffer,
235    temp_query_results: Vec<u64>,
236    draw_buffer_count: u8,
237    current_index_buffer: Option<glow::Buffer>,
238}
239
240#[derive(Clone, Debug)]
241pub struct Buffer {
242    raw: Option<glow::Buffer>,
243    target: BindTarget,
244    size: wgt::BufferAddress,
245    map_flags: u32,
246    data: Option<Arc<std::sync::Mutex<Vec<u8>>>>,
247}
248
249#[cfg(all(
250    target_arch = "wasm32",
251    feature = "fragile-send-sync-non-atomic-wasm",
252    not(target_feature = "atomics")
253))]
254unsafe impl Sync for Buffer {}
255#[cfg(all(
256    target_arch = "wasm32",
257    feature = "fragile-send-sync-non-atomic-wasm",
258    not(target_feature = "atomics")
259))]
260unsafe impl Send for Buffer {}
261
262#[derive(Clone, Debug)]
263pub enum TextureInner {
264    Renderbuffer {
265        raw: glow::Renderbuffer,
266    },
267    DefaultRenderbuffer,
268    Texture {
269        raw: glow::Texture,
270        target: BindTarget,
271    },
272    #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
273    ExternalFramebuffer {
274        inner: web_sys::WebGlFramebuffer,
275    },
276}
277
278#[cfg(all(
279    target_arch = "wasm32",
280    feature = "fragile-send-sync-non-atomic-wasm",
281    not(target_feature = "atomics")
282))]
283unsafe impl Sync for TextureInner {}
284#[cfg(all(
285    target_arch = "wasm32",
286    feature = "fragile-send-sync-non-atomic-wasm",
287    not(target_feature = "atomics")
288))]
289unsafe impl Send for TextureInner {}
290
291impl TextureInner {
292    fn as_native(&self) -> (glow::Texture, BindTarget) {
293        match *self {
294            Self::Renderbuffer { .. } | Self::DefaultRenderbuffer => {
295                panic!("Unexpected renderbuffer");
296            }
297            Self::Texture { raw, target } => (raw, target),
298            #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
299            Self::ExternalFramebuffer { .. } => panic!("Unexpected external framebuffer"),
300        }
301    }
302}
303
304#[derive(Debug)]
305pub struct Texture {
306    pub inner: TextureInner,
307    pub drop_guard: Option<crate::DropGuard>,
308    pub mip_level_count: u32,
309    pub array_layer_count: u32,
310    pub format: wgt::TextureFormat,
311    #[allow(unused)]
312    pub format_desc: TextureFormatDesc,
313    pub copy_size: CopyExtent,
314    pub is_cubemap: bool,
315}
316
317impl Texture {
318    pub fn default_framebuffer(format: wgt::TextureFormat) -> Self {
319        Self {
320            inner: TextureInner::DefaultRenderbuffer,
321            drop_guard: None,
322            mip_level_count: 1,
323            array_layer_count: 1,
324            format,
325            format_desc: TextureFormatDesc {
326                internal: 0,
327                external: 0,
328                data_type: 0,
329            },
330            copy_size: CopyExtent {
331                width: 0,
332                height: 0,
333                depth: 0,
334            },
335            is_cubemap: false,
336        }
337    }
338
339    /// Returns the `target`, whether the image is 3d and whether the image is a cubemap.
340    fn get_info_from_desc(desc: &TextureDescriptor) -> (u32, bool, bool) {
341        match desc.dimension {
342            wgt::TextureDimension::D1 => (glow::TEXTURE_2D, false, false),
343            wgt::TextureDimension::D2 => {
344                // HACK: detect a cube map; forces cube compatible textures to be cube textures
345                match (desc.is_cube_compatible(), desc.size.depth_or_array_layers) {
346                    (false, 1) => (glow::TEXTURE_2D, false, false),
347                    (false, _) => (glow::TEXTURE_2D_ARRAY, true, false),
348                    (true, 6) => (glow::TEXTURE_CUBE_MAP, false, true),
349                    (true, _) => (glow::TEXTURE_CUBE_MAP_ARRAY, true, true),
350                }
351            }
352            wgt::TextureDimension::D3 => (glow::TEXTURE_3D, true, false),
353        }
354    }
355}
356
357#[derive(Clone, Debug)]
358pub struct TextureView {
359    inner: TextureInner,
360    aspects: crate::FormatAspects,
361    mip_levels: Range<u32>,
362    array_layers: Range<u32>,
363    format: wgt::TextureFormat,
364}
365
366#[derive(Debug)]
367pub struct Sampler {
368    raw: glow::Sampler,
369}
370
371pub struct BindGroupLayout {
372    entries: Arc<[wgt::BindGroupLayoutEntry]>,
373}
374
375struct BindGroupLayoutInfo {
376    entries: Arc<[wgt::BindGroupLayoutEntry]>,
377    /// Mapping of resources, indexed by `binding`, into the whole layout space.
378    /// For texture resources, the value is the texture slot index.
379    /// For sampler resources, the value is the index of the sampler in the whole layout.
380    /// For buffers, the value is the uniform or storage slot index.
381    /// For unused bindings, the value is `!0`
382    binding_to_slot: Box<[u8]>,
383}
384
385pub struct PipelineLayout {
386    group_infos: Box<[BindGroupLayoutInfo]>,
387    naga_options: naga::back::glsl::Options,
388}
389
390impl PipelineLayout {
391    fn get_slot(&self, br: &naga::ResourceBinding) -> u8 {
392        let group_info = &self.group_infos[br.group as usize];
393        group_info.binding_to_slot[br.binding as usize]
394    }
395}
396
397#[derive(Debug)]
398enum BindingRegister {
399    UniformBuffers,
400    StorageBuffers,
401    Textures,
402    Images,
403}
404
405#[derive(Debug)]
406enum RawBinding {
407    Buffer {
408        raw: glow::Buffer,
409        offset: i32,
410        size: i32,
411    },
412    Texture {
413        raw: glow::Texture,
414        target: BindTarget,
415        aspects: crate::FormatAspects,
416        //TODO: mip levels, array layers
417    },
418    Image(ImageBinding),
419    Sampler(glow::Sampler),
420}
421
422#[derive(Debug)]
423pub struct BindGroup {
424    contents: Box<[RawBinding]>,
425}
426
427type ShaderId = u32;
428
429#[derive(Debug)]
430pub struct ShaderModule {
431    naga: crate::NagaShader,
432    label: Option<String>,
433    id: ShaderId,
434}
435
436#[derive(Clone, Debug, Default)]
437struct VertexFormatDesc {
438    element_count: i32,
439    element_format: u32,
440    attrib_kind: VertexAttribKind,
441}
442
443#[derive(Clone, Debug, Default)]
444struct AttributeDesc {
445    location: u32,
446    offset: u32,
447    buffer_index: u32,
448    format_desc: VertexFormatDesc,
449}
450
451#[derive(Clone, Debug)]
452struct BufferBinding {
453    raw: glow::Buffer,
454    offset: wgt::BufferAddress,
455}
456
457#[derive(Clone, Debug)]
458struct ImageBinding {
459    raw: glow::Texture,
460    mip_level: u32,
461    array_layer: Option<u32>,
462    access: u32,
463    format: u32,
464}
465
466#[derive(Clone, Debug, Default, PartialEq)]
467struct VertexBufferDesc {
468    step: wgt::VertexStepMode,
469    stride: u32,
470}
471
472#[derive(Clone, Debug, Default)]
473struct UniformDesc {
474    location: Option<glow::UniformLocation>,
475    size: u32,
476    utype: u32,
477}
478
479#[cfg(all(
480    target_arch = "wasm32",
481    feature = "fragile-send-sync-non-atomic-wasm",
482    not(target_feature = "atomics")
483))]
484unsafe impl Sync for UniformDesc {}
485#[cfg(all(
486    target_arch = "wasm32",
487    feature = "fragile-send-sync-non-atomic-wasm",
488    not(target_feature = "atomics")
489))]
490unsafe impl Send for UniformDesc {}
491
492/// For each texture in the pipeline layout, store the index of the only
493/// sampler (in this layout) that the texture is used with.
494type SamplerBindMap = [Option<u8>; MAX_TEXTURE_SLOTS];
495
496struct PipelineInner {
497    program: glow::Program,
498    sampler_map: SamplerBindMap,
499    uniforms: [UniformDesc; MAX_PUSH_CONSTANTS],
500}
501
502#[derive(Clone, Debug)]
503struct DepthState {
504    function: u32,
505    mask: bool,
506}
507
508#[derive(Clone, Debug, PartialEq)]
509struct BlendComponent {
510    src: u32,
511    dst: u32,
512    equation: u32,
513}
514
515#[derive(Clone, Debug, PartialEq)]
516struct BlendDesc {
517    alpha: BlendComponent,
518    color: BlendComponent,
519}
520
521#[derive(Clone, Debug, Default, PartialEq)]
522struct ColorTargetDesc {
523    mask: wgt::ColorWrites,
524    blend: Option<BlendDesc>,
525}
526
527#[derive(PartialEq, Eq, Hash)]
528struct ProgramStage {
529    naga_stage: naga::ShaderStage,
530    shader_id: ShaderId,
531    entry_point: String,
532}
533
534#[derive(PartialEq, Eq, Hash)]
535struct ProgramCacheKey {
536    stages: ArrayVec<ProgramStage, 3>,
537    group_to_binding_to_slot: Box<[Box<[u8]>]>,
538}
539
540type ProgramCache = FastHashMap<ProgramCacheKey, Result<Arc<PipelineInner>, crate::PipelineError>>;
541
542pub struct RenderPipeline {
543    inner: Arc<PipelineInner>,
544    primitive: wgt::PrimitiveState,
545    vertex_buffers: Box<[VertexBufferDesc]>,
546    vertex_attributes: Box<[AttributeDesc]>,
547    color_targets: Box<[ColorTargetDesc]>,
548    depth: Option<DepthState>,
549    depth_bias: wgt::DepthBiasState,
550    stencil: Option<StencilState>,
551    alpha_to_coverage_enabled: bool,
552}
553
554#[cfg(all(
555    target_arch = "wasm32",
556    feature = "fragile-send-sync-non-atomic-wasm",
557    not(target_feature = "atomics")
558))]
559unsafe impl Sync for RenderPipeline {}
560#[cfg(all(
561    target_arch = "wasm32",
562    feature = "fragile-send-sync-non-atomic-wasm",
563    not(target_feature = "atomics")
564))]
565unsafe impl Send for RenderPipeline {}
566
567pub struct ComputePipeline {
568    inner: Arc<PipelineInner>,
569}
570
571#[cfg(all(
572    target_arch = "wasm32",
573    feature = "fragile-send-sync-non-atomic-wasm",
574    not(target_feature = "atomics")
575))]
576unsafe impl Sync for ComputePipeline {}
577#[cfg(all(
578    target_arch = "wasm32",
579    feature = "fragile-send-sync-non-atomic-wasm",
580    not(target_feature = "atomics")
581))]
582unsafe impl Send for ComputePipeline {}
583
584#[derive(Debug)]
585pub struct QuerySet {
586    queries: Box<[glow::Query]>,
587    target: BindTarget,
588}
589
590#[derive(Debug)]
591pub struct Fence {
592    last_completed: crate::FenceValue,
593    pending: Vec<(crate::FenceValue, glow::Fence)>,
594}
595
596#[cfg(any(
597    not(target_arch = "wasm32"),
598    all(
599        feature = "fragile-send-sync-non-atomic-wasm",
600        not(target_feature = "atomics")
601    )
602))]
603unsafe impl Send for Fence {}
604#[cfg(any(
605    not(target_arch = "wasm32"),
606    all(
607        feature = "fragile-send-sync-non-atomic-wasm",
608        not(target_feature = "atomics")
609    )
610))]
611unsafe impl Sync for Fence {}
612
613impl Fence {
614    fn get_latest(&self, gl: &glow::Context) -> crate::FenceValue {
615        let mut max_value = self.last_completed;
616        for &(value, sync) in self.pending.iter() {
617            let status = unsafe { gl.get_sync_status(sync) };
618            if status == glow::SIGNALED {
619                max_value = value;
620            }
621        }
622        max_value
623    }
624
625    fn maintain(&mut self, gl: &glow::Context) {
626        let latest = self.get_latest(gl);
627        for &(value, sync) in self.pending.iter() {
628            if value <= latest {
629                unsafe {
630                    gl.delete_sync(sync);
631                }
632            }
633        }
634        self.pending.retain(|&(value, _)| value > latest);
635        self.last_completed = latest;
636    }
637}
638
639#[derive(Clone, Debug, PartialEq)]
640struct StencilOps {
641    pass: u32,
642    fail: u32,
643    depth_fail: u32,
644}
645
646impl Default for StencilOps {
647    fn default() -> Self {
648        Self {
649            pass: glow::KEEP,
650            fail: glow::KEEP,
651            depth_fail: glow::KEEP,
652        }
653    }
654}
655
656#[derive(Clone, Debug, PartialEq)]
657struct StencilSide {
658    function: u32,
659    mask_read: u32,
660    mask_write: u32,
661    reference: u32,
662    ops: StencilOps,
663}
664
665impl Default for StencilSide {
666    fn default() -> Self {
667        Self {
668            function: glow::ALWAYS,
669            mask_read: 0xFF,
670            mask_write: 0xFF,
671            reference: 0,
672            ops: StencilOps::default(),
673        }
674    }
675}
676
677#[derive(Clone, Default)]
678struct StencilState {
679    front: StencilSide,
680    back: StencilSide,
681}
682
683#[derive(Clone, Debug, Default, PartialEq)]
684struct PrimitiveState {
685    front_face: u32,
686    cull_face: u32,
687    unclipped_depth: bool,
688}
689
690type InvalidatedAttachments = ArrayVec<u32, { crate::MAX_COLOR_ATTACHMENTS + 2 }>;
691
692#[derive(Debug)]
693enum Command {
694    Draw {
695        topology: u32,
696        start_vertex: u32,
697        vertex_count: u32,
698        instance_count: u32,
699    },
700    DrawIndexed {
701        topology: u32,
702        index_type: u32,
703        index_count: u32,
704        index_offset: wgt::BufferAddress,
705        base_vertex: i32,
706        instance_count: u32,
707    },
708    DrawIndirect {
709        topology: u32,
710        indirect_buf: glow::Buffer,
711        indirect_offset: wgt::BufferAddress,
712    },
713    DrawIndexedIndirect {
714        topology: u32,
715        index_type: u32,
716        indirect_buf: glow::Buffer,
717        indirect_offset: wgt::BufferAddress,
718    },
719    Dispatch([u32; 3]),
720    DispatchIndirect {
721        indirect_buf: glow::Buffer,
722        indirect_offset: wgt::BufferAddress,
723    },
724    ClearBuffer {
725        dst: Buffer,
726        dst_target: BindTarget,
727        range: crate::MemoryRange,
728    },
729    CopyBufferToBuffer {
730        src: Buffer,
731        src_target: BindTarget,
732        dst: Buffer,
733        dst_target: BindTarget,
734        copy: crate::BufferCopy,
735    },
736    #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
737    CopyExternalImageToTexture {
738        src: wgt::ImageCopyExternalImage,
739        dst: glow::Texture,
740        dst_target: BindTarget,
741        dst_format: wgt::TextureFormat,
742        dst_premultiplication: bool,
743        copy: crate::TextureCopy,
744    },
745    CopyTextureToTexture {
746        src: glow::Texture,
747        src_target: BindTarget,
748        dst: glow::Texture,
749        dst_target: BindTarget,
750        copy: crate::TextureCopy,
751        dst_is_cubemap: bool,
752    },
753    CopyBufferToTexture {
754        src: Buffer,
755        #[allow(unused)]
756        src_target: BindTarget,
757        dst: glow::Texture,
758        dst_target: BindTarget,
759        dst_format: wgt::TextureFormat,
760        copy: crate::BufferTextureCopy,
761    },
762    CopyTextureToBuffer {
763        src: glow::Texture,
764        src_target: BindTarget,
765        src_format: wgt::TextureFormat,
766        dst: Buffer,
767        #[allow(unused)]
768        dst_target: BindTarget,
769        copy: crate::BufferTextureCopy,
770    },
771    SetIndexBuffer(glow::Buffer),
772    BeginQuery(glow::Query, BindTarget),
773    EndQuery(BindTarget),
774    CopyQueryResults {
775        query_range: Range<u32>,
776        dst: Buffer,
777        dst_target: BindTarget,
778        dst_offset: wgt::BufferAddress,
779    },
780    ResetFramebuffer {
781        is_default: bool,
782    },
783    BindAttachment {
784        attachment: u32,
785        view: TextureView,
786    },
787    ResolveAttachment {
788        attachment: u32,
789        dst: TextureView,
790        size: wgt::Extent3d,
791    },
792    InvalidateAttachments(InvalidatedAttachments),
793    SetDrawColorBuffers(u8),
794    ClearColorF {
795        draw_buffer: u32,
796        color: [f32; 4],
797        is_srgb: bool,
798    },
799    ClearColorU(u32, [u32; 4]),
800    ClearColorI(u32, [i32; 4]),
801    ClearDepth(f32),
802    ClearStencil(u32),
803    // Clearing both the depth and stencil buffer individually appears to
804    // result in the stencil buffer failing to clear, atleast in WebGL.
805    // It is also more efficient to emit a single command instead of two for
806    // this.
807    ClearDepthAndStencil(f32, u32),
808    BufferBarrier(glow::Buffer, crate::BufferUses),
809    TextureBarrier(crate::TextureUses),
810    SetViewport {
811        rect: crate::Rect<i32>,
812        depth: Range<f32>,
813    },
814    SetScissor(crate::Rect<i32>),
815    SetStencilFunc {
816        face: u32,
817        function: u32,
818        reference: u32,
819        read_mask: u32,
820    },
821    SetStencilOps {
822        face: u32,
823        write_mask: u32,
824        ops: StencilOps,
825    },
826    SetDepth(DepthState),
827    SetDepthBias(wgt::DepthBiasState),
828    ConfigureDepthStencil(crate::FormatAspects),
829    SetAlphaToCoverage(bool),
830    SetVertexAttribute {
831        buffer: Option<glow::Buffer>,
832        buffer_desc: VertexBufferDesc,
833        attribute_desc: AttributeDesc,
834    },
835    UnsetVertexAttribute(u32),
836    SetVertexBuffer {
837        index: u32,
838        buffer: BufferBinding,
839        buffer_desc: VertexBufferDesc,
840    },
841    SetProgram(glow::Program),
842    SetPrimitive(PrimitiveState),
843    SetBlendConstant([f32; 4]),
844    SetColorTarget {
845        draw_buffer_index: Option<u32>,
846        desc: ColorTargetDesc,
847    },
848    BindBuffer {
849        target: BindTarget,
850        slot: u32,
851        buffer: glow::Buffer,
852        offset: i32,
853        size: i32,
854    },
855    BindSampler(u32, Option<glow::Sampler>),
856    BindTexture {
857        slot: u32,
858        texture: glow::Texture,
859        target: BindTarget,
860        aspects: crate::FormatAspects,
861    },
862    BindImage {
863        slot: u32,
864        binding: ImageBinding,
865    },
866    InsertDebugMarker(Range<u32>),
867    PushDebugGroup(Range<u32>),
868    PopDebugGroup,
869    SetPushConstants {
870        uniform: UniformDesc,
871        /// Offset from the start of the `data_bytes`
872        offset: u32,
873    },
874}
875
876#[derive(Default)]
877pub struct CommandBuffer {
878    label: Option<String>,
879    commands: Vec<Command>,
880    data_bytes: Vec<u8>,
881    queries: Vec<glow::Query>,
882}
883
884impl fmt::Debug for CommandBuffer {
885    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
886        let mut builder = f.debug_struct("CommandBuffer");
887        if let Some(ref label) = self.label {
888            builder.field("label", label);
889        }
890        builder.finish()
891    }
892}
893
894//TODO: we would have something like `Arc<typed_arena::Arena>`
895// here and in the command buffers. So that everything grows
896// inside the encoder and stays there until `reset_all`.
897
898pub struct CommandEncoder {
899    cmd_buffer: CommandBuffer,
900    state: command::State,
901    private_caps: PrivateCapabilities,
902}
903
904impl fmt::Debug for CommandEncoder {
905    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906        f.debug_struct("CommandEncoder")
907            .field("cmd_buffer", &self.cmd_buffer)
908            .finish()
909    }
910}