use bytemuck::{Pod, Zeroable};
#[cfg(any(feature = "serde", test))]
use serde::{Deserialize, Serialize};
use crate::{link_to_wgpu_docs, LoadOpDontCare};
#[cfg(doc)]
use crate::{Features, TextureFormat};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum BlendFactor {
Zero = 0,
One = 1,
Src = 2,
OneMinusSrc = 3,
SrcAlpha = 4,
OneMinusSrcAlpha = 5,
Dst = 6,
OneMinusDst = 7,
DstAlpha = 8,
OneMinusDstAlpha = 9,
SrcAlphaSaturated = 10,
Constant = 11,
OneMinusConstant = 12,
Src1 = 13,
OneMinusSrc1 = 14,
Src1Alpha = 15,
OneMinusSrc1Alpha = 16,
}
impl BlendFactor {
#[must_use]
pub fn ref_second_blend_source(&self) -> bool {
match self {
BlendFactor::Src1
| BlendFactor::OneMinusSrc1
| BlendFactor::Src1Alpha
| BlendFactor::OneMinusSrc1Alpha => true,
_ => false,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum BlendOperation {
#[default]
Add = 0,
Subtract = 1,
ReverseSubtract = 2,
Min = 3,
Max = 4,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct BlendComponent {
pub src_factor: BlendFactor,
pub dst_factor: BlendFactor,
pub operation: BlendOperation,
}
impl BlendComponent {
pub const REPLACE: Self = Self {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::Zero,
operation: BlendOperation::Add,
};
pub const OVER: Self = Self {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::OneMinusSrcAlpha,
operation: BlendOperation::Add,
};
#[must_use]
pub fn uses_constant(&self) -> bool {
match (self.src_factor, self.dst_factor) {
(BlendFactor::Constant, _)
| (BlendFactor::OneMinusConstant, _)
| (_, BlendFactor::Constant)
| (_, BlendFactor::OneMinusConstant) => true,
(_, _) => false,
}
}
}
impl Default for BlendComponent {
fn default() -> Self {
Self::REPLACE
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct BlendState {
pub color: BlendComponent,
pub alpha: BlendComponent,
}
impl BlendState {
pub const REPLACE: Self = Self {
color: BlendComponent::REPLACE,
alpha: BlendComponent::REPLACE,
};
pub const ALPHA_BLENDING: Self = Self {
color: BlendComponent {
src_factor: BlendFactor::SrcAlpha,
dst_factor: BlendFactor::OneMinusSrcAlpha,
operation: BlendOperation::Add,
},
alpha: BlendComponent::OVER,
};
pub const PREMULTIPLIED_ALPHA_BLENDING: Self = Self {
color: BlendComponent::OVER,
alpha: BlendComponent::OVER,
};
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct ColorTargetState {
#[doc = link_to_wgpu_docs!(["CEbrp"]: "struct.CommandEncoder.html#method.begin_render_pass")]
pub format: crate::TextureFormat,
#[cfg_attr(feature = "serde", serde(default))]
pub blend: Option<BlendState>,
#[cfg_attr(feature = "serde", serde(default))]
pub write_mask: ColorWrites,
}
impl From<crate::TextureFormat> for ColorTargetState {
fn from(format: crate::TextureFormat) -> Self {
Self {
format,
blend: None,
write_mask: ColorWrites::ALL,
}
}
}
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ColorWrites(u32);
bitflags::bitflags! {
impl ColorWrites: u32 {
const RED = 1 << 0;
const GREEN = 1 << 1;
const BLUE = 1 << 2;
const ALPHA = 1 << 3;
const COLOR = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits();
const ALL = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits() | Self::ALPHA.bits();
}
}
impl Default for ColorWrites {
fn default() -> Self {
Self::ALL
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PrimitiveTopology {
PointList = 0,
LineList = 1,
LineStrip = 2,
#[default]
TriangleList = 3,
TriangleStrip = 4,
}
impl PrimitiveTopology {
#[must_use]
pub fn is_strip(&self) -> bool {
match *self {
Self::PointList | Self::LineList | Self::TriangleList => false,
Self::LineStrip | Self::TriangleStrip => true,
}
}
#[must_use]
pub fn is_triangles(&self) -> bool {
match *self {
Self::TriangleList | Self::TriangleStrip => true,
Self::PointList | Self::LineList | Self::LineStrip => false,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum FrontFace {
#[default]
Ccw = 0,
Cw = 1,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum Face {
Front = 0,
Back = 1,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PolygonMode {
#[default]
Fill = 0,
Line = 1,
Point = 2,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct PrimitiveState {
pub topology: PrimitiveTopology,
#[cfg_attr(feature = "serde", serde(default))]
pub strip_index_format: Option<IndexFormat>,
#[cfg_attr(feature = "serde", serde(default))]
pub front_face: FrontFace,
#[cfg_attr(feature = "serde", serde(default))]
pub cull_mode: Option<Face>,
#[cfg_attr(feature = "serde", serde(default))]
pub unclipped_depth: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub polygon_mode: PolygonMode,
pub conservative: bool,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct MultisampleState {
pub count: u32,
pub mask: u64,
pub alpha_to_coverage_enabled: bool,
}
impl Default for MultisampleState {
fn default() -> Self {
MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum IndexFormat {
Uint16 = 0,
#[default]
Uint32 = 1,
}
impl IndexFormat {
pub fn byte_size(&self) -> usize {
match self {
IndexFormat::Uint16 => 2,
IndexFormat::Uint32 => 4,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum StencilOperation {
#[default]
Keep = 0,
Zero = 1,
#[doc = link_to_wgpu_docs!(["RPssr"]: "struct.RenderPass.html#method.set_stencil_reference")]
Replace = 2,
Invert = 3,
IncrementClamp = 4,
DecrementClamp = 5,
IncrementWrap = 6,
DecrementWrap = 7,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct StencilFaceState {
pub compare: CompareFunction,
pub fail_op: StencilOperation,
pub depth_fail_op: StencilOperation,
pub pass_op: StencilOperation,
}
impl StencilFaceState {
pub const IGNORE: Self = StencilFaceState {
compare: CompareFunction::Always,
fail_op: StencilOperation::Keep,
depth_fail_op: StencilOperation::Keep,
pass_op: StencilOperation::Keep,
};
#[must_use]
pub fn needs_ref_value(&self) -> bool {
self.compare.needs_ref_value()
|| self.fail_op == StencilOperation::Replace
|| self.depth_fail_op == StencilOperation::Replace
|| self.pass_op == StencilOperation::Replace
}
#[must_use]
pub fn is_read_only(&self) -> bool {
self.pass_op == StencilOperation::Keep
&& self.depth_fail_op == StencilOperation::Keep
&& self.fail_op == StencilOperation::Keep
}
}
impl Default for StencilFaceState {
fn default() -> Self {
Self::IGNORE
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum CompareFunction {
Never = 1,
Less = 2,
Equal = 3,
LessEqual = 4,
Greater = 5,
NotEqual = 6,
GreaterEqual = 7,
#[default]
Always = 8,
}
impl CompareFunction {
#[must_use]
pub fn needs_ref_value(self) -> bool {
match self {
Self::Never | Self::Always => false,
_ => true,
}
}
}
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StencilState {
pub front: StencilFaceState,
pub back: StencilFaceState,
pub read_mask: u32,
pub write_mask: u32,
}
impl StencilState {
#[must_use]
pub fn is_enabled(&self) -> bool {
(self.front != StencilFaceState::IGNORE || self.back != StencilFaceState::IGNORE)
&& (self.read_mask != 0 || self.write_mask != 0)
}
#[must_use]
pub fn is_read_only(&self, cull_mode: Option<Face>) -> bool {
if self.write_mask == 0 {
return true;
}
let front_ro = cull_mode == Some(Face::Front) || self.front.is_read_only();
let back_ro = cull_mode == Some(Face::Back) || self.back.is_read_only();
front_ro && back_ro
}
#[must_use]
pub fn needs_ref_value(&self) -> bool {
self.front.needs_ref_value() || self.back.needs_ref_value()
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DepthBiasState {
pub constant: i32,
pub slope_scale: f32,
pub clamp: f32,
}
impl DepthBiasState {
#[must_use]
pub fn is_enabled(&self) -> bool {
self.constant != 0 || self.slope_scale != 0.0
}
}
impl core::hash::Hash for DepthBiasState {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.constant.hash(state);
self.slope_scale.to_bits().hash(state);
self.clamp.to_bits().hash(state);
}
}
impl PartialEq for DepthBiasState {
fn eq(&self, other: &Self) -> bool {
(self.constant == other.constant)
&& (self.slope_scale.to_bits() == other.slope_scale.to_bits())
&& (self.clamp.to_bits() == other.clamp.to_bits())
}
}
impl Eq for DepthBiasState {}
#[repr(u8)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum LoadOp<V> {
Clear(V) = 0,
Load = 1,
DontCare(#[cfg_attr(feature = "serde", serde(skip))] LoadOpDontCare) = 2,
}
impl<V> LoadOp<V> {
pub fn eq_variant<T>(&self, other: LoadOp<T>) -> bool {
matches!(
(self, other),
(LoadOp::Clear(_), LoadOp::Clear(_))
| (LoadOp::Load, LoadOp::Load)
| (LoadOp::DontCare(_), LoadOp::DontCare(_))
)
}
}
impl<V: Default> Default for LoadOp<V> {
fn default() -> Self {
Self::Clear(Default::default())
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum StoreOp {
#[default]
Store = 0,
Discard = 1,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Operations<V> {
pub load: LoadOp<V>,
pub store: StoreOp,
}
impl<V: Default> Default for Operations<V> {
#[inline]
fn default() -> Self {
Self {
load: LoadOp::<V>::default(),
store: StoreOp::default(),
}
}
}
#[repr(C)]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DepthStencilState {
#[doc = link_to_wgpu_docs!(["CEbrp"]: "struct.CommandEncoder.html#method.begin_render_pass")]
pub format: crate::TextureFormat,
pub depth_write_enabled: Option<bool>,
pub depth_compare: Option<CompareFunction>,
#[cfg_attr(feature = "serde", serde(default))]
pub stencil: StencilState,
#[cfg_attr(feature = "serde", serde(default))]
pub bias: DepthBiasState,
}
impl DepthStencilState {
pub fn stencil(format: crate::TextureFormat, stencil: StencilState) -> DepthStencilState {
assert!(
format.has_stencil_aspect(),
"{format:?} is not a stencil format"
);
DepthStencilState {
format,
depth_write_enabled: None,
depth_compare: None,
stencil,
bias: DepthBiasState::default(),
}
}
#[must_use]
pub fn is_depth_enabled(&self) -> bool {
self.depth_compare.unwrap_or_default() != CompareFunction::Always
|| self.depth_write_enabled.unwrap_or_default()
}
#[must_use]
pub fn is_depth_read_only(&self) -> bool {
!self.depth_write_enabled.unwrap_or_default()
}
#[must_use]
pub fn is_stencil_read_only(&self, cull_mode: Option<Face>) -> bool {
self.stencil.is_read_only(cull_mode)
}
#[must_use]
pub fn is_read_only(&self, cull_mode: Option<Face>) -> bool {
self.is_depth_read_only() && self.is_stencil_read_only(cull_mode)
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RenderBundleDepthStencil {
pub format: crate::TextureFormat,
#[doc = link_to_wgpu_docs!(["`RenderPassDepthStencilAttachment::depth_ops`"]: "struct.RenderPassDepthStencilAttachment.html#structfield.depth_ops")]
pub depth_read_only: bool,
#[doc = link_to_wgpu_docs!(["`RenderPassDepthStencilAttachment::stencil_ops`"]: "struct.RenderPassDepthStencilAttachment.html#structfield.stencil_ops")]
pub stencil_read_only: bool,
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RenderBundleDescriptor<L> {
pub label: L,
}
impl<L> RenderBundleDescriptor<L> {
#[must_use]
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> RenderBundleDescriptor<K> {
RenderBundleDescriptor {
label: fun(&self.label),
}
}
}
impl<T> Default for RenderBundleDescriptor<Option<T>> {
fn default() -> Self {
Self { label: None }
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
pub struct DrawIndirectArgs {
pub vertex_count: u32,
pub instance_count: u32,
pub first_vertex: u32,
pub first_instance: u32,
}
impl DrawIndirectArgs {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
bytemuck::bytes_of(self)
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
pub struct DrawIndexedIndirectArgs {
pub index_count: u32,
pub instance_count: u32,
pub first_index: u32,
pub base_vertex: i32,
pub first_instance: u32,
}
impl DrawIndexedIndirectArgs {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
bytemuck::bytes_of(self)
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
pub struct DispatchIndirectArgs {
pub x: u32,
pub y: u32,
pub z: u32,
}
impl DispatchIndirectArgs {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
bytemuck::bytes_of(self)
}
}