#![allow(
// We don't use syntax sugar where it's not necessary.
clippy::match_like_matches_macro,
// Redundant matching is more explicit.
clippy::redundant_pattern_matching,
// Explicit lifetimes are often easier to reason about.
clippy::needless_lifetimes,
// No need for defaults in the internal types.
clippy::new_without_default,
// Matches are good and extendable, no need to make an exception here.
clippy::single_match,
// Push commands are more regular than macros.
clippy::vec_init_then_push,
// This is the land of unsafe.
clippy::missing_safety_doc,
// Let me decide when it's too many.
clippy::too_many_arguments,
)]
#![warn(
trivial_numeric_casts,
unused_extern_crates,
//TODO: re-enable. Currently doesn't like "mem::size_of" on newer Rust
//unused_qualifications,
// We don't match on a reference, unless required.
clippy::pattern_type_mismatch,
)]
pub use naga::{StorageAccess, VectorSize, back::PipelineConstants};
pub type Transform = mint::RowMatrix3x4<f32>;
pub const IDENTITY_TRANSFORM: Transform = mint::RowMatrix3x4 {
x: mint::Vector4 {
x: 1.0,
y: 0.0,
z: 0.0,
w: 0.0,
},
y: mint::Vector4 {
x: 0.0,
y: 1.0,
z: 0.0,
w: 0.0,
},
z: mint::Vector4 {
x: 0.0,
y: 0.0,
z: 1.0,
w: 0.0,
},
};
pub mod derive;
#[cfg_attr(
all(not(vulkan), not(gles), any(target_os = "ios", target_os = "macos")),
path = "metal/mod.rs"
)]
#[cfg_attr(
all(
not(gles),
any(
vulkan,
windows,
target_os = "linux",
target_os = "android",
target_os = "freebsd"
)
),
path = "vulkan/mod.rs"
)]
#[cfg_attr(any(gles, target_arch = "wasm32"), path = "gles/mod.rs")]
mod hal;
mod shader;
pub mod traits;
pub mod util;
pub mod limits {
pub const PASS_COUNT: usize = 100;
pub const PLAIN_DATA_SIZE: u32 = 256;
pub const RESOURCES_IN_GROUP: u32 = 8;
pub const STORAGE_BUFFER_ALIGNMENT: u64 = 16;
pub const ACCELERATION_STRUCTURE_SCRATCH_ALIGNMENT: u64 = 256;
}
pub use hal::*;
#[cfg(target_arch = "wasm32")]
pub const CANVAS_ID: &str = "blade";
use std::{fmt, num::NonZeroU32};
#[derive(Debug)]
pub struct PlatformError(String);
impl PlatformError {
pub(crate) fn loading(err: impl fmt::Debug) -> Self {
Self(format!("failed to load: {:?}", err))
}
pub(crate) fn init(err: impl fmt::Debug) -> Self {
Self(format!("failed to initialize: {:?}", err))
}
}
impl fmt::Display for PlatformError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for PlatformError {}
#[cfg(not(any(
vulkan,
windows,
target_os = "linux",
target_os = "android",
target_os = "freebsd"
)))]
pub mod openxr {
#[derive(Clone, Debug)]
pub enum Instance {}
#[derive(Clone, Debug)]
pub enum SystemId {}
}
#[derive(Clone)]
pub struct XrDesc {
pub instance: openxr::Instance,
pub system_id: openxr::SystemId,
}
impl fmt::Debug for XrDesc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("XrDesc")
.field("system_id", &self.system_id)
.finish()
}
}
#[derive(Clone, Debug, Default)]
pub struct ContextDesc {
pub presentation: bool,
pub xr: Option<XrDesc>,
pub ray_tracing: bool,
pub validation: bool,
pub timing: bool,
pub capture: bool,
pub overlay: bool,
pub device_id: Option<u32>,
}
#[derive(Debug)]
pub enum NotSupportedError {
Platform(PlatformError),
NoSupportedDeviceFound,
PlatformNotSupported,
}
impl fmt::Display for NotSupportedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Platform(ref e) => write!(f, "platform error: {}", e),
Self::NoSupportedDeviceFound => f.write_str("no supported device found"),
Self::PlatformNotSupported => f.write_str("platform not supported"),
}
}
}
impl std::error::Error for NotSupportedError {}
impl From<PlatformError> for NotSupportedError {
fn from(error: PlatformError) -> Self {
Self::Platform(error)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DeviceError {
DeviceLost,
OutOfMemory,
}
impl fmt::Display for DeviceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::DeviceLost => f.write_str("device lost"),
Self::OutOfMemory => f.write_str("out of memory"),
}
}
}
impl std::error::Error for DeviceError {}
#[derive(Clone, Copy, Debug, Default)]
pub struct MemoryStats {
pub budget: u64,
pub usage: u64,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct CooperativeMatrix {
pub f32_tile: u32,
pub f16_tile: u32,
}
impl CooperativeMatrix {
pub fn is_supported(&self) -> bool {
self.f32_tile > 0 || self.f16_tile > 0
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Capabilities {
pub binding_array: bool,
pub ray_query: ShaderVisibility,
pub sample_count_mask: u32,
pub dual_source_blending: bool,
pub shader_float16: bool,
pub cooperative_matrix: CooperativeMatrix,
}
#[derive(Clone, Debug, Default)]
pub struct DeviceInformation {
pub is_software_emulated: bool,
pub device_name: String,
pub driver_name: String,
pub driver_info: String,
}
impl Context {
pub fn create_surface_configured<
I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
>(
&self,
window: &I,
config: SurfaceConfig,
) -> Result<Surface, NotSupportedError> {
let mut surface = self.create_surface(window)?;
self.reconfigure_surface(&mut surface, config);
Ok(surface)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Memory {
Device,
Shared,
Upload,
External(ExternalMemorySource),
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum ExternalMemorySource {
#[cfg(target_os = "windows")]
Win32(Option<isize>),
#[cfg(target_os = "windows")]
Win32KMT(Option<isize>),
#[cfg(not(target_os = "windows"))]
Fd(Option<i32>),
#[cfg(target_os = "linux")]
Dma(Option<i32>),
HostAllocation(usize),
}
impl Memory {
pub fn is_host_visible(&self) -> bool {
match *self {
Self::Shared
| Self::Upload
| Self::External(ExternalMemorySource::HostAllocation(_)) => true,
Self::Device | Self::External(_) => false,
}
}
}
#[derive(Debug)]
pub struct BufferDesc<'a> {
pub name: &'a str,
pub size: u64,
pub memory: Memory,
}
#[derive(Clone, Copy, Debug)]
pub struct BufferPiece {
pub buffer: Buffer,
pub offset: u64,
}
impl From<Buffer> for BufferPiece {
fn from(buffer: Buffer) -> Self {
Self { buffer, offset: 0 }
}
}
impl BufferPiece {
pub fn data(&self) -> *mut u8 {
let base = self.buffer.data();
assert!(!base.is_null());
debug_assert!(
self.offset <= self.buffer.size(),
"BufferPiece offset {} exceeds buffer size {}",
self.offset,
self.buffer.size(),
);
unsafe { base.offset(self.offset as isize) }
}
}
impl Buffer {
pub fn at(self, offset: u64) -> BufferPiece {
BufferPiece {
buffer: self,
offset,
}
}
}
pub type ResourceIndex = u32;
pub struct ResourceArray<T, const N: ResourceIndex> {
data: Vec<T>,
free_list: Vec<ResourceIndex>,
}
impl<T, const N: ResourceIndex> ResourceArray<T, N> {
pub fn new() -> Self {
Self {
data: Vec::with_capacity(N as usize),
free_list: Vec::new(),
}
}
pub fn alloc(&mut self, value: T) -> ResourceIndex {
if let Some(index) = self.free_list.pop() {
self.data[index as usize] = value;
index
} else {
let index = self.data.len() as u32;
assert!(index < N);
self.data.push(value);
index
}
}
pub fn free(&mut self, index: ResourceIndex) {
self.free_list.push(index);
}
pub fn clear(&mut self) {
self.data.clear();
self.free_list.clear();
}
}
impl<T, const N: ResourceIndex> std::ops::Index<ResourceIndex> for ResourceArray<T, N> {
type Output = T;
fn index(&self, index: ResourceIndex) -> &T {
&self.data[index as usize]
}
}
impl<T, const N: ResourceIndex> std::ops::IndexMut<ResourceIndex> for ResourceArray<T, N> {
fn index_mut(&mut self, index: ResourceIndex) -> &mut T {
&mut self.data[index as usize]
}
}
pub type BufferArray<const N: ResourceIndex> = ResourceArray<BufferPiece, N>;
pub type TextureArray<const N: ResourceIndex> = ResourceArray<TextureView, N>;
pub type AccelerationStructureArray<const N: ResourceIndex> =
ResourceArray<AccelerationStructure, N>;
#[derive(Clone, Copy, Debug)]
pub struct TexturePiece {
pub texture: Texture,
pub mip_level: u32,
pub array_layer: u32,
pub origin: [u32; 3],
}
impl From<Texture> for TexturePiece {
fn from(texture: Texture) -> Self {
Self {
texture,
mip_level: 0,
array_layer: 0,
origin: [0; 3],
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub enum TextureFormat {
R8Unorm,
Rg8Unorm,
Rg8Snorm,
Rgba8Unorm,
Rgba8UnormSrgb,
Bgra8Unorm,
Bgra8UnormSrgb,
Rgba8Snorm,
R16Float,
Rg16Float,
Rgba16Float,
R32Float,
Rg32Float,
Rgba32Float,
R32Uint,
Rg32Uint,
Rgba32Uint,
Depth32Float,
Depth32FloatStencil8Uint,
Stencil8Uint,
Bc1Unorm,
Bc1UnormSrgb,
Bc2Unorm,
Bc2UnormSrgb,
Bc3Unorm,
Bc3UnormSrgb,
Bc4Unorm,
Bc4Snorm,
Bc5Unorm,
Bc5Snorm,
Bc6hUfloat,
Bc6hFloat,
Bc7Unorm,
Bc7UnormSrgb,
Rgb10a2Unorm,
Rg11b10Ufloat,
Rgb9e5Ufloat,
}
#[derive(Clone, Copy, Debug)]
pub struct TexelBlockInfo {
pub dimensions: (u8, u8),
pub size: u8,
}
bitflags::bitflags! {
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub struct TexelAspects: u8 {
const COLOR = 0x1;
const DEPTH = 0x2;
const STENCIL = 0x4;
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureDimension {
D1,
D2,
D3,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum ViewDimension {
D1,
D1Array,
D2,
D2Array,
Cube,
CubeArray,
D3,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Extent {
pub width: u32,
pub height: u32,
pub depth: u32,
}
impl Default for Extent {
fn default() -> Self {
Self {
width: 1,
height: 1,
depth: 1,
}
}
}
impl fmt::Display for Extent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}x{}x{}", self.width, self.height, self.depth)
}
}
impl Extent {
pub fn max_mip_levels(&self) -> u32 {
self.width
.max(self.height)
.max(self.depth)
.next_power_of_two()
.trailing_zeros()
}
pub fn at_mip_level(&self, level: u32) -> Self {
Self {
width: (self.width >> level).max(1),
height: (self.height >> level).max(1),
depth: (self.depth >> level).max(1),
}
}
}
bitflags::bitflags! {
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub struct TextureUsage: u32 {
const COPY = 1 << 0;
const TARGET = 1 << 1;
const RESOURCE = 1 << 2;
const STORAGE = 1 << 3;
}
}
#[derive(Debug)]
pub struct TextureDesc<'a> {
pub name: &'a str,
pub format: TextureFormat,
pub size: Extent,
pub array_layer_count: u32,
pub mip_level_count: u32,
pub sample_count: u32,
pub dimension: TextureDimension,
pub usage: TextureUsage,
pub external: Option<ExternalMemorySource>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TextureSubresources {
pub base_mip_level: u32,
pub mip_level_count: Option<NonZeroU32>,
pub base_array_layer: u32,
pub array_layer_count: Option<NonZeroU32>,
}
#[derive(Debug)]
pub struct TextureViewDesc<'a> {
pub name: &'a str,
pub format: TextureFormat,
pub dimension: ViewDimension,
pub subresources: &'a TextureSubresources,
}
bitflags::bitflags! {
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub struct ShaderVisibility: u32 {
const COMPUTE = 1 << 0;
const VERTEX = 1 << 1;
const FRAGMENT = 1 << 2;
}
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum AddressMode {
#[default]
ClampToEdge,
Repeat,
MirrorRepeat,
ClampToBorder,
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum FilterMode {
#[default]
Nearest,
Linear,
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum CompareFunction {
Never,
Less,
Equal,
LessEqual,
Greater,
NotEqual,
GreaterEqual,
#[default]
Always,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TextureColor {
TransparentBlack,
OpaqueBlack,
White,
}
#[derive(Debug, Default)]
pub struct SamplerDesc<'a> {
pub name: &'a str,
pub address_modes: [AddressMode; 3],
pub mag_filter: FilterMode,
pub min_filter: FilterMode,
pub mipmap_filter: FilterMode,
pub lod_min_clamp: f32,
pub lod_max_clamp: Option<f32>,
pub compare: Option<CompareFunction>,
pub anisotropy_clamp: u32,
pub border_color: Option<TextureColor>,
}
#[derive(Debug)]
pub enum AccelerationStructureType {
TopLevel,
BottomLevel,
}
#[derive(Debug)]
pub struct AccelerationStructureDesc<'a> {
pub name: &'a str,
pub ty: AccelerationStructureType,
pub size: u64,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub enum VertexFormat {
F32,
F32Vec2,
F32Vec3,
F32Vec4,
U32,
U32Vec2,
U32Vec3,
U32Vec4,
I32,
I32Vec2,
I32Vec3,
I32Vec4,
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureMesh {
pub vertex_data: BufferPiece,
pub vertex_format: VertexFormat,
pub vertex_stride: u32,
pub vertex_count: u32,
pub index_data: BufferPiece,
pub index_type: Option<IndexType>,
pub triangle_count: u32,
pub transform_data: BufferPiece,
pub is_opaque: bool,
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureInstance {
pub acceleration_structure_index: u32,
pub transform: Transform,
pub mask: u32,
pub custom_index: u32,
}
impl Default for AccelerationStructureInstance {
fn default() -> Self {
Self {
acceleration_structure_index: 0,
transform: IDENTITY_TRANSFORM,
mask: 0xFF,
custom_index: 0,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct AccelerationStructureSizes {
pub data: u64,
pub scratch: u64,
}
pub struct Shader {
module: naga::Module,
info: naga::valid::ModuleInfo,
source: String,
}
#[derive(Clone, Copy)]
pub struct ShaderFunction<'a> {
pub shader: &'a Shader,
pub entry_point: &'a str,
pub constants: &'a PipelineConstants,
}
impl ShaderFunction<'_> {
fn entry_point_index(&self) -> usize {
self.shader
.module
.entry_points
.iter()
.position(|ep| ep.name == self.entry_point)
.expect("Entry point not found in the shader")
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ShaderBinding {
Texture,
TextureArray { count: u32 },
Sampler,
Buffer,
BufferArray { count: u32 },
AccelerationStructure,
AccelerationStructureArray { count: u32 },
Plain { size: u32 },
}
pub trait ShaderBindable: Clone + Copy + derive::HasShaderBinding {
fn bind_to(&self, context: &mut PipelineContext, index: u32);
}
#[derive(Debug)]
struct ShaderDataInfo {
visibility: ShaderVisibility,
binding_access: Box<[StorageAccess]>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ShaderDataLayout {
pub bindings: Vec<(&'static str, ShaderBinding)>,
}
impl ShaderDataLayout {
pub const EMPTY: &'static Self = &Self {
bindings: Vec::new(),
};
fn to_info(&self) -> ShaderDataInfo {
ShaderDataInfo {
visibility: ShaderVisibility::empty(),
binding_access: vec![StorageAccess::empty(); self.bindings.len()].into_boxed_slice(),
}
}
}
pub trait ShaderData {
fn layout() -> ShaderDataLayout;
fn fill(&self, context: PipelineContext);
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct VertexAttribute {
pub offset: u32,
pub format: VertexFormat,
}
struct VertexAttributeMapping {
buffer_index: usize,
attribute_index: usize,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct VertexLayout {
pub attributes: Vec<(&'static str, VertexAttribute)>,
pub stride: u32,
}
pub trait Vertex {
fn layout() -> VertexLayout;
}
#[derive(Clone, Debug, PartialEq)]
pub struct VertexFetchState<'a> {
pub layout: &'a VertexLayout,
pub instanced: bool,
}
pub struct ShaderDesc<'a> {
pub source: &'a str,
pub naga_module: Option<naga::Module>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub enum CommandType {
Transfer,
Compute,
#[default]
General,
}
pub struct CommandEncoderDesc<'a> {
pub name: &'a str,
pub buffer_count: u32,
}
pub struct ComputePipelineDesc<'a> {
pub name: &'a str,
pub data_layouts: &'a [&'a ShaderDataLayout],
pub compute: ShaderFunction<'a>,
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum PrimitiveTopology {
PointList,
LineList,
LineStrip,
#[default]
TriangleList,
TriangleStrip,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub enum FrontFace {
#[default]
Ccw,
Cw,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Face {
Front,
Back,
}
#[derive(Clone, Debug, Default)]
pub struct PrimitiveState {
pub topology: PrimitiveTopology,
pub front_face: FrontFace,
pub cull_mode: Option<Face>,
pub unclipped_depth: bool,
pub wireframe: bool,
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum StencilOperation {
#[default]
Keep,
Zero,
Replace,
Invert,
IncrementClamp,
DecrementClamp,
IncrementWrap,
DecrementWrap,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
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,
};
}
impl Default for StencilFaceState {
fn default() -> Self {
Self::IGNORE
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct StencilState {
pub front: StencilFaceState,
pub back: StencilFaceState,
pub read_mask: u32,
pub write_mask: u32,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct DepthBiasState {
pub constant: i32,
pub slope_scale: f32,
pub clamp: f32,
}
#[derive(Clone, Debug)]
pub struct DepthStencilState {
pub format: TextureFormat,
pub depth_write_enabled: bool,
pub depth_compare: CompareFunction,
pub stencil: StencilState,
pub bias: DepthBiasState,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum BlendFactor {
Zero,
One,
Src,
OneMinusSrc,
SrcAlpha,
OneMinusSrcAlpha,
Dst,
OneMinusDst,
DstAlpha,
OneMinusDstAlpha,
SrcAlphaSaturated,
Constant,
OneMinusConstant,
Src1,
OneMinusSrc1,
Src1Alpha,
OneMinusSrc1Alpha,
}
impl BlendFactor {
pub const fn uses_dual_source(&self) -> bool {
matches!(
self,
BlendFactor::Src1
| BlendFactor::OneMinusSrc1
| BlendFactor::Src1Alpha
| BlendFactor::OneMinusSrc1Alpha
)
}
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum BlendOperation {
#[default]
Add,
Subtract,
ReverseSubtract,
Min,
Max,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
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,
};
pub const ADDITIVE: Self = Self {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::One,
operation: BlendOperation::Add,
};
pub const fn uses_dual_source(&self) -> bool {
self.src_factor.uses_dual_source() || self.dst_factor.uses_dual_source()
}
}
impl Default for BlendComponent {
fn default() -> Self {
Self::REPLACE
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
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,
};
pub const ADDITIVE: Self = Self {
color: BlendComponent::ADDITIVE,
alpha: BlendComponent::ADDITIVE,
};
pub const fn uses_dual_source(&self) -> bool {
self.color.uses_dual_source() || self.alpha.uses_dual_source()
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct 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
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ColorTargetState {
pub format: TextureFormat,
pub blend: Option<BlendState>,
pub write_mask: ColorWrites,
}
impl From<TextureFormat> for ColorTargetState {
fn from(format: TextureFormat) -> Self {
Self {
format,
blend: None,
write_mask: ColorWrites::ALL,
}
}
}
pub struct RenderPipelineDesc<'a> {
pub name: &'a str,
pub data_layouts: &'a [&'a ShaderDataLayout],
pub vertex: ShaderFunction<'a>,
pub vertex_fetches: &'a [VertexFetchState<'a>],
pub primitive: PrimitiveState,
pub depth_stencil: Option<DepthStencilState>,
pub fragment: Option<ShaderFunction<'a>>,
pub color_targets: &'a [ColorTargetState],
pub multisample_state: MultisampleState,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct MultisampleState {
pub sample_count: u32,
pub sample_mask: u64,
pub alpha_to_coverage: bool,
}
impl Default for MultisampleState {
fn default() -> Self {
Self {
sample_count: 1,
sample_mask: !0,
alpha_to_coverage: false,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum InitOp {
Load,
Clear(TextureColor),
DontCare,
}
#[derive(Clone, Copy, Debug)]
pub enum FinishOp {
Store,
Discard,
ResolveTo(TextureView),
Ignore,
}
#[derive(Debug)]
pub struct RenderTarget {
pub view: TextureView,
pub init_op: InitOp,
pub finish_op: FinishOp,
}
#[derive(Debug)]
pub struct RenderTargetSet<'a> {
pub colors: &'a [RenderTarget],
pub depth_stencil: Option<RenderTarget>,
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum DisplaySync {
#[default]
Block,
Recent,
Tear,
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum ColorSpace {
#[default]
Linear,
Srgb,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct SurfaceConfig {
pub size: Extent,
pub usage: TextureUsage,
pub display_sync: DisplaySync,
pub color_space: ColorSpace,
pub transparent: bool,
pub allow_exclusive_full_screen: bool,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct XrSurfaceConfig {
pub size: Extent,
pub usage: TextureUsage,
pub color_space: ColorSpace,
pub view_count: u32,
}
impl Default for XrSurfaceConfig {
fn default() -> Self {
Self {
size: Extent::default(),
usage: TextureUsage::TARGET,
color_space: ColorSpace::Linear,
view_count: 2,
}
}
}
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
pub enum AlphaMode {
#[default]
Ignored,
PreMultiplied,
PostMultiplied,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SurfaceInfo {
pub format: TextureFormat,
pub alpha: AlphaMode,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum IndexType {
U16,
U32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ScissorRect {
pub x: i32,
pub y: i32,
pub w: u32,
pub h: u32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Viewport {
pub x: f32,
pub y: f32,
pub w: f32,
pub h: f32,
pub depth: std::ops::Range<f32>,
}
pub type Timings = Vec<(String, std::time::Duration)>;