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