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