use bitflags::bitflags;
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendComponentKey {
pub src_factor: wgpu::BlendFactor,
pub dst_factor: wgpu::BlendFactor,
pub operation: wgpu::BlendOperation,
}
impl From<wgpu::BlendComponent> for BlendComponentKey {
fn from(b: wgpu::BlendComponent) -> Self {
Self {
src_factor: b.src_factor,
dst_factor: b.dst_factor,
operation: b.operation,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendStateKey {
pub color: BlendComponentKey,
pub alpha: BlendComponentKey,
}
impl From<wgpu::BlendState> for BlendStateKey {
fn from(b: wgpu::BlendState) -> Self {
Self {
color: b.color.into(),
alpha: b.alpha.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ColorTargetKey {
pub format: wgpu::TextureFormat,
pub blend: Option<BlendStateKey>,
pub write_mask: u32, }
impl From<wgpu::ColorTargetState> for ColorTargetKey {
fn from(c: wgpu::ColorTargetState) -> Self {
Self {
format: c.format,
blend: c.blend.map(Into::into),
write_mask: c.write_mask.bits(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StencilFaceKey {
pub compare: wgpu::CompareFunction,
pub fail_op: wgpu::StencilOperation,
pub depth_fail_op: wgpu::StencilOperation,
pub pass_op: wgpu::StencilOperation,
}
impl From<wgpu::StencilFaceState> for StencilFaceKey {
fn from(s: wgpu::StencilFaceState) -> Self {
Self {
compare: s.compare,
fail_op: s.fail_op,
depth_fail_op: s.depth_fail_op,
pass_op: s.pass_op,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StencilStateKey {
pub front: StencilFaceKey,
pub back: StencilFaceKey,
pub read_mask: u32,
pub write_mask: u32,
}
impl From<wgpu::StencilState> for StencilStateKey {
fn from(s: wgpu::StencilState) -> Self {
Self {
front: s.front.into(),
back: s.back.into(),
read_mask: s.read_mask,
write_mask: s.write_mask,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DepthBiasKey {
pub constant: i32,
pub slope_scale_bits: u32,
pub clamp_bits: u32,
}
impl From<wgpu::DepthBiasState> for DepthBiasKey {
fn from(b: wgpu::DepthBiasState) -> Self {
Self {
constant: b.constant,
slope_scale_bits: b.slope_scale.to_bits(),
clamp_bits: b.clamp.to_bits(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DepthStencilKey {
pub format: wgpu::TextureFormat,
pub depth_write_enabled: Option<bool>,
pub depth_compare: Option<wgpu::CompareFunction>,
pub stencil: StencilStateKey,
pub bias: DepthBiasKey,
}
impl From<wgpu::DepthStencilState> for DepthStencilKey {
fn from(d: wgpu::DepthStencilState) -> Self {
Self {
format: d.format,
depth_write_enabled: d.depth_write_enabled,
depth_compare: d.depth_compare,
stencil: d.stencil.into(),
bias: d.bias.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MultisampleKey {
pub count: u32,
pub mask: u64,
pub alpha_to_coverage_enabled: bool,
}
impl From<wgpu::MultisampleState> for MultisampleKey {
fn from(m: wgpu::MultisampleState) -> Self {
Self {
count: m.count,
mask: m.mask,
alpha_to_coverage_enabled: m.alpha_to_coverage_enabled,
}
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PipelineFlags: u32 {
const DEPTH_WRITE = 1 << 0;
const ALPHA_TO_COVERAGE = 1 << 1;
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GraphicsPipelineKey {
pub shader_hash: u64,
pub vertex_layout_id: u64,
pub bind_group_layout_ids: [u64; 4],
pub topology: wgpu::PrimitiveTopology,
pub cull_mode: Option<wgpu::Face>,
pub front_face: wgpu::FrontFace,
pub depth_compare: wgpu::CompareFunction,
pub blend_state: Option<BlendStateKey>,
pub color_targets: smallvec::SmallVec<[ColorTargetKey; 3]>,
pub depth_format: wgpu::TextureFormat,
pub sample_count: u32,
pub flags: PipelineFlags,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FullscreenPipelineKey {
pub shader_hash: u128,
pub color_targets: smallvec::SmallVec<[ColorTargetKey; 2]>,
pub depth_stencil: Option<DepthStencilKey>,
pub multisample: MultisampleKey,
}
impl FullscreenPipelineKey {
#[must_use]
pub fn fullscreen(
shader_hash: u128,
color_targets: smallvec::SmallVec<[ColorTargetKey; 2]>,
depth_stencil: Option<DepthStencilKey>,
) -> Self {
Self {
shader_hash,
color_targets,
depth_stencil,
multisample: MultisampleKey::from(wgpu::MultisampleState::default()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ComputePipelineKey {
pub shader_hash: u128,
pub compilation_hash: u64,
}
impl ComputePipelineKey {
#[must_use]
pub fn new(shader_hash: u128) -> Self {
Self {
shader_hash,
compilation_hash: 0,
}
}
#[must_use]
pub fn with_compilation_options(
mut self,
options: &wgpu::PipelineCompilationOptions<'_>,
) -> Self {
self.compilation_hash = hash_pipeline_compilation_options(options);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SimpleGeometryPipelineKey {
pub shader_hash: u128,
pub vertex_layout_id: u64,
pub color_targets: smallvec::SmallVec<[ColorTargetKey; 3]>,
pub depth_stencil: DepthStencilKey,
pub topology: wgpu::PrimitiveTopology,
pub cull_mode: Option<wgpu::Face>,
pub front_face: wgpu::FrontFace,
pub sample_count: u32,
}
#[inline]
pub fn fx_hash_key<K: Hash>(key: &K) -> u64 {
let mut hasher = rustc_hash::FxHasher::default();
key.hash(&mut hasher);
hasher.finish()
}
#[inline]
#[must_use]
pub fn hash_pipeline_compilation_options(options: &wgpu::PipelineCompilationOptions<'_>) -> u64 {
let mut hasher = rustc_hash::FxHasher::default();
options.zero_initialize_workgroup_memory.hash(&mut hasher);
for (name, value) in options.constants {
name.hash(&mut hasher);
value.to_bits().hash(&mut hasher);
}
hasher.finish()
}