Skip to main content

pebble/graphics/types/
pipeline_state.rs

1use crate::graphics::types::{
2    BlendFactor, BlendOperation, CompareFunction, StencilOperation, TextureFormat, VertexFormat, VertexStepMode,
3    flags::ColorWrites,
4};
5
6/// One field within a vertex — its format, byte offset, and `@location` in
7/// the shader.
8#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
9pub struct VertexAttribute {
10    pub format: VertexFormat,
11    pub offset: u64,
12    pub shader_location: u32,
13}
14
15impl From<VertexAttribute> for wgpu::VertexAttribute {
16    fn from(attr: VertexAttribute) -> Self {
17        Self {
18            format: attr.format.into(),
19            offset: attr.offset,
20            shader_location: attr.shader_location,
21        }
22    }
23}
24
25/// One vertex buffer's layout — stride, step mode, and its [`VertexAttribute`]s.
26/// Usually built by a vertex type's own `layout()` method (e.g. [`Vertex::layout`](crate::graphics::pipeline::mesh::Vertex::layout))
27/// rather than by hand.
28#[derive(Clone, Debug, PartialEq)]
29pub struct VertexBufferLayout {
30    pub array_stride: u64,
31    pub step_mode: VertexStepMode,
32    pub attributes: Vec<VertexAttribute>,
33}
34
35/// How one channel (color or alpha) blends — src/dst factors plus the
36/// combining operation. [`REPLACE`](Self::REPLACE)/[`OVER`](Self::OVER) cover the common cases.
37#[derive(Copy, Clone, PartialEq, Eq, Hash)]
38pub struct BlendComponent {
39    pub src_factor: BlendFactor,
40    pub dst_factor: BlendFactor,
41    pub operation: BlendOperation,
42}
43
44impl BlendComponent {
45    pub const REPLACE: Self = Self {
46        src_factor: BlendFactor::One,
47        dst_factor: BlendFactor::Zero,
48        operation: BlendOperation::Add,
49    };
50
51    pub const OVER: Self = Self {
52        src_factor: BlendFactor::One,
53        dst_factor: BlendFactor::OneMinusSrcAlpha,
54        operation: BlendOperation::Add,
55    };
56}
57
58impl From<BlendComponent> for wgpu::BlendComponent {
59    fn from(value: BlendComponent) -> Self {
60        Self {
61            src_factor: value.src_factor.into(),
62            dst_factor: value.dst_factor.into(),
63            operation: value.operation.into(),
64        }
65    }
66}
67
68/// Color + alpha blending for one [`ColorTargetState`]. Presets:
69/// [`REPLACE`](Self::REPLACE) (no blending), [`ALPHA_BLENDING`](Self::ALPHA_BLENDING),
70/// [`PREMULTIPLIED_ALPHA_BLENDING`](Self::PREMULTIPLIED_ALPHA_BLENDING).
71#[derive(Copy, Clone, PartialEq, Eq, Hash)]
72pub struct BlendState {
73    pub color: BlendComponent,
74    pub alpha: BlendComponent,
75}
76
77impl BlendState {
78    pub const REPLACE: Self = Self { color: BlendComponent::REPLACE, alpha: BlendComponent::REPLACE };
79
80    pub const ALPHA_BLENDING: Self = Self {
81        color: BlendComponent {
82            src_factor: BlendFactor::SrcAlpha,
83            dst_factor: BlendFactor::OneMinusSrcAlpha,
84            operation: BlendOperation::Add,
85        },
86        alpha: BlendComponent::OVER,
87    };
88
89    pub const PREMULTIPLIED_ALPHA_BLENDING: Self =
90        Self { color: BlendComponent::OVER, alpha: BlendComponent::OVER };
91}
92
93impl From<BlendState> for wgpu::BlendState {
94    fn from(value: BlendState) -> Self {
95        Self { color: value.color.into(), alpha: value.alpha.into() }
96    }
97}
98
99/// One color attachment's output format, blend mode, and write mask —
100/// passed to [`Material::with_targets`](crate::graphics::pipeline::material::Material::with_targets).
101#[derive(Clone, PartialEq, Eq, Hash)]
102pub struct ColorTargetState {
103    pub format: TextureFormat,
104    pub blend: Option<BlendState>,
105    pub write_mask: ColorWrites,
106}
107
108impl From<ColorTargetState> for wgpu::ColorTargetState {
109    fn from(value: ColorTargetState) -> Self {
110        Self {
111            format: value.format.into(),
112            blend: value.blend.map(Into::into),
113            write_mask: value.write_mask.into(),
114        }
115    }
116}
117
118/// A single opaque `Rgba8Unorm` target with no blending — a reasonable
119/// default for [`Material::with_targets`](crate::graphics::pipeline::material::Material::with_targets).
120pub const DEFAULT_TARGET: [ColorTargetState; 1] = [ColorTargetState {
121    format: TextureFormat::Rgba8Unorm,
122    blend: None,
123    write_mask: ColorWrites::ALL,
124}];
125
126/// Stencil test/write behavior for one face — see [`StencilState`]. Defaults
127/// to [`IGNORE`](Self::IGNORE) (stencil test always passes, no writes).
128#[derive(Copy, Clone, PartialEq, Eq, Hash)]
129pub struct StencilFaceState {
130    pub compare: CompareFunction,
131    pub fail_op: StencilOperation,
132    pub depth_fail_op: StencilOperation,
133    pub pass_op: StencilOperation,
134}
135
136impl StencilFaceState {
137    pub const IGNORE: Self = Self {
138        compare: CompareFunction::Always,
139        fail_op: StencilOperation::Keep,
140        depth_fail_op: StencilOperation::Keep,
141        pass_op: StencilOperation::Keep,
142    };
143}
144
145impl Default for StencilFaceState {
146    fn default() -> Self {
147        Self::IGNORE
148    }
149}
150
151impl From<StencilFaceState> for wgpu::StencilFaceState {
152    fn from(value: StencilFaceState) -> Self {
153        Self {
154            compare: value.compare.into(),
155            fail_op: value.fail_op.into(),
156            depth_fail_op: value.depth_fail_op.into(),
157            pass_op: value.pass_op.into(),
158        }
159    }
160}
161
162/// Front/back stencil face state plus read/write masks — part of [`DepthStencilState`].
163#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
164pub struct StencilState {
165    pub front: StencilFaceState,
166    pub back: StencilFaceState,
167    pub read_mask: u32,
168    pub write_mask: u32,
169}
170
171impl From<StencilState> for wgpu::StencilState {
172    fn from(value: StencilState) -> Self {
173        Self {
174            front: value.front.into(),
175            back: value.back.into(),
176            read_mask: value.read_mask,
177            write_mask: value.write_mask,
178        }
179    }
180}
181
182/// Depth bias ("polygon offset") — nudges depth values to avoid z-fighting,
183/// e.g. for shadow-acne mitigation. Part of [`DepthStencilState`].
184#[derive(Copy, Clone, PartialEq, Default)]
185pub struct DepthBiasState {
186    pub constant: i32,
187    pub slope_scale: f32,
188    pub clamp: f32,
189}
190
191impl From<DepthBiasState> for wgpu::DepthBiasState {
192    fn from(value: DepthBiasState) -> Self {
193        Self { constant: value.constant, slope_scale: value.slope_scale, clamp: value.clamp }
194    }
195}
196
197/// Depth/stencil buffer state for a pipeline — passed to
198/// [`Material::with_depth`](crate::graphics::pipeline::material::Material::with_depth).
199#[derive(Clone, PartialEq)]
200pub struct DepthStencilState {
201    pub format: TextureFormat,
202    pub depth_write_enabled: Option<bool>,
203    pub depth_compare: Option<CompareFunction>,
204    pub stencil: StencilState,
205    pub bias: DepthBiasState,
206}
207
208impl From<DepthStencilState> for wgpu::DepthStencilState {
209    fn from(value: DepthStencilState) -> Self {
210        Self {
211            format: value.format.into(),
212            depth_write_enabled: value.depth_write_enabled,
213            depth_compare: value.depth_compare.map(Into::into),
214            stencil: value.stencil.into(),
215            bias: value.bias.into(),
216        }
217    }
218}