wgpu_types/
render.rs

1//! Types for configuring render passes and render pipelines (except for vertex attributes).
2
3use bytemuck::{Pod, Zeroable};
4
5#[cfg(any(feature = "serde", test))]
6use serde::{Deserialize, Serialize};
7
8use crate::{link_to_wgpu_docs, LoadOpDontCare};
9
10#[cfg(doc)]
11use crate::{Features, TextureFormat};
12
13/// Alpha blend factor.
14///
15/// Corresponds to [WebGPU `GPUBlendFactor`](
16/// https://gpuweb.github.io/gpuweb/#enumdef-gpublendfactor). Values using `Src1`
17/// require [`Features::DUAL_SOURCE_BLENDING`] and can only be used with the first
18/// render target.
19///
20/// For further details on how the blend factors are applied, see the analogous
21/// functionality in OpenGL: <https://www.khronos.org/opengl/wiki/Blending#Blending_Parameters>.
22#[repr(C)]
23#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
26pub enum BlendFactor {
27    /// 0.0
28    Zero = 0,
29    /// 1.0
30    One = 1,
31    /// S.component
32    Src = 2,
33    /// 1.0 - S.component
34    OneMinusSrc = 3,
35    /// S.alpha
36    SrcAlpha = 4,
37    /// 1.0 - S.alpha
38    OneMinusSrcAlpha = 5,
39    /// D.component
40    Dst = 6,
41    /// 1.0 - D.component
42    OneMinusDst = 7,
43    /// D.alpha
44    DstAlpha = 8,
45    /// 1.0 - D.alpha
46    OneMinusDstAlpha = 9,
47    /// min(S.alpha, 1.0 - D.alpha)
48    SrcAlphaSaturated = 10,
49    /// Constant
50    Constant = 11,
51    /// 1.0 - Constant
52    OneMinusConstant = 12,
53    /// S1.component
54    Src1 = 13,
55    /// 1.0 - S1.component
56    OneMinusSrc1 = 14,
57    /// S1.alpha
58    Src1Alpha = 15,
59    /// 1.0 - S1.alpha
60    OneMinusSrc1Alpha = 16,
61}
62
63impl BlendFactor {
64    /// Returns `true` if the blend factor references the second blend source.
65    ///
66    /// Note that the usage of those blend factors require [`Features::DUAL_SOURCE_BLENDING`].
67    #[must_use]
68    pub fn ref_second_blend_source(&self) -> bool {
69        match self {
70            BlendFactor::Src1
71            | BlendFactor::OneMinusSrc1
72            | BlendFactor::Src1Alpha
73            | BlendFactor::OneMinusSrc1Alpha => true,
74            _ => false,
75        }
76    }
77}
78
79/// Alpha blend operation.
80///
81/// Corresponds to [WebGPU `GPUBlendOperation`](
82/// https://gpuweb.github.io/gpuweb/#enumdef-gpublendoperation).
83///
84/// For further details on how the blend operations are applied, see
85/// the analogous functionality in OpenGL: <https://www.khronos.org/opengl/wiki/Blending#Blend_Equations>.
86#[repr(C)]
87#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
88#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
89#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
90pub enum BlendOperation {
91    /// Src + Dst
92    #[default]
93    Add = 0,
94    /// Src - Dst
95    Subtract = 1,
96    /// Dst - Src
97    ReverseSubtract = 2,
98    /// min(Src, Dst)
99    Min = 3,
100    /// max(Src, Dst)
101    Max = 4,
102}
103
104/// Describes a blend component of a [`BlendState`].
105///
106/// Corresponds to [WebGPU `GPUBlendComponent`](
107/// https://gpuweb.github.io/gpuweb/#dictdef-gpublendcomponent).
108#[repr(C)]
109#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
110#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
111#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
112pub struct BlendComponent {
113    /// Multiplier for the source, which is produced by the fragment shader.
114    pub src_factor: BlendFactor,
115    /// Multiplier for the destination, which is stored in the target.
116    pub dst_factor: BlendFactor,
117    /// The binary operation applied to the source and destination,
118    /// multiplied by their respective factors.
119    pub operation: BlendOperation,
120}
121
122impl BlendComponent {
123    /// Default blending state that replaces destination with the source.
124    pub const REPLACE: Self = Self {
125        src_factor: BlendFactor::One,
126        dst_factor: BlendFactor::Zero,
127        operation: BlendOperation::Add,
128    };
129
130    /// Blend state of `(1 * src) + ((1 - src_alpha) * dst)`.
131    pub const OVER: Self = Self {
132        src_factor: BlendFactor::One,
133        dst_factor: BlendFactor::OneMinusSrcAlpha,
134        operation: BlendOperation::Add,
135    };
136
137    /// Returns true if the state relies on the constant color, which is
138    /// set independently on a render command encoder.
139    #[must_use]
140    pub fn uses_constant(&self) -> bool {
141        match (self.src_factor, self.dst_factor) {
142            (BlendFactor::Constant, _)
143            | (BlendFactor::OneMinusConstant, _)
144            | (_, BlendFactor::Constant)
145            | (_, BlendFactor::OneMinusConstant) => true,
146            (_, _) => false,
147        }
148    }
149}
150
151impl Default for BlendComponent {
152    fn default() -> Self {
153        Self::REPLACE
154    }
155}
156
157/// Describe the blend state of a render pipeline,
158/// within [`ColorTargetState`].
159///
160/// Corresponds to [WebGPU `GPUBlendState`](
161/// https://gpuweb.github.io/gpuweb/#dictdef-gpublendstate).
162#[repr(C)]
163#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
164#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
165#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
166pub struct BlendState {
167    /// Color equation.
168    pub color: BlendComponent,
169    /// Alpha equation.
170    pub alpha: BlendComponent,
171}
172
173impl BlendState {
174    /// Blend mode that does no color blending, just overwrites the output with the contents of the shader.
175    pub const REPLACE: Self = Self {
176        color: BlendComponent::REPLACE,
177        alpha: BlendComponent::REPLACE,
178    };
179
180    /// Blend mode that does standard alpha blending with non-premultiplied alpha.
181    pub const ALPHA_BLENDING: Self = Self {
182        color: BlendComponent {
183            src_factor: BlendFactor::SrcAlpha,
184            dst_factor: BlendFactor::OneMinusSrcAlpha,
185            operation: BlendOperation::Add,
186        },
187        alpha: BlendComponent::OVER,
188    };
189
190    /// Blend mode that does standard alpha blending with premultiplied alpha.
191    pub const PREMULTIPLIED_ALPHA_BLENDING: Self = Self {
192        color: BlendComponent::OVER,
193        alpha: BlendComponent::OVER,
194    };
195
196    /// Blend mode that does standard additive blending.
197    pub const ADDITIVE: Self = Self {
198        color: BlendComponent {
199            src_factor: BlendFactor::One,
200            dst_factor: BlendFactor::One,
201            operation: BlendOperation::Add,
202        },
203        alpha: BlendComponent {
204            src_factor: BlendFactor::One,
205            dst_factor: BlendFactor::One,
206            operation: BlendOperation::Add,
207        },
208    };
209}
210
211/// Describes the color state of a render pipeline.
212///
213/// Corresponds to [WebGPU `GPUColorTargetState`](
214/// https://gpuweb.github.io/gpuweb/#dictdef-gpucolortargetstate).
215#[repr(C)]
216#[derive(Clone, Debug, PartialEq, Eq, Hash)]
217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
218#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
219pub struct ColorTargetState {
220    /// The [`TextureFormat`] of the image that this pipeline will render to. Must match the format
221    /// of the corresponding color attachment in [`CommandEncoder::begin_render_pass`][CEbrp]
222    ///
223    #[doc = link_to_wgpu_docs!(["CEbrp"]: "struct.CommandEncoder.html#method.begin_render_pass")]
224    pub format: crate::TextureFormat,
225    /// The blending that is used for this pipeline.
226    #[cfg_attr(feature = "serde", serde(default))]
227    pub blend: Option<BlendState>,
228    /// Mask which enables/disables writes to different color/alpha channel.
229    #[cfg_attr(feature = "serde", serde(default))]
230    pub write_mask: ColorWrites,
231}
232
233impl From<crate::TextureFormat> for ColorTargetState {
234    fn from(format: crate::TextureFormat) -> Self {
235        Self {
236            format,
237            blend: None,
238            write_mask: ColorWrites::ALL,
239        }
240    }
241}
242
243/// Color write mask. Disabled color channels will not be written to.
244///
245/// Corresponds to [WebGPU `GPUColorWriteFlags`](
246/// https://gpuweb.github.io/gpuweb/#typedefdef-gpucolorwriteflags).
247#[repr(transparent)]
248#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
249#[cfg_attr(feature = "serde", serde(transparent))]
250#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
251pub struct ColorWrites(u32);
252
253bitflags::bitflags! {
254    impl ColorWrites: u32 {
255        /// Enable red channel writes
256        const RED = 1 << 0;
257        /// Enable green channel writes
258        const GREEN = 1 << 1;
259        /// Enable blue channel writes
260        const BLUE = 1 << 2;
261        /// Enable alpha channel writes
262        const ALPHA = 1 << 3;
263        /// Enable red, green, and blue channel writes
264        const COLOR = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits();
265        /// Enable writes to all channels.
266        const ALL = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits() | Self::ALPHA.bits();
267    }
268}
269
270impl Default for ColorWrites {
271    fn default() -> Self {
272        Self::ALL
273    }
274}
275
276/// Primitive type the input mesh is composed of.
277///
278/// Corresponds to [WebGPU `GPUPrimitiveTopology`](
279/// https://gpuweb.github.io/gpuweb/#enumdef-gpuprimitivetopology).
280#[repr(C)]
281#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
282#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
283#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
284pub enum PrimitiveTopology {
285    /// Vertex data is a list of points. Each vertex is a new point.
286    PointList = 0,
287    /// Vertex data is a list of lines. Each pair of vertices composes a new line.
288    ///
289    /// Vertices `0 1 2 3` create two lines `0 1` and `2 3`
290    LineList = 1,
291    /// Vertex data is a strip of lines. Each set of two adjacent vertices form a line.
292    ///
293    /// Vertices `0 1 2 3` create three lines `0 1`, `1 2`, and `2 3`.
294    LineStrip = 2,
295    /// Vertex data is a list of triangles. Each set of 3 vertices composes a new triangle.
296    ///
297    /// Vertices `0 1 2 3 4 5` create two triangles `0 1 2` and `3 4 5`
298    #[default]
299    TriangleList = 3,
300    /// Vertex data is a triangle strip. Each set of three adjacent vertices form a triangle.
301    ///
302    /// Vertices `0 1 2 3 4 5` create four triangles `0 1 2`, `2 1 3`, `2 3 4`, and `4 3 5`
303    TriangleStrip = 4,
304}
305
306impl PrimitiveTopology {
307    /// Returns true for strip topologies.
308    #[must_use]
309    pub fn is_strip(&self) -> bool {
310        match *self {
311            Self::PointList | Self::LineList | Self::TriangleList => false,
312            Self::LineStrip | Self::TriangleStrip => true,
313        }
314    }
315
316    /// Returns true for triangle topologies.
317    #[must_use]
318    pub fn is_triangles(&self) -> bool {
319        match *self {
320            Self::TriangleList | Self::TriangleStrip => true,
321            Self::PointList | Self::LineList | Self::LineStrip => false,
322        }
323    }
324}
325
326/// Vertex winding order which classifies the "front" face of a triangle.
327///
328/// Corresponds to [WebGPU `GPUFrontFace`](
329/// https://gpuweb.github.io/gpuweb/#enumdef-gpufrontface).
330#[repr(C)]
331#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
332#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
333#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
334pub enum FrontFace {
335    /// Triangles with vertices in counter clockwise order are considered the front face.
336    ///
337    /// This is the default with right handed coordinate spaces.
338    #[default]
339    Ccw = 0,
340    /// Triangles with vertices in clockwise order are considered the front face.
341    ///
342    /// This is the default with left handed coordinate spaces.
343    Cw = 1,
344}
345
346/// Face of a vertex.
347///
348/// Corresponds to [WebGPU `GPUCullMode`](
349/// https://gpuweb.github.io/gpuweb/#enumdef-gpucullmode),
350/// except that the `"none"` value is represented using `Option<Face>` instead.
351#[repr(C)]
352#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
354#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
355pub enum Face {
356    /// Front face
357    Front = 0,
358    /// Back face
359    Back = 1,
360}
361
362/// Type of drawing mode for polygons
363#[repr(C)]
364#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
365#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
366#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
367pub enum PolygonMode {
368    /// Polygons are filled
369    #[default]
370    Fill = 0,
371    /// Polygons are drawn as line segments
372    Line = 1,
373    /// Polygons are drawn as points
374    Point = 2,
375}
376
377/// Describes the state of primitive assembly and rasterization in a render pipeline.
378///
379/// Corresponds to [WebGPU `GPUPrimitiveState`](
380/// https://gpuweb.github.io/gpuweb/#dictdef-gpuprimitivestate).
381#[repr(C)]
382#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
383#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
384#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
385pub struct PrimitiveState {
386    /// The primitive topology used to interpret vertices.
387    pub topology: PrimitiveTopology,
388    /// When drawing strip topologies with indices, this is the required format for the index buffer.
389    /// This has no effect on non-indexed or non-strip draws.
390    ///
391    /// This is required for indexed drawing with strip topology and must match index buffer format, as primitive restart is always enabled
392    /// in all backends and individual strips will be separated
393    /// with the index value `0xFFFF` when using `Uint16`, or `0xFFFFFFFF` when using `Uint32`.
394    #[cfg_attr(feature = "serde", serde(default))]
395    pub strip_index_format: Option<IndexFormat>,
396    /// The face to consider the front for the purpose of culling and stencil operations.
397    #[cfg_attr(feature = "serde", serde(default))]
398    pub front_face: FrontFace,
399    /// The face culling mode.
400    #[cfg_attr(feature = "serde", serde(default))]
401    pub cull_mode: Option<Face>,
402    /// If set to true, the polygon depth is not clipped to 0-1 before rasterization.
403    ///
404    /// Enabling this requires [`Features::DEPTH_CLIP_CONTROL`] to be enabled.
405    #[cfg_attr(feature = "serde", serde(default))]
406    pub unclipped_depth: bool,
407    /// Controls the way each polygon is rasterized. Can be either `Fill` (default), `Line` or `Point`
408    ///
409    /// Setting this to `Line` requires [`Features::POLYGON_MODE_LINE`] to be enabled.
410    ///
411    /// Setting this to `Point` requires [`Features::POLYGON_MODE_POINT`] to be enabled.
412    #[cfg_attr(feature = "serde", serde(default))]
413    pub polygon_mode: PolygonMode,
414    /// If set to true, the primitives are rendered with conservative overestimation. I.e. any rastered pixel touched by it is filled.
415    /// Only valid for `[PolygonMode::Fill`]!
416    ///
417    /// Enabling this requires [`Features::CONSERVATIVE_RASTERIZATION`] to be enabled.
418    pub conservative: bool,
419}
420
421/// Describes the multi-sampling state of a render pipeline.
422///
423/// Corresponds to [WebGPU `GPUMultisampleState`](
424/// https://gpuweb.github.io/gpuweb/#dictdef-gpumultisamplestate).
425#[repr(C)]
426#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
427#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
428#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
429pub struct MultisampleState {
430    /// The number of samples calculated per pixel (for MSAA). For non-multisampled textures,
431    /// this should be `1`
432    pub count: u32,
433    /// Bitmask that restricts the samples of a pixel modified by this pipeline. All samples
434    /// can be enabled using the value `!0`
435    pub mask: u64,
436    /// When enabled, produces another sample mask per pixel based on the alpha output value, that
437    /// is ANDed with the sample mask and the primitive coverage to restrict the set of samples
438    /// affected by a primitive.
439    ///
440    /// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one
441    /// is guaranteed to be all 1-s.
442    pub alpha_to_coverage_enabled: bool,
443}
444
445impl Default for MultisampleState {
446    fn default() -> Self {
447        MultisampleState {
448            count: 1,
449            mask: !0,
450            alpha_to_coverage_enabled: false,
451        }
452    }
453}
454
455/// Format of indices used with pipeline.
456///
457/// Corresponds to [WebGPU `GPUIndexFormat`](
458/// https://gpuweb.github.io/gpuweb/#enumdef-gpuindexformat).
459#[repr(C)]
460#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
461#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
462#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
463pub enum IndexFormat {
464    /// Indices are 16 bit unsigned integers.
465    Uint16 = 0,
466    /// Indices are 32 bit unsigned integers.
467    #[default]
468    Uint32 = 1,
469}
470
471impl IndexFormat {
472    /// Returns the size in bytes of the index format
473    pub fn byte_size(&self) -> usize {
474        match self {
475            IndexFormat::Uint16 => 2,
476            IndexFormat::Uint32 => 4,
477        }
478    }
479}
480
481/// Operation to perform on the stencil value.
482///
483/// Corresponds to [WebGPU `GPUStencilOperation`](
484/// https://gpuweb.github.io/gpuweb/#enumdef-gpustenciloperation).
485#[repr(C)]
486#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
487#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
488#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
489pub enum StencilOperation {
490    /// Keep stencil value unchanged.
491    #[default]
492    Keep = 0,
493    /// Set stencil value to zero.
494    Zero = 1,
495    /// Replace stencil value with value provided in most recent call to
496    /// [`RenderPass::set_stencil_reference`][RPssr].
497    ///
498    #[doc = link_to_wgpu_docs!(["RPssr"]: "struct.RenderPass.html#method.set_stencil_reference")]
499    Replace = 2,
500    /// Bitwise inverts stencil value.
501    Invert = 3,
502    /// Increments stencil value by one, clamping on overflow.
503    IncrementClamp = 4,
504    /// Decrements stencil value by one, clamping on underflow.
505    DecrementClamp = 5,
506    /// Increments stencil value by one, wrapping on overflow.
507    IncrementWrap = 6,
508    /// Decrements stencil value by one, wrapping on underflow.
509    DecrementWrap = 7,
510}
511
512/// Describes stencil state in a render pipeline.
513///
514/// If you are not using stencil state, set this to [`StencilFaceState::IGNORE`].
515///
516/// Corresponds to [WebGPU `GPUStencilFaceState`](
517/// https://gpuweb.github.io/gpuweb/#dictdef-gpustencilfacestate).
518#[repr(C)]
519#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
520#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
521#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
522pub struct StencilFaceState {
523    /// Comparison function that determines if the fail_op or pass_op is used on the stencil buffer.
524    pub compare: CompareFunction,
525    /// Operation that is performed when stencil test fails.
526    pub fail_op: StencilOperation,
527    /// Operation that is performed when depth test fails but stencil test succeeds.
528    pub depth_fail_op: StencilOperation,
529    /// Operation that is performed when stencil test success.
530    pub pass_op: StencilOperation,
531}
532
533impl StencilFaceState {
534    /// Ignore the stencil state for the face.
535    pub const IGNORE: Self = StencilFaceState {
536        compare: CompareFunction::Always,
537        fail_op: StencilOperation::Keep,
538        depth_fail_op: StencilOperation::Keep,
539        pass_op: StencilOperation::Keep,
540    };
541
542    /// Returns true if the face state uses the reference value for testing or operation.
543    #[must_use]
544    pub fn needs_ref_value(&self) -> bool {
545        self.compare.needs_ref_value()
546            || self.fail_op == StencilOperation::Replace
547            || self.depth_fail_op == StencilOperation::Replace
548            || self.pass_op == StencilOperation::Replace
549    }
550
551    /// Returns true if the face state doesn't mutate the target values.
552    #[must_use]
553    pub fn is_read_only(&self) -> bool {
554        self.pass_op == StencilOperation::Keep
555            && self.depth_fail_op == StencilOperation::Keep
556            && self.fail_op == StencilOperation::Keep
557    }
558}
559
560impl Default for StencilFaceState {
561    fn default() -> Self {
562        Self::IGNORE
563    }
564}
565
566/// Comparison function used for depth and stencil operations.
567///
568/// Corresponds to [WebGPU `GPUCompareFunction`](
569/// https://gpuweb.github.io/gpuweb/#enumdef-gpucomparefunction).
570#[repr(C)]
571#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
572#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
573#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
574pub enum CompareFunction {
575    /// Function never passes
576    Never = 1,
577    /// Function passes if new value less than existing value
578    Less = 2,
579    /// Function passes if new value is equal to existing value. When using
580    /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)`
581    /// output as `@invariant` to prevent artifacting.
582    Equal = 3,
583    /// Function passes if new value is less than or equal to existing value
584    LessEqual = 4,
585    /// Function passes if new value is greater than existing value
586    Greater = 5,
587    /// Function passes if new value is not equal to existing value. When using
588    /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)`
589    /// output as `@invariant` to prevent artifacting.
590    NotEqual = 6,
591    /// Function passes if new value is greater than or equal to existing value
592    GreaterEqual = 7,
593    /// Function always passes
594    #[default]
595    Always = 8,
596}
597
598impl CompareFunction {
599    /// Returns true if the comparison depends on the reference value.
600    #[must_use]
601    pub fn needs_ref_value(self) -> bool {
602        match self {
603            Self::Never | Self::Always => false,
604            _ => true,
605        }
606    }
607}
608
609/// State of the stencil operation (fixed-pipeline stage).
610///
611/// For use in [`DepthStencilState`].
612///
613/// Corresponds to a portion of [WebGPU `GPUDepthStencilState`](
614/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
615#[repr(C)]
616#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
617#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
618pub struct StencilState {
619    /// Front face mode.
620    pub front: StencilFaceState,
621    /// Back face mode.
622    pub back: StencilFaceState,
623    /// Stencil values are AND'd with this mask when reading and writing from the stencil buffer. Only low 8 bits are used.
624    pub read_mask: u32,
625    /// Stencil values are AND'd with this mask when writing to the stencil buffer. Only low 8 bits are used.
626    pub write_mask: u32,
627}
628
629impl StencilState {
630    /// Returns true if the stencil test is enabled.
631    #[must_use]
632    pub fn is_enabled(&self) -> bool {
633        (self.front != StencilFaceState::IGNORE || self.back != StencilFaceState::IGNORE)
634            && (self.read_mask != 0 || self.write_mask != 0)
635    }
636    /// Returns true if the state doesn't mutate the target values.
637    #[must_use]
638    pub fn is_read_only(&self, cull_mode: Option<Face>) -> bool {
639        // The rules are defined in step 7 of the "Device timeline initialization steps"
640        // subsection of the "Render Pipeline Creation" section of WebGPU
641        // (link to the section: https://gpuweb.github.io/gpuweb/#render-pipeline-creation)
642
643        if self.write_mask == 0 {
644            return true;
645        }
646
647        let front_ro = cull_mode == Some(Face::Front) || self.front.is_read_only();
648        let back_ro = cull_mode == Some(Face::Back) || self.back.is_read_only();
649
650        front_ro && back_ro
651    }
652    /// Returns true if the stencil state uses the reference value for testing.
653    #[must_use]
654    pub fn needs_ref_value(&self) -> bool {
655        self.front.needs_ref_value() || self.back.needs_ref_value()
656    }
657}
658
659/// Describes the biasing setting for the depth target.
660///
661/// For use in [`DepthStencilState`].
662///
663/// Corresponds to a portion of [WebGPU `GPUDepthStencilState`](
664/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
665#[repr(C)]
666#[derive(Clone, Copy, Debug, Default)]
667#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
668pub struct DepthBiasState {
669    /// Constant depth biasing factor, in basic units of the depth format.
670    pub constant: i32,
671    /// Slope depth biasing factor.
672    pub slope_scale: f32,
673    /// Depth bias clamp value (absolute).
674    pub clamp: f32,
675}
676
677impl DepthBiasState {
678    /// Returns true if the depth biasing is enabled.
679    #[must_use]
680    pub fn is_enabled(&self) -> bool {
681        self.constant != 0 || self.slope_scale != 0.0
682    }
683}
684
685impl core::hash::Hash for DepthBiasState {
686    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
687        self.constant.hash(state);
688        self.slope_scale.to_bits().hash(state);
689        self.clamp.to_bits().hash(state);
690    }
691}
692
693impl PartialEq for DepthBiasState {
694    fn eq(&self, other: &Self) -> bool {
695        (self.constant == other.constant)
696            && (self.slope_scale.to_bits() == other.slope_scale.to_bits())
697            && (self.clamp.to_bits() == other.clamp.to_bits())
698    }
699}
700
701impl Eq for DepthBiasState {}
702
703/// Operation to perform to the output attachment at the start of a render pass.
704///
705/// Corresponds to [WebGPU `GPULoadOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpuloadop),
706/// plus the corresponding clearValue.
707#[repr(u8)]
708#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
709#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
710#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
711pub enum LoadOp<V> {
712    /// Loads the specified value for this attachment into the render pass.
713    ///
714    /// On some GPU hardware (primarily mobile), "clear" is significantly cheaper
715    /// because it avoids loading data from main memory into tile-local memory.
716    ///
717    /// On other GPU hardware, there isn’t a significant difference.
718    ///
719    /// As a result, it is recommended to use "clear" rather than "load" in cases
720    /// where the initial value doesn’t matter
721    /// (e.g. the render target will be cleared using a skybox).
722    Clear(V) = 0,
723    /// Loads the existing value for this attachment into the render pass.
724    Load = 1,
725    /// The render target has undefined contents at the start of the render pass.
726    /// This may lead to undefined behavior if you read from the any of the
727    /// render target pixels without first writing to them.
728    ///
729    /// Blending also becomes undefined behavior if the source
730    /// pixels are undefined.
731    ///
732    /// This is the fastest option on all GPUs if you always overwrite all pixels
733    /// in the render target after this load operation.
734    ///
735    /// Backends that don't support `DontCare` internally, will pick a different (unspecified)
736    /// load op instead.
737    ///
738    /// # Safety
739    ///
740    /// - All pixels in the render target must be written to before
741    ///   any read or a [`StoreOp::Store`] occurs.
742    DontCare(#[cfg_attr(feature = "serde", serde(skip))] LoadOpDontCare) = 2,
743}
744
745impl<V> LoadOp<V> {
746    /// Returns true if variants are same (ignoring clear value)
747    pub fn eq_variant<T>(&self, other: LoadOp<T>) -> bool {
748        matches!(
749            (self, other),
750            (LoadOp::Clear(_), LoadOp::Clear(_))
751                | (LoadOp::Load, LoadOp::Load)
752                | (LoadOp::DontCare(_), LoadOp::DontCare(_))
753        )
754    }
755}
756
757impl<V: Default> Default for LoadOp<V> {
758    fn default() -> Self {
759        Self::Clear(Default::default())
760    }
761}
762
763/// Operation to perform to the output attachment at the end of a render pass.
764///
765/// Corresponds to [WebGPU `GPUStoreOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpustoreop).
766#[repr(C)]
767#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)]
768#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
769#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
770pub enum StoreOp {
771    /// Stores the resulting value of the render pass for this attachment.
772    #[default]
773    Store = 0,
774    /// Discards the resulting value of the render pass for this attachment.
775    ///
776    /// The attachment will be treated as uninitialized afterwards.
777    /// (If only either Depth or Stencil texture-aspects is set to `Discard`,
778    /// the respective other texture-aspect will be preserved.)
779    ///
780    /// This can be significantly faster on tile-based render hardware.
781    ///
782    /// Prefer this if the attachment is not read by subsequent passes.
783    Discard = 1,
784}
785
786/// Pair of load and store operations for an attachment aspect.
787///
788/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
789/// separate `loadOp` and `storeOp` fields are used instead.
790#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
791#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
792pub struct Operations<V> {
793    /// How data should be read through this attachment.
794    pub load: LoadOp<V>,
795    /// Whether data will be written to through this attachment.
796    ///
797    /// Note that resolve textures (if specified) are always written to,
798    /// regardless of this setting.
799    pub store: StoreOp,
800}
801
802impl<V: Default> Default for Operations<V> {
803    #[inline]
804    fn default() -> Self {
805        Self {
806            load: LoadOp::<V>::default(),
807            store: StoreOp::default(),
808        }
809    }
810}
811
812/// Describes the depth/stencil state in a render pipeline.
813///
814/// Corresponds to [WebGPU `GPUDepthStencilState`](
815/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
816#[repr(C)]
817#[derive(Clone, Debug, Hash, PartialEq, Eq)]
818#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
819pub struct DepthStencilState {
820    /// Format of the depth/stencil buffer, must be special depth format. Must match the format
821    /// of the depth/stencil attachment in [`CommandEncoder::begin_render_pass`][CEbrp].
822    ///
823    #[doc = link_to_wgpu_docs!(["CEbrp"]: "struct.CommandEncoder.html#method.begin_render_pass")]
824    pub format: crate::TextureFormat,
825    /// Whether to write updated depth values to the depth attachment.
826    ///
827    /// If `format` is a depth or depth/stencil format, then this must be `Some`.
828    /// Otherwise, specifying `None` is preferred, but `Some(false)` is also
829    /// accepted.
830    pub depth_write_enabled: Option<bool>,
831    /// Comparison function used to compare depth values in the depth test.
832    ///
833    /// If `depth_write_enabled` is `Some(true)` or if `depth_fail_op` for either
834    /// stencil face is not `Keep`, then this must be `Some`. Otherwise, specifying
835    /// `None` is preferred, but `Some(CompareFunction::Always)` is also accepted.
836    pub depth_compare: Option<CompareFunction>,
837    /// Stencil state.
838    #[cfg_attr(feature = "serde", serde(default))]
839    pub stencil: StencilState,
840    /// Depth bias state.
841    #[cfg_attr(feature = "serde", serde(default))]
842    pub bias: DepthBiasState,
843}
844
845impl DepthStencilState {
846    /// Construct `DepthStencilState` for a stencil operation with no depth operation.
847    ///
848    /// Panics if `format` does not have a stencil aspect.
849    pub fn stencil(format: crate::TextureFormat, stencil: StencilState) -> DepthStencilState {
850        assert!(
851            format.has_stencil_aspect(),
852            "{format:?} is not a stencil format"
853        );
854        DepthStencilState {
855            format,
856            depth_write_enabled: None,
857            depth_compare: None,
858            stencil,
859            bias: DepthBiasState::default(),
860        }
861    }
862
863    /// Returns true if the depth testing is enabled.
864    #[must_use]
865    pub fn is_depth_enabled(&self) -> bool {
866        self.depth_compare.unwrap_or_default() != CompareFunction::Always
867            || self.depth_write_enabled.unwrap_or_default()
868    }
869
870    /// Returns true if the state doesn't mutate the depth buffer.
871    #[must_use]
872    pub fn is_depth_read_only(&self) -> bool {
873        !self.depth_write_enabled.unwrap_or_default()
874    }
875
876    /// Returns true if the state doesn't mutate the stencil.
877    #[must_use]
878    pub fn is_stencil_read_only(&self, cull_mode: Option<Face>) -> bool {
879        self.stencil.is_read_only(cull_mode)
880    }
881
882    /// Returns true if the state doesn't mutate either depth or stencil of the target.
883    #[must_use]
884    pub fn is_read_only(&self, cull_mode: Option<Face>) -> bool {
885        self.is_depth_read_only() && self.is_stencil_read_only(cull_mode)
886    }
887}
888
889/// Describes the depth/stencil attachment for render bundles.
890///
891/// Corresponds to a portion of [WebGPU `GPURenderBundleEncoderDescriptor`](
892/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor).
893#[repr(C)]
894#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
895#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
896pub struct RenderBundleDepthStencil {
897    /// Format of the attachment.
898    pub format: crate::TextureFormat,
899    /// If the depth aspect of the depth stencil attachment is going to be written to.
900    ///
901    /// This must match the [`RenderPassDepthStencilAttachment::depth_ops`] of the renderpass this render bundle is executed in.
902    /// If `depth_ops` is `Some(..)` this must be false. If it is `None` this must be true.
903    ///
904    #[doc = link_to_wgpu_docs!(["`RenderPassDepthStencilAttachment::depth_ops`"]: "struct.RenderPassDepthStencilAttachment.html#structfield.depth_ops")]
905    pub depth_read_only: bool,
906
907    /// If the stencil aspect of the depth stencil attachment is going to be written to.
908    ///
909    /// This must match the [`RenderPassDepthStencilAttachment::stencil_ops`] of the renderpass this render bundle is executed in.
910    /// If `depth_ops` is `Some(..)` this must be false. If it is `None` this must be true.
911    ///
912    #[doc = link_to_wgpu_docs!(["`RenderPassDepthStencilAttachment::stencil_ops`"]: "struct.RenderPassDepthStencilAttachment.html#structfield.stencil_ops")]
913    pub stencil_read_only: bool,
914}
915
916/// Describes a [`RenderBundle`](../wgpu/struct.RenderBundle.html).
917///
918/// Corresponds to [WebGPU `GPURenderBundleDescriptor`](
919/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundledescriptor).
920#[repr(C)]
921#[derive(Clone, Debug, PartialEq, Eq, Hash)]
922#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
923pub struct RenderBundleDescriptor<L> {
924    /// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification.
925    pub label: L,
926}
927
928impl<L> RenderBundleDescriptor<L> {
929    /// Takes a closure and maps the label of the render bundle descriptor into another.
930    #[must_use]
931    pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> RenderBundleDescriptor<K> {
932        RenderBundleDescriptor {
933            label: fun(&self.label),
934        }
935    }
936}
937
938impl<T> Default for RenderBundleDescriptor<Option<T>> {
939    fn default() -> Self {
940        Self { label: None }
941    }
942}
943
944/// Argument buffer layout for `draw_indirect` commands.
945#[repr(C)]
946#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
947pub struct DrawIndirectArgs {
948    /// The number of vertices to draw.
949    pub vertex_count: u32,
950    /// The number of instances to draw.
951    pub instance_count: u32,
952    /// The Index of the first vertex to draw.
953    pub first_vertex: u32,
954    /// The instance ID of the first instance to draw.
955    ///
956    /// Has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`](crate::Features::INDIRECT_FIRST_INSTANCE) is enabled.
957    pub first_instance: u32,
958}
959
960impl DrawIndirectArgs {
961    /// Returns the bytes representation of the struct, ready to be written in a buffer.
962    #[must_use]
963    pub fn as_bytes(&self) -> &[u8] {
964        bytemuck::bytes_of(self)
965    }
966}
967
968/// Argument buffer layout for `draw_indexed_indirect` commands.
969#[repr(C)]
970#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
971pub struct DrawIndexedIndirectArgs {
972    /// The number of indices to draw.
973    pub index_count: u32,
974    /// The number of instances to draw.
975    pub instance_count: u32,
976    /// The first index within the index buffer.
977    pub first_index: u32,
978    /// The value added to the vertex index before indexing into the vertex buffer.
979    pub base_vertex: i32,
980    /// The instance ID of the first instance to draw.
981    ///
982    /// Has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`](crate::Features::INDIRECT_FIRST_INSTANCE) is enabled.
983    pub first_instance: u32,
984}
985
986impl DrawIndexedIndirectArgs {
987    /// Returns the bytes representation of the struct, ready to be written in a buffer.
988    #[must_use]
989    pub fn as_bytes(&self) -> &[u8] {
990        bytemuck::bytes_of(self)
991    }
992}
993
994/// Argument buffer layout for `dispatch_workgroups_indirect` commands.
995#[repr(C)]
996#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
997pub struct DispatchIndirectArgs {
998    /// The number of work groups in X dimension.
999    pub x: u32,
1000    /// The number of work groups in Y dimension.
1001    pub y: u32,
1002    /// The number of work groups in Z dimension.
1003    pub z: u32,
1004}
1005
1006impl DispatchIndirectArgs {
1007    /// Returns the bytes representation of the struct, ready to be written into a buffer.
1008    #[must_use]
1009    pub fn as_bytes(&self) -> &[u8] {
1010        bytemuck::bytes_of(self)
1011    }
1012}