#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![allow(
// We don't use syntax sugar where it's not necessary.
clippy::match_like_matches_macro,
)]
#![warn(missing_docs, unsafe_op_in_unsafe_fn)]
#[cfg(any(feature = "serde", test))]
use serde::Deserialize;
#[cfg(any(feature = "serde", test))]
use serde::Serialize;
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use std::{num::NonZeroU32, ops::Range};
pub mod assertions;
mod counters;
pub mod math;
pub use counters::*;
macro_rules! impl_bitflags {
($name:ident) => {
#[cfg(feature = "serde")]
impl serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.bits().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = <_ as serde::Deserialize<'de>>::deserialize(deserializer)?;
Ok($name::from_bits_retain(value))
}
}
impl $name {
pub fn contains_invalid_bits(&self) -> bool {
let all = Self::all().bits();
(self.bits() | all) != all
}
}
};
}
pub type BufferAddress = u64;
pub type BufferSize = std::num::NonZeroU64;
pub type ShaderLocation = u32;
pub type DynamicOffset = u32;
pub const COPY_BYTES_PER_ROW_ALIGNMENT: u32 = 256;
pub const QUERY_RESOLVE_BUFFER_ALIGNMENT: BufferAddress = 256;
pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4;
pub const MAP_ALIGNMENT: BufferAddress = 8;
pub const VERTEX_STRIDE_ALIGNMENT: BufferAddress = 4;
pub const PUSH_CONSTANT_ALIGNMENT: u32 = 4;
pub const QUERY_SET_MAX_QUERIES: u32 = 8192;
pub const QUERY_SIZE: u32 = 8;
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Backend {
Empty = 0,
Vulkan = 1,
Metal = 2,
Dx12 = 3,
Gl = 4,
BrowserWebGpu = 5,
}
impl Backend {
pub const fn to_str(self) -> &'static str {
match self {
Backend::Empty => "empty",
Backend::Vulkan => "vulkan",
Backend::Metal => "metal",
Backend::Dx12 => "dx12",
Backend::Gl => "gl",
Backend::BrowserWebGpu => "webgpu",
}
}
}
impl std::fmt::Display for Backend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.to_str())
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PowerPreference {
#[default]
None = 0,
LowPower = 1,
HighPerformance = 2,
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Backends: u32 {
const VULKAN = 1 << Backend::Vulkan as u32;
const GL = 1 << Backend::Gl as u32;
const METAL = 1 << Backend::Metal as u32;
const DX12 = 1 << Backend::Dx12 as u32;
const BROWSER_WEBGPU = 1 << Backend::BrowserWebGpu as u32;
const PRIMARY = Self::VULKAN.bits()
| Self::METAL.bits()
| Self::DX12.bits()
| Self::BROWSER_WEBGPU.bits();
const SECONDARY = Self::GL.bits();
}
}
impl Default for Backends {
fn default() -> Self {
Self::all()
}
}
impl_bitflags!(Backends);
impl From<Backend> for Backends {
fn from(backend: Backend) -> Self {
Self::from_bits(1 << backend as u32).unwrap()
}
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RequestAdapterOptions<S> {
pub power_preference: PowerPreference,
pub force_fallback_adapter: bool,
pub compatible_surface: Option<S>,
}
impl<S> Default for RequestAdapterOptions<S> {
fn default() -> Self {
Self {
power_preference: PowerPreference::default(),
force_fallback_adapter: false,
compatible_surface: None,
}
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Default)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Features: u64 {
const DEPTH_CLIP_CONTROL = 1 << 0;
const DEPTH32FLOAT_STENCIL8 = 1 << 1;
const TEXTURE_COMPRESSION_BC = 1 << 2;
const TEXTURE_COMPRESSION_ETC2 = 1 << 3;
const TEXTURE_COMPRESSION_ASTC = 1 << 4;
const TIMESTAMP_QUERY = 1 << 5;
const INDIRECT_FIRST_INSTANCE = 1 << 6;
const SHADER_F16 = 1 << 7;
const RG11B10UFLOAT_RENDERABLE = 1 << 8;
const BGRA8UNORM_STORAGE = 1 << 9;
const FLOAT32_FILTERABLE = 1 << 10;
const TEXTURE_FORMAT_16BIT_NORM = 1 << 20;
const TEXTURE_COMPRESSION_ASTC_HDR = 1 << 21;
const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 1 << 22;
const PIPELINE_STATISTICS_QUERY = 1 << 23;
const TIMESTAMP_QUERY_INSIDE_ENCODERS = 1 << 24;
const TIMESTAMP_QUERY_INSIDE_PASSES = 1 << 25;
const MAPPABLE_PRIMARY_BUFFERS = 1 << 26;
const TEXTURE_BINDING_ARRAY = 1 << 27;
const BUFFER_BINDING_ARRAY = 1 << 28;
const STORAGE_RESOURCE_BINDING_ARRAY = 1 << 29;
const SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING = 1 << 30;
const UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING = 1 << 31;
const PARTIALLY_BOUND_BINDING_ARRAY = 1 << 32;
const MULTI_DRAW_INDIRECT = 1 << 33;
const MULTI_DRAW_INDIRECT_COUNT = 1 << 34;
const PUSH_CONSTANTS = 1 << 35;
const ADDRESS_MODE_CLAMP_TO_ZERO = 1 << 36;
const ADDRESS_MODE_CLAMP_TO_BORDER = 1 << 37;
const POLYGON_MODE_LINE = 1 << 38;
const POLYGON_MODE_POINT = 1 << 39;
const CONSERVATIVE_RASTERIZATION = 1 << 40;
const VERTEX_WRITABLE_STORAGE = 1 << 41;
const CLEAR_TEXTURE = 1 << 42;
const SPIRV_SHADER_PASSTHROUGH = 1 << 43;
const MULTIVIEW = 1 << 44;
const VERTEX_ATTRIBUTE_64BIT = 1 << 45;
const TEXTURE_FORMAT_NV12 = 1 << 47;
const RAY_TRACING_ACCELERATION_STRUCTURE = 1 << 48;
const RAY_QUERY = 1 << 49;
const SHADER_F64 = 1 << 50;
const SHADER_I16 = 1 << 51;
const SHADER_PRIMITIVE_INDEX = 1 << 52;
const SHADER_EARLY_DEPTH_TEST = 1 << 53;
const DUAL_SOURCE_BLENDING = 1 << 54;
const SHADER_INT64 = 1 << 55;
const SUBGROUP = 1 << 56;
const SUBGROUP_VERTEX = 1 << 57;
const SUBGROUP_BARRIER = 1 << 58;
const PIPELINE_CACHE = 1 << 59;
const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 60;
const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 61;
}
}
impl_bitflags!(Features);
impl Features {
pub const fn all_webgpu_mask() -> Self {
Self::from_bits_truncate(0xFFFFF)
}
pub const fn all_native_mask() -> Self {
Self::from_bits_truncate(!Self::all_webgpu_mask().bits())
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct InstanceFlags: u32 {
const DEBUG = 1 << 0;
const VALIDATION = 1 << 1;
const DISCARD_HAL_LABELS = 1 << 2;
const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
const GPU_BASED_VALIDATION = 1 << 4;
}
}
impl Default for InstanceFlags {
fn default() -> Self {
Self::from_build_config()
}
}
impl InstanceFlags {
pub fn debugging() -> Self {
InstanceFlags::DEBUG | InstanceFlags::VALIDATION
}
pub fn advanced_debugging() -> Self {
Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION
}
pub fn from_build_config() -> Self {
if cfg!(debug_assertions) {
return InstanceFlags::debugging();
}
InstanceFlags::empty()
}
pub fn with_env(mut self) -> Self {
fn env(key: &str) -> Option<bool> {
std::env::var(key).ok().map(|s| match s.as_str() {
"0" => false,
_ => true,
})
}
if let Some(bit) = env("WGPU_VALIDATION") {
self.set(Self::VALIDATION, bit);
}
if let Some(bit) = env("WGPU_DEBUG") {
self.set(Self::DEBUG, bit);
}
if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
}
if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
self.set(Self::GPU_BASED_VALIDATION, bit);
}
self
}
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase", default))]
pub struct Limits {
#[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension1D"))]
pub max_texture_dimension_1d: u32,
#[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension2D"))]
pub max_texture_dimension_2d: u32,
#[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension3D"))]
pub max_texture_dimension_3d: u32,
pub max_texture_array_layers: u32,
pub max_bind_groups: u32,
pub max_bindings_per_bind_group: u32,
pub max_dynamic_uniform_buffers_per_pipeline_layout: u32,
pub max_dynamic_storage_buffers_per_pipeline_layout: u32,
pub max_sampled_textures_per_shader_stage: u32,
pub max_samplers_per_shader_stage: u32,
pub max_storage_buffers_per_shader_stage: u32,
pub max_storage_textures_per_shader_stage: u32,
pub max_uniform_buffers_per_shader_stage: u32,
pub max_uniform_buffer_binding_size: u32,
pub max_storage_buffer_binding_size: u32,
pub max_vertex_buffers: u32,
pub max_buffer_size: u64,
pub max_vertex_attributes: u32,
pub max_vertex_buffer_array_stride: u32,
pub min_uniform_buffer_offset_alignment: u32,
pub min_storage_buffer_offset_alignment: u32,
pub max_inter_stage_shader_components: u32,
pub max_color_attachments: u32,
pub max_color_attachment_bytes_per_sample: u32,
pub max_compute_workgroup_storage_size: u32,
pub max_compute_invocations_per_workgroup: u32,
pub max_compute_workgroup_size_x: u32,
pub max_compute_workgroup_size_y: u32,
pub max_compute_workgroup_size_z: u32,
pub max_compute_workgroups_per_dimension: u32,
pub min_subgroup_size: u32,
pub max_subgroup_size: u32,
pub max_push_constant_size: u32,
pub max_non_sampler_bindings: u32,
}
impl Default for Limits {
fn default() -> Self {
Self::defaults()
}
}
impl Limits {
const fn defaults() -> Self {
Self {
max_texture_dimension_1d: 8192,
max_texture_dimension_2d: 8192,
max_texture_dimension_3d: 2048,
max_texture_array_layers: 256,
max_bind_groups: 4,
max_bindings_per_bind_group: 1000,
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
max_dynamic_storage_buffers_per_pipeline_layout: 4,
max_sampled_textures_per_shader_stage: 16,
max_samplers_per_shader_stage: 16,
max_storage_buffers_per_shader_stage: 8,
max_storage_textures_per_shader_stage: 4,
max_uniform_buffers_per_shader_stage: 12,
max_uniform_buffer_binding_size: 64 << 10, max_storage_buffer_binding_size: 128 << 20, max_vertex_buffers: 8,
max_buffer_size: 256 << 20, max_vertex_attributes: 16,
max_vertex_buffer_array_stride: 2048,
min_uniform_buffer_offset_alignment: 256,
min_storage_buffer_offset_alignment: 256,
max_inter_stage_shader_components: 60,
max_color_attachments: 8,
max_color_attachment_bytes_per_sample: 32,
max_compute_workgroup_storage_size: 16384,
max_compute_invocations_per_workgroup: 256,
max_compute_workgroup_size_x: 256,
max_compute_workgroup_size_y: 256,
max_compute_workgroup_size_z: 64,
max_compute_workgroups_per_dimension: 65535,
min_subgroup_size: 0,
max_subgroup_size: 0,
max_push_constant_size: 0,
max_non_sampler_bindings: 1_000_000,
}
}
pub const fn downlevel_defaults() -> Self {
Self {
max_texture_dimension_1d: 2048,
max_texture_dimension_2d: 2048,
max_texture_dimension_3d: 256,
max_storage_buffers_per_shader_stage: 4,
max_uniform_buffer_binding_size: 16 << 10, max_compute_workgroup_storage_size: 16352,
..Self::defaults()
}
}
pub const fn downlevel_webgl2_defaults() -> Self {
Self {
max_uniform_buffers_per_shader_stage: 11,
max_storage_buffers_per_shader_stage: 0,
max_storage_textures_per_shader_stage: 0,
max_dynamic_storage_buffers_per_pipeline_layout: 0,
max_storage_buffer_binding_size: 0,
max_vertex_buffer_array_stride: 255,
max_compute_workgroup_storage_size: 0,
max_compute_invocations_per_workgroup: 0,
max_compute_workgroup_size_x: 0,
max_compute_workgroup_size_y: 0,
max_compute_workgroup_size_z: 0,
max_compute_workgroups_per_dimension: 0,
min_subgroup_size: 0,
max_subgroup_size: 0,
max_inter_stage_shader_components: 31,
..Self::downlevel_defaults()
}
}
pub const fn using_resolution(self, other: Self) -> Self {
Self {
max_texture_dimension_1d: other.max_texture_dimension_1d,
max_texture_dimension_2d: other.max_texture_dimension_2d,
max_texture_dimension_3d: other.max_texture_dimension_3d,
..self
}
}
pub const fn using_alignment(self, other: Self) -> Self {
Self {
min_uniform_buffer_offset_alignment: other.min_uniform_buffer_offset_alignment,
min_storage_buffer_offset_alignment: other.min_storage_buffer_offset_alignment,
..self
}
}
pub fn check_limits(&self, allowed: &Self) -> bool {
let mut within = true;
self.check_limits_with_fail_fn(allowed, true, |_, _, _| within = false);
within
}
pub fn check_limits_with_fail_fn(
&self,
allowed: &Self,
fatal: bool,
mut fail_fn: impl FnMut(&'static str, u64, u64),
) {
use std::cmp::Ordering;
macro_rules! compare {
($name:ident, $ordering:ident) => {
match self.$name.cmp(&allowed.$name) {
Ordering::$ordering | Ordering::Equal => (),
_ => {
fail_fn(stringify!($name), self.$name as u64, allowed.$name as u64);
if fatal {
return;
}
}
}
};
}
compare!(max_texture_dimension_1d, Less);
compare!(max_texture_dimension_2d, Less);
compare!(max_texture_dimension_3d, Less);
compare!(max_texture_array_layers, Less);
compare!(max_bind_groups, Less);
compare!(max_dynamic_uniform_buffers_per_pipeline_layout, Less);
compare!(max_dynamic_storage_buffers_per_pipeline_layout, Less);
compare!(max_sampled_textures_per_shader_stage, Less);
compare!(max_samplers_per_shader_stage, Less);
compare!(max_storage_buffers_per_shader_stage, Less);
compare!(max_storage_textures_per_shader_stage, Less);
compare!(max_uniform_buffers_per_shader_stage, Less);
compare!(max_uniform_buffer_binding_size, Less);
compare!(max_storage_buffer_binding_size, Less);
compare!(max_vertex_buffers, Less);
compare!(max_vertex_attributes, Less);
compare!(max_vertex_buffer_array_stride, Less);
if self.min_subgroup_size > 0 && self.max_subgroup_size > 0 {
compare!(min_subgroup_size, Greater);
compare!(max_subgroup_size, Less);
}
compare!(max_push_constant_size, Less);
compare!(min_uniform_buffer_offset_alignment, Greater);
compare!(min_storage_buffer_offset_alignment, Greater);
compare!(max_inter_stage_shader_components, Less);
compare!(max_compute_workgroup_storage_size, Less);
compare!(max_compute_invocations_per_workgroup, Less);
compare!(max_compute_workgroup_size_x, Less);
compare!(max_compute_workgroup_size_y, Less);
compare!(max_compute_workgroup_size_z, Less);
compare!(max_compute_workgroups_per_dimension, Less);
compare!(max_buffer_size, Less);
compare!(max_non_sampler_bindings, Less);
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DownlevelLimits {}
#[allow(unknown_lints)] #[allow(clippy::derivable_impls)]
impl Default for DownlevelLimits {
fn default() -> Self {
DownlevelLimits {}
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DownlevelCapabilities {
pub flags: DownlevelFlags,
pub limits: DownlevelLimits,
pub shader_model: ShaderModel,
}
impl Default for DownlevelCapabilities {
fn default() -> Self {
Self {
flags: DownlevelFlags::all(),
limits: DownlevelLimits::default(),
shader_model: ShaderModel::Sm5,
}
}
}
impl DownlevelCapabilities {
pub fn is_webgpu_compliant(&self) -> bool {
self.flags.contains(DownlevelFlags::compliant())
&& self.limits == DownlevelLimits::default()
&& self.shader_model >= ShaderModel::Sm5
}
}
bitflags::bitflags! {
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DownlevelFlags: u32 {
const COMPUTE_SHADERS = 1 << 0;
const FRAGMENT_WRITABLE_STORAGE = 1 << 1;
const INDIRECT_EXECUTION = 1 << 2;
const BASE_VERTEX = 1 << 3;
const READ_ONLY_DEPTH_STENCIL = 1 << 4;
const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 1 << 5;
const CUBE_ARRAY_TEXTURES = 1 << 6;
const COMPARISON_SAMPLERS = 1 << 7;
const INDEPENDENT_BLEND = 1 << 8;
const VERTEX_STORAGE = 1 << 9;
const ANISOTROPIC_FILTERING = 1 << 10;
const FRAGMENT_STORAGE = 1 << 11;
const MULTISAMPLED_SHADING = 1 << 12;
const DEPTH_TEXTURE_AND_BUFFER_COPIES = 1 << 13;
const WEBGPU_TEXTURE_FORMAT_SUPPORT = 1 << 14;
const BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED = 1 << 15;
const UNRESTRICTED_INDEX_BUFFER = 1 << 16;
const FULL_DRAW_INDEX_UINT32 = 1 << 17;
const DEPTH_BIAS_CLAMP = 1 << 18;
const VIEW_FORMATS = 1 << 19;
const UNRESTRICTED_EXTERNAL_TEXTURE_COPIES = 1 << 20;
const SURFACE_VIEW_FORMATS = 1 << 21;
const NONBLOCKING_QUERY_RESOLVE = 1 << 22;
const VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW = 1 << 23;
}
}
impl_bitflags!(DownlevelFlags);
impl DownlevelFlags {
pub const fn compliant() -> Self {
Self::from_bits_truncate(Self::all().bits() & !Self::ANISOTROPIC_FILTERING.bits())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ShaderModel {
Sm2,
Sm4,
Sm5,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DeviceType {
Other,
IntegratedGpu,
DiscreteGpu,
VirtualGpu,
Cpu,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AdapterInfo {
pub name: String,
pub vendor: u32,
pub device: u32,
pub device_type: DeviceType,
pub driver: String,
pub driver_info: String,
pub backend: Backend,
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MemoryHints {
#[default]
Performance,
MemoryUsage,
Manual {
suballocated_device_memory_block_size: Range<u64>,
},
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DeviceDescriptor<L> {
pub label: L,
pub required_features: Features,
pub required_limits: Limits,
pub memory_hints: MemoryHints,
}
impl<L> DeviceDescriptor<L> {
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> DeviceDescriptor<K> {
DeviceDescriptor {
label: fun(&self.label),
required_features: self.required_features,
required_limits: self.required_limits.clone(),
memory_hints: self.memory_hints.clone(),
}
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ShaderStages: u32 {
const NONE = 0;
const VERTEX = 1 << 0;
const FRAGMENT = 1 << 1;
const COMPUTE = 1 << 2;
const VERTEX_FRAGMENT = Self::VERTEX.bits() | Self::FRAGMENT.bits();
}
}
impl_bitflags!(ShaderStages);
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TextureViewDimension {
#[cfg_attr(feature = "serde", serde(rename = "1d"))]
D1,
#[cfg_attr(feature = "serde", serde(rename = "2d"))]
#[default]
D2,
#[cfg_attr(feature = "serde", serde(rename = "2d-array"))]
D2Array,
#[cfg_attr(feature = "serde", serde(rename = "cube"))]
Cube,
#[cfg_attr(feature = "serde", serde(rename = "cube-array"))]
CubeArray,
#[cfg_attr(feature = "serde", serde(rename = "3d"))]
D3,
}
impl TextureViewDimension {
pub fn compatible_texture_dimension(self) -> TextureDimension {
match self {
Self::D1 => TextureDimension::D1,
Self::D2 | Self::D2Array | Self::Cube | Self::CubeArray => TextureDimension::D2,
Self::D3 => TextureDimension::D3,
}
}
}
#[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 {
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,
};
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 {
pub format: TextureFormat,
#[cfg_attr(feature = "serde", serde(default))]
pub blend: Option<BlendState>,
#[cfg_attr(feature = "serde", serde(default))]
pub write_mask: ColorWrites,
}
impl From<TextureFormat> for ColorTargetState {
fn from(format: TextureFormat) -> Self {
Self {
format,
blend: None,
write_mask: ColorWrites::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 {
pub fn is_strip(&self) -> bool {
match *self {
Self::PointList | Self::LineList | Self::TriangleList => false,
Self::LineStrip | Self::TriangleStrip => true,
}
}
}
#[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,
}
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TextureFormatFeatureFlags: u32 {
const FILTERABLE = 1 << 0;
const MULTISAMPLE_X2 = 1 << 1;
const MULTISAMPLE_X4 = 1 << 2 ;
const MULTISAMPLE_X8 = 1 << 3 ;
const MULTISAMPLE_X16 = 1 << 4;
const MULTISAMPLE_RESOLVE = 1 << 5;
const STORAGE_READ_WRITE = 1 << 6;
const BLENDABLE = 1 << 7;
}
}
impl TextureFormatFeatureFlags {
pub fn sample_count_supported(&self, count: u32) -> bool {
use TextureFormatFeatureFlags as tfsc;
match count {
1 => true,
2 => self.contains(tfsc::MULTISAMPLE_X2),
4 => self.contains(tfsc::MULTISAMPLE_X4),
8 => self.contains(tfsc::MULTISAMPLE_X8),
16 => self.contains(tfsc::MULTISAMPLE_X16),
_ => false,
}
}
pub fn supported_sample_counts(&self) -> Vec<u32> {
let all_possible_sample_counts: [u32; 5] = [1, 2, 4, 8, 16];
all_possible_sample_counts
.into_iter()
.filter(|&sc| self.sample_count_supported(sc))
.collect()
}
}
impl_bitflags!(TextureFormatFeatureFlags);
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TextureFormatFeatures {
pub allowed_usages: TextureUsages,
pub flags: TextureFormatFeatureFlags,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AstcBlock {
B4x4,
B5x4,
B5x5,
B6x5,
B6x6,
B8x5,
B8x6,
B8x8,
B10x5,
B10x6,
B10x8,
B10x10,
B12x10,
B12x12,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AstcChannel {
Unorm,
UnormSrgb,
Hdr,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureFormat {
R8Unorm,
R8Snorm,
R8Uint,
R8Sint,
R16Uint,
R16Sint,
R16Unorm,
R16Snorm,
R16Float,
Rg8Unorm,
Rg8Snorm,
Rg8Uint,
Rg8Sint,
R32Uint,
R32Sint,
R32Float,
Rg16Uint,
Rg16Sint,
Rg16Unorm,
Rg16Snorm,
Rg16Float,
Rgba8Unorm,
Rgba8UnormSrgb,
Rgba8Snorm,
Rgba8Uint,
Rgba8Sint,
Bgra8Unorm,
Bgra8UnormSrgb,
Rgb9e5Ufloat,
Rgb10a2Uint,
Rgb10a2Unorm,
Rg11b10Float,
Rg32Uint,
Rg32Sint,
Rg32Float,
Rgba16Uint,
Rgba16Sint,
Rgba16Unorm,
Rgba16Snorm,
Rgba16Float,
Rgba32Uint,
Rgba32Sint,
Rgba32Float,
Stencil8,
Depth16Unorm,
Depth24Plus,
Depth24PlusStencil8,
Depth32Float,
Depth32FloatStencil8,
NV12,
Bc1RgbaUnorm,
Bc1RgbaUnormSrgb,
Bc2RgbaUnorm,
Bc2RgbaUnormSrgb,
Bc3RgbaUnorm,
Bc3RgbaUnormSrgb,
Bc4RUnorm,
Bc4RSnorm,
Bc5RgUnorm,
Bc5RgSnorm,
Bc6hRgbUfloat,
Bc6hRgbFloat,
Bc7RgbaUnorm,
Bc7RgbaUnormSrgb,
Etc2Rgb8Unorm,
Etc2Rgb8UnormSrgb,
Etc2Rgb8A1Unorm,
Etc2Rgb8A1UnormSrgb,
Etc2Rgba8Unorm,
Etc2Rgba8UnormSrgb,
EacR11Unorm,
EacR11Snorm,
EacRg11Unorm,
EacRg11Snorm,
Astc {
block: AstcBlock,
channel: AstcChannel,
},
}
#[cfg(any(feature = "serde", test))]
impl<'de> Deserialize<'de> for TextureFormat {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{self, Error, Unexpected};
struct TextureFormatVisitor;
impl<'de> de::Visitor<'de> for TextureFormatVisitor {
type Value = TextureFormat;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid texture format")
}
fn visit_str<E: Error>(self, s: &str) -> Result<Self::Value, E> {
let format = match s {
"r8unorm" => TextureFormat::R8Unorm,
"r8snorm" => TextureFormat::R8Snorm,
"r8uint" => TextureFormat::R8Uint,
"r8sint" => TextureFormat::R8Sint,
"r16uint" => TextureFormat::R16Uint,
"r16sint" => TextureFormat::R16Sint,
"r16unorm" => TextureFormat::R16Unorm,
"r16snorm" => TextureFormat::R16Snorm,
"r16float" => TextureFormat::R16Float,
"rg8unorm" => TextureFormat::Rg8Unorm,
"rg8snorm" => TextureFormat::Rg8Snorm,
"rg8uint" => TextureFormat::Rg8Uint,
"rg8sint" => TextureFormat::Rg8Sint,
"r32uint" => TextureFormat::R32Uint,
"r32sint" => TextureFormat::R32Sint,
"r32float" => TextureFormat::R32Float,
"rg16uint" => TextureFormat::Rg16Uint,
"rg16sint" => TextureFormat::Rg16Sint,
"rg16unorm" => TextureFormat::Rg16Unorm,
"rg16snorm" => TextureFormat::Rg16Snorm,
"rg16float" => TextureFormat::Rg16Float,
"rgba8unorm" => TextureFormat::Rgba8Unorm,
"rgba8unorm-srgb" => TextureFormat::Rgba8UnormSrgb,
"rgba8snorm" => TextureFormat::Rgba8Snorm,
"rgba8uint" => TextureFormat::Rgba8Uint,
"rgba8sint" => TextureFormat::Rgba8Sint,
"bgra8unorm" => TextureFormat::Bgra8Unorm,
"bgra8unorm-srgb" => TextureFormat::Bgra8UnormSrgb,
"rgb10a2uint" => TextureFormat::Rgb10a2Uint,
"rgb10a2unorm" => TextureFormat::Rgb10a2Unorm,
"rg11b10ufloat" => TextureFormat::Rg11b10Float,
"rg32uint" => TextureFormat::Rg32Uint,
"rg32sint" => TextureFormat::Rg32Sint,
"rg32float" => TextureFormat::Rg32Float,
"rgba16uint" => TextureFormat::Rgba16Uint,
"rgba16sint" => TextureFormat::Rgba16Sint,
"rgba16unorm" => TextureFormat::Rgba16Unorm,
"rgba16snorm" => TextureFormat::Rgba16Snorm,
"rgba16float" => TextureFormat::Rgba16Float,
"rgba32uint" => TextureFormat::Rgba32Uint,
"rgba32sint" => TextureFormat::Rgba32Sint,
"rgba32float" => TextureFormat::Rgba32Float,
"stencil8" => TextureFormat::Stencil8,
"depth32float" => TextureFormat::Depth32Float,
"depth32float-stencil8" => TextureFormat::Depth32FloatStencil8,
"depth16unorm" => TextureFormat::Depth16Unorm,
"depth24plus" => TextureFormat::Depth24Plus,
"depth24plus-stencil8" => TextureFormat::Depth24PlusStencil8,
"nv12" => TextureFormat::NV12,
"rgb9e5ufloat" => TextureFormat::Rgb9e5Ufloat,
"bc1-rgba-unorm" => TextureFormat::Bc1RgbaUnorm,
"bc1-rgba-unorm-srgb" => TextureFormat::Bc1RgbaUnormSrgb,
"bc2-rgba-unorm" => TextureFormat::Bc2RgbaUnorm,
"bc2-rgba-unorm-srgb" => TextureFormat::Bc2RgbaUnormSrgb,
"bc3-rgba-unorm" => TextureFormat::Bc3RgbaUnorm,
"bc3-rgba-unorm-srgb" => TextureFormat::Bc3RgbaUnormSrgb,
"bc4-r-unorm" => TextureFormat::Bc4RUnorm,
"bc4-r-snorm" => TextureFormat::Bc4RSnorm,
"bc5-rg-unorm" => TextureFormat::Bc5RgUnorm,
"bc5-rg-snorm" => TextureFormat::Bc5RgSnorm,
"bc6h-rgb-ufloat" => TextureFormat::Bc6hRgbUfloat,
"bc6h-rgb-float" => TextureFormat::Bc6hRgbFloat,
"bc7-rgba-unorm" => TextureFormat::Bc7RgbaUnorm,
"bc7-rgba-unorm-srgb" => TextureFormat::Bc7RgbaUnormSrgb,
"etc2-rgb8unorm" => TextureFormat::Etc2Rgb8Unorm,
"etc2-rgb8unorm-srgb" => TextureFormat::Etc2Rgb8UnormSrgb,
"etc2-rgb8a1unorm" => TextureFormat::Etc2Rgb8A1Unorm,
"etc2-rgb8a1unorm-srgb" => TextureFormat::Etc2Rgb8A1UnormSrgb,
"etc2-rgba8unorm" => TextureFormat::Etc2Rgba8Unorm,
"etc2-rgba8unorm-srgb" => TextureFormat::Etc2Rgba8UnormSrgb,
"eac-r11unorm" => TextureFormat::EacR11Unorm,
"eac-r11snorm" => TextureFormat::EacR11Snorm,
"eac-rg11unorm" => TextureFormat::EacRg11Unorm,
"eac-rg11snorm" => TextureFormat::EacRg11Snorm,
other => {
if let Some(parts) = other.strip_prefix("astc-") {
let (block, channel) = parts
.split_once('-')
.ok_or_else(|| E::invalid_value(Unexpected::Str(s), &self))?;
let block = match block {
"4x4" => AstcBlock::B4x4,
"5x4" => AstcBlock::B5x4,
"5x5" => AstcBlock::B5x5,
"6x5" => AstcBlock::B6x5,
"6x6" => AstcBlock::B6x6,
"8x5" => AstcBlock::B8x5,
"8x6" => AstcBlock::B8x6,
"8x8" => AstcBlock::B8x8,
"10x5" => AstcBlock::B10x5,
"10x6" => AstcBlock::B10x6,
"10x8" => AstcBlock::B10x8,
"10x10" => AstcBlock::B10x10,
"12x10" => AstcBlock::B12x10,
"12x12" => AstcBlock::B12x12,
_ => return Err(E::invalid_value(Unexpected::Str(s), &self)),
};
let channel = match channel {
"unorm" => AstcChannel::Unorm,
"unorm-srgb" => AstcChannel::UnormSrgb,
"hdr" => AstcChannel::Hdr,
_ => return Err(E::invalid_value(Unexpected::Str(s), &self)),
};
TextureFormat::Astc { block, channel }
} else {
return Err(E::invalid_value(Unexpected::Str(s), &self));
}
}
};
Ok(format)
}
}
deserializer.deserialize_str(TextureFormatVisitor)
}
}
#[cfg(any(feature = "serde", test))]
impl Serialize for TextureFormat {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s: String;
let name = match *self {
TextureFormat::R8Unorm => "r8unorm",
TextureFormat::R8Snorm => "r8snorm",
TextureFormat::R8Uint => "r8uint",
TextureFormat::R8Sint => "r8sint",
TextureFormat::R16Uint => "r16uint",
TextureFormat::R16Sint => "r16sint",
TextureFormat::R16Unorm => "r16unorm",
TextureFormat::R16Snorm => "r16snorm",
TextureFormat::R16Float => "r16float",
TextureFormat::Rg8Unorm => "rg8unorm",
TextureFormat::Rg8Snorm => "rg8snorm",
TextureFormat::Rg8Uint => "rg8uint",
TextureFormat::Rg8Sint => "rg8sint",
TextureFormat::R32Uint => "r32uint",
TextureFormat::R32Sint => "r32sint",
TextureFormat::R32Float => "r32float",
TextureFormat::Rg16Uint => "rg16uint",
TextureFormat::Rg16Sint => "rg16sint",
TextureFormat::Rg16Unorm => "rg16unorm",
TextureFormat::Rg16Snorm => "rg16snorm",
TextureFormat::Rg16Float => "rg16float",
TextureFormat::Rgba8Unorm => "rgba8unorm",
TextureFormat::Rgba8UnormSrgb => "rgba8unorm-srgb",
TextureFormat::Rgba8Snorm => "rgba8snorm",
TextureFormat::Rgba8Uint => "rgba8uint",
TextureFormat::Rgba8Sint => "rgba8sint",
TextureFormat::Bgra8Unorm => "bgra8unorm",
TextureFormat::Bgra8UnormSrgb => "bgra8unorm-srgb",
TextureFormat::Rgb10a2Uint => "rgb10a2uint",
TextureFormat::Rgb10a2Unorm => "rgb10a2unorm",
TextureFormat::Rg11b10Float => "rg11b10ufloat",
TextureFormat::Rg32Uint => "rg32uint",
TextureFormat::Rg32Sint => "rg32sint",
TextureFormat::Rg32Float => "rg32float",
TextureFormat::Rgba16Uint => "rgba16uint",
TextureFormat::Rgba16Sint => "rgba16sint",
TextureFormat::Rgba16Unorm => "rgba16unorm",
TextureFormat::Rgba16Snorm => "rgba16snorm",
TextureFormat::Rgba16Float => "rgba16float",
TextureFormat::Rgba32Uint => "rgba32uint",
TextureFormat::Rgba32Sint => "rgba32sint",
TextureFormat::Rgba32Float => "rgba32float",
TextureFormat::Stencil8 => "stencil8",
TextureFormat::Depth32Float => "depth32float",
TextureFormat::Depth16Unorm => "depth16unorm",
TextureFormat::Depth32FloatStencil8 => "depth32float-stencil8",
TextureFormat::Depth24Plus => "depth24plus",
TextureFormat::Depth24PlusStencil8 => "depth24plus-stencil8",
TextureFormat::NV12 => "nv12",
TextureFormat::Rgb9e5Ufloat => "rgb9e5ufloat",
TextureFormat::Bc1RgbaUnorm => "bc1-rgba-unorm",
TextureFormat::Bc1RgbaUnormSrgb => "bc1-rgba-unorm-srgb",
TextureFormat::Bc2RgbaUnorm => "bc2-rgba-unorm",
TextureFormat::Bc2RgbaUnormSrgb => "bc2-rgba-unorm-srgb",
TextureFormat::Bc3RgbaUnorm => "bc3-rgba-unorm",
TextureFormat::Bc3RgbaUnormSrgb => "bc3-rgba-unorm-srgb",
TextureFormat::Bc4RUnorm => "bc4-r-unorm",
TextureFormat::Bc4RSnorm => "bc4-r-snorm",
TextureFormat::Bc5RgUnorm => "bc5-rg-unorm",
TextureFormat::Bc5RgSnorm => "bc5-rg-snorm",
TextureFormat::Bc6hRgbUfloat => "bc6h-rgb-ufloat",
TextureFormat::Bc6hRgbFloat => "bc6h-rgb-float",
TextureFormat::Bc7RgbaUnorm => "bc7-rgba-unorm",
TextureFormat::Bc7RgbaUnormSrgb => "bc7-rgba-unorm-srgb",
TextureFormat::Etc2Rgb8Unorm => "etc2-rgb8unorm",
TextureFormat::Etc2Rgb8UnormSrgb => "etc2-rgb8unorm-srgb",
TextureFormat::Etc2Rgb8A1Unorm => "etc2-rgb8a1unorm",
TextureFormat::Etc2Rgb8A1UnormSrgb => "etc2-rgb8a1unorm-srgb",
TextureFormat::Etc2Rgba8Unorm => "etc2-rgba8unorm",
TextureFormat::Etc2Rgba8UnormSrgb => "etc2-rgba8unorm-srgb",
TextureFormat::EacR11Unorm => "eac-r11unorm",
TextureFormat::EacR11Snorm => "eac-r11snorm",
TextureFormat::EacRg11Unorm => "eac-rg11unorm",
TextureFormat::EacRg11Snorm => "eac-rg11snorm",
TextureFormat::Astc { block, channel } => {
let block = match block {
AstcBlock::B4x4 => "4x4",
AstcBlock::B5x4 => "5x4",
AstcBlock::B5x5 => "5x5",
AstcBlock::B6x5 => "6x5",
AstcBlock::B6x6 => "6x6",
AstcBlock::B8x5 => "8x5",
AstcBlock::B8x6 => "8x6",
AstcBlock::B8x8 => "8x8",
AstcBlock::B10x5 => "10x5",
AstcBlock::B10x6 => "10x6",
AstcBlock::B10x8 => "10x8",
AstcBlock::B10x10 => "10x10",
AstcBlock::B12x10 => "12x10",
AstcBlock::B12x12 => "12x12",
};
let channel = match channel {
AstcChannel::Unorm => "unorm",
AstcChannel::UnormSrgb => "unorm-srgb",
AstcChannel::Hdr => "hdr",
};
s = format!("astc-{block}-{channel}");
&s
}
};
serializer.serialize_str(name)
}
}
impl TextureAspect {
pub fn from_plane(plane: u32) -> Option<Self> {
Some(match plane {
0 => Self::Plane0,
1 => Self::Plane1,
2 => Self::Plane2,
_ => return None,
})
}
}
impl TextureFormat {
pub fn aspect_specific_format(&self, aspect: TextureAspect) -> Option<Self> {
match (*self, aspect) {
(Self::Stencil8, TextureAspect::StencilOnly) => Some(*self),
(
Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float,
TextureAspect::DepthOnly,
) => Some(*self),
(
Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8,
TextureAspect::StencilOnly,
) => Some(Self::Stencil8),
(Self::Depth24PlusStencil8, TextureAspect::DepthOnly) => Some(Self::Depth24Plus),
(Self::Depth32FloatStencil8, TextureAspect::DepthOnly) => Some(Self::Depth32Float),
(Self::NV12, TextureAspect::Plane0) => Some(Self::R8Unorm),
(Self::NV12, TextureAspect::Plane1) => Some(Self::Rg8Unorm),
(format, TextureAspect::All) if !format.is_multi_planar_format() => Some(format),
_ => None,
}
}
pub fn is_depth_stencil_component(&self, combined_format: Self) -> bool {
match (combined_format, *self) {
(Self::Depth24PlusStencil8, Self::Depth24Plus | Self::Stencil8)
| (Self::Depth32FloatStencil8, Self::Depth32Float | Self::Stencil8) => true,
_ => false,
}
}
pub fn is_depth_stencil_format(&self) -> bool {
match *self {
Self::Stencil8
| Self::Depth16Unorm
| Self::Depth24Plus
| Self::Depth24PlusStencil8
| Self::Depth32Float
| Self::Depth32FloatStencil8 => true,
_ => false,
}
}
pub fn is_combined_depth_stencil_format(&self) -> bool {
match *self {
Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => true,
_ => false,
}
}
pub fn is_multi_planar_format(&self) -> bool {
self.planes().is_some()
}
pub fn planes(&self) -> Option<u32> {
match *self {
Self::NV12 => Some(2),
_ => None,
}
}
pub fn has_color_aspect(&self) -> bool {
!self.is_depth_stencil_format()
}
pub fn has_depth_aspect(&self) -> bool {
match *self {
Self::Depth16Unorm
| Self::Depth24Plus
| Self::Depth24PlusStencil8
| Self::Depth32Float
| Self::Depth32FloatStencil8 => true,
_ => false,
}
}
pub fn has_stencil_aspect(&self) -> bool {
match *self {
Self::Stencil8 | Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => true,
_ => false,
}
}
pub fn size_multiple_requirement(&self) -> (u32, u32) {
match *self {
Self::NV12 => (2, 2),
_ => self.block_dimensions(),
}
}
pub fn block_dimensions(&self) -> (u32, u32) {
match *self {
Self::R8Unorm
| Self::R8Snorm
| Self::R8Uint
| Self::R8Sint
| Self::R16Uint
| Self::R16Sint
| Self::R16Unorm
| Self::R16Snorm
| Self::R16Float
| Self::Rg8Unorm
| Self::Rg8Snorm
| Self::Rg8Uint
| Self::Rg8Sint
| Self::R32Uint
| Self::R32Sint
| Self::R32Float
| Self::Rg16Uint
| Self::Rg16Sint
| Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rg16Float
| Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Rgba8Uint
| Self::Rgba8Sint
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb
| Self::Rgb9e5Ufloat
| Self::Rgb10a2Uint
| Self::Rgb10a2Unorm
| Self::Rg11b10Float
| Self::Rg32Uint
| Self::Rg32Sint
| Self::Rg32Float
| Self::Rgba16Uint
| Self::Rgba16Sint
| Self::Rgba16Unorm
| Self::Rgba16Snorm
| Self::Rgba16Float
| Self::Rgba32Uint
| Self::Rgba32Sint
| Self::Rgba32Float
| Self::Stencil8
| Self::Depth16Unorm
| Self::Depth24Plus
| Self::Depth24PlusStencil8
| Self::Depth32Float
| Self::Depth32FloatStencil8
| Self::NV12 => (1, 1),
Self::Bc1RgbaUnorm
| Self::Bc1RgbaUnormSrgb
| Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc4RUnorm
| Self::Bc4RSnorm
| Self::Bc5RgUnorm
| Self::Bc5RgSnorm
| Self::Bc6hRgbUfloat
| Self::Bc6hRgbFloat
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb => (4, 4),
Self::Etc2Rgb8Unorm
| Self::Etc2Rgb8UnormSrgb
| Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb
| Self::EacR11Unorm
| Self::EacR11Snorm
| Self::EacRg11Unorm
| Self::EacRg11Snorm => (4, 4),
Self::Astc { block, .. } => match block {
AstcBlock::B4x4 => (4, 4),
AstcBlock::B5x4 => (5, 4),
AstcBlock::B5x5 => (5, 5),
AstcBlock::B6x5 => (6, 5),
AstcBlock::B6x6 => (6, 6),
AstcBlock::B8x5 => (8, 5),
AstcBlock::B8x6 => (8, 6),
AstcBlock::B8x8 => (8, 8),
AstcBlock::B10x5 => (10, 5),
AstcBlock::B10x6 => (10, 6),
AstcBlock::B10x8 => (10, 8),
AstcBlock::B10x10 => (10, 10),
AstcBlock::B12x10 => (12, 10),
AstcBlock::B12x12 => (12, 12),
},
}
}
pub fn is_compressed(&self) -> bool {
self.block_dimensions() != (1, 1)
}
pub fn required_features(&self) -> Features {
match *self {
Self::R8Unorm
| Self::R8Snorm
| Self::R8Uint
| Self::R8Sint
| Self::R16Uint
| Self::R16Sint
| Self::R16Float
| Self::Rg8Unorm
| Self::Rg8Snorm
| Self::Rg8Uint
| Self::Rg8Sint
| Self::R32Uint
| Self::R32Sint
| Self::R32Float
| Self::Rg16Uint
| Self::Rg16Sint
| Self::Rg16Float
| Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Rgba8Uint
| Self::Rgba8Sint
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb
| Self::Rgb9e5Ufloat
| Self::Rgb10a2Uint
| Self::Rgb10a2Unorm
| Self::Rg11b10Float
| Self::Rg32Uint
| Self::Rg32Sint
| Self::Rg32Float
| Self::Rgba16Uint
| Self::Rgba16Sint
| Self::Rgba16Float
| Self::Rgba32Uint
| Self::Rgba32Sint
| Self::Rgba32Float
| Self::Stencil8
| Self::Depth16Unorm
| Self::Depth24Plus
| Self::Depth24PlusStencil8
| Self::Depth32Float => Features::empty(),
Self::Depth32FloatStencil8 => Features::DEPTH32FLOAT_STENCIL8,
Self::NV12 => Features::TEXTURE_FORMAT_NV12,
Self::R16Unorm
| Self::R16Snorm
| Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rgba16Unorm
| Self::Rgba16Snorm => Features::TEXTURE_FORMAT_16BIT_NORM,
Self::Bc1RgbaUnorm
| Self::Bc1RgbaUnormSrgb
| Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc4RUnorm
| Self::Bc4RSnorm
| Self::Bc5RgUnorm
| Self::Bc5RgSnorm
| Self::Bc6hRgbUfloat
| Self::Bc6hRgbFloat
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb => Features::TEXTURE_COMPRESSION_BC,
Self::Etc2Rgb8Unorm
| Self::Etc2Rgb8UnormSrgb
| Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb
| Self::EacR11Unorm
| Self::EacR11Snorm
| Self::EacRg11Unorm
| Self::EacRg11Snorm => Features::TEXTURE_COMPRESSION_ETC2,
Self::Astc { channel, .. } => match channel {
AstcChannel::Hdr => Features::TEXTURE_COMPRESSION_ASTC_HDR,
AstcChannel::Unorm | AstcChannel::UnormSrgb => Features::TEXTURE_COMPRESSION_ASTC,
},
}
}
pub fn guaranteed_format_features(&self, device_features: Features) -> TextureFormatFeatures {
let noaa = TextureFormatFeatureFlags::empty();
let msaa = TextureFormatFeatureFlags::MULTISAMPLE_X4;
let msaa_resolve = msaa | TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE;
let basic =
TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING;
let attachment = basic | TextureUsages::RENDER_ATTACHMENT;
let storage = basic | TextureUsages::STORAGE_BINDING;
let binding = TextureUsages::TEXTURE_BINDING;
let all_flags = TextureUsages::all();
let rg11b10f = if device_features.contains(Features::RG11B10UFLOAT_RENDERABLE) {
attachment
} else {
basic
};
let bgra8unorm = if device_features.contains(Features::BGRA8UNORM_STORAGE) {
attachment | TextureUsages::STORAGE_BINDING
} else {
attachment
};
#[rustfmt::skip] let (
mut flags,
allowed_usages,
) = match *self {
Self::R8Unorm => (msaa_resolve, attachment),
Self::R8Snorm => ( noaa, basic),
Self::R8Uint => ( msaa, attachment),
Self::R8Sint => ( msaa, attachment),
Self::R16Uint => ( msaa, attachment),
Self::R16Sint => ( msaa, attachment),
Self::R16Float => (msaa_resolve, attachment),
Self::Rg8Unorm => (msaa_resolve, attachment),
Self::Rg8Snorm => ( noaa, basic),
Self::Rg8Uint => ( msaa, attachment),
Self::Rg8Sint => ( msaa, attachment),
Self::R32Uint => ( noaa, all_flags),
Self::R32Sint => ( noaa, all_flags),
Self::R32Float => ( msaa, all_flags),
Self::Rg16Uint => ( msaa, attachment),
Self::Rg16Sint => ( msaa, attachment),
Self::Rg16Float => (msaa_resolve, attachment),
Self::Rgba8Unorm => (msaa_resolve, all_flags),
Self::Rgba8UnormSrgb => (msaa_resolve, attachment),
Self::Rgba8Snorm => ( noaa, storage),
Self::Rgba8Uint => ( msaa, all_flags),
Self::Rgba8Sint => ( msaa, all_flags),
Self::Bgra8Unorm => (msaa_resolve, bgra8unorm),
Self::Bgra8UnormSrgb => (msaa_resolve, attachment),
Self::Rgb10a2Uint => ( msaa, attachment),
Self::Rgb10a2Unorm => (msaa_resolve, attachment),
Self::Rg11b10Float => ( msaa, rg11b10f),
Self::Rg32Uint => ( noaa, all_flags),
Self::Rg32Sint => ( noaa, all_flags),
Self::Rg32Float => ( noaa, all_flags),
Self::Rgba16Uint => ( msaa, all_flags),
Self::Rgba16Sint => ( msaa, all_flags),
Self::Rgba16Float => (msaa_resolve, all_flags),
Self::Rgba32Uint => ( noaa, all_flags),
Self::Rgba32Sint => ( noaa, all_flags),
Self::Rgba32Float => ( noaa, all_flags),
Self::Stencil8 => ( msaa, attachment),
Self::Depth16Unorm => ( msaa, attachment),
Self::Depth24Plus => ( msaa, attachment),
Self::Depth24PlusStencil8 => ( msaa, attachment),
Self::Depth32Float => ( msaa, attachment),
Self::Depth32FloatStencil8 => ( msaa, attachment),
Self::NV12 => ( noaa, binding),
Self::R16Unorm => ( msaa, storage),
Self::R16Snorm => ( msaa, storage),
Self::Rg16Unorm => ( msaa, storage),
Self::Rg16Snorm => ( msaa, storage),
Self::Rgba16Unorm => ( msaa, storage),
Self::Rgba16Snorm => ( msaa, storage),
Self::Rgb9e5Ufloat => ( noaa, basic),
Self::Bc1RgbaUnorm => ( noaa, basic),
Self::Bc1RgbaUnormSrgb => ( noaa, basic),
Self::Bc2RgbaUnorm => ( noaa, basic),
Self::Bc2RgbaUnormSrgb => ( noaa, basic),
Self::Bc3RgbaUnorm => ( noaa, basic),
Self::Bc3RgbaUnormSrgb => ( noaa, basic),
Self::Bc4RUnorm => ( noaa, basic),
Self::Bc4RSnorm => ( noaa, basic),
Self::Bc5RgUnorm => ( noaa, basic),
Self::Bc5RgSnorm => ( noaa, basic),
Self::Bc6hRgbUfloat => ( noaa, basic),
Self::Bc6hRgbFloat => ( noaa, basic),
Self::Bc7RgbaUnorm => ( noaa, basic),
Self::Bc7RgbaUnormSrgb => ( noaa, basic),
Self::Etc2Rgb8Unorm => ( noaa, basic),
Self::Etc2Rgb8UnormSrgb => ( noaa, basic),
Self::Etc2Rgb8A1Unorm => ( noaa, basic),
Self::Etc2Rgb8A1UnormSrgb => ( noaa, basic),
Self::Etc2Rgba8Unorm => ( noaa, basic),
Self::Etc2Rgba8UnormSrgb => ( noaa, basic),
Self::EacR11Unorm => ( noaa, basic),
Self::EacR11Snorm => ( noaa, basic),
Self::EacRg11Unorm => ( noaa, basic),
Self::EacRg11Snorm => ( noaa, basic),
Self::Astc { .. } => ( noaa, basic),
};
let sample_type1 = self.sample_type(None, Some(device_features));
let is_filterable = sample_type1 == Some(TextureSampleType::Float { filterable: true });
let sample_type2 = self.sample_type(None, None);
let is_blendable = sample_type2 == Some(TextureSampleType::Float { filterable: true });
flags.set(TextureFormatFeatureFlags::FILTERABLE, is_filterable);
flags.set(TextureFormatFeatureFlags::BLENDABLE, is_blendable);
TextureFormatFeatures {
allowed_usages,
flags,
}
}
pub fn sample_type(
&self,
aspect: Option<TextureAspect>,
device_features: Option<Features>,
) -> Option<TextureSampleType> {
let float = TextureSampleType::Float { filterable: true };
let unfilterable_float = TextureSampleType::Float { filterable: false };
let float32_sample_type = TextureSampleType::Float {
filterable: device_features
.unwrap_or(Features::empty())
.contains(Features::FLOAT32_FILTERABLE),
};
let depth = TextureSampleType::Depth;
let uint = TextureSampleType::Uint;
let sint = TextureSampleType::Sint;
match *self {
Self::R8Unorm
| Self::R8Snorm
| Self::Rg8Unorm
| Self::Rg8Snorm
| Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb
| Self::R16Float
| Self::Rg16Float
| Self::Rgba16Float
| Self::Rgb10a2Unorm
| Self::Rg11b10Float => Some(float),
Self::R32Float | Self::Rg32Float | Self::Rgba32Float => Some(float32_sample_type),
Self::R8Uint
| Self::Rg8Uint
| Self::Rgba8Uint
| Self::R16Uint
| Self::Rg16Uint
| Self::Rgba16Uint
| Self::R32Uint
| Self::Rg32Uint
| Self::Rgba32Uint
| Self::Rgb10a2Uint => Some(uint),
Self::R8Sint
| Self::Rg8Sint
| Self::Rgba8Sint
| Self::R16Sint
| Self::Rg16Sint
| Self::Rgba16Sint
| Self::R32Sint
| Self::Rg32Sint
| Self::Rgba32Sint => Some(sint),
Self::Stencil8 => Some(uint),
Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => Some(depth),
Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => match aspect {
Some(TextureAspect::DepthOnly) => Some(depth),
Some(TextureAspect::StencilOnly) => Some(uint),
_ => None,
},
Self::NV12 => match aspect {
Some(TextureAspect::Plane0) | Some(TextureAspect::Plane1) => {
Some(unfilterable_float)
}
_ => None,
},
Self::R16Unorm
| Self::R16Snorm
| Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rgba16Unorm
| Self::Rgba16Snorm => Some(float),
Self::Rgb9e5Ufloat => Some(float),
Self::Bc1RgbaUnorm
| Self::Bc1RgbaUnormSrgb
| Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc4RUnorm
| Self::Bc4RSnorm
| Self::Bc5RgUnorm
| Self::Bc5RgSnorm
| Self::Bc6hRgbUfloat
| Self::Bc6hRgbFloat
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb => Some(float),
Self::Etc2Rgb8Unorm
| Self::Etc2Rgb8UnormSrgb
| Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb
| Self::EacR11Unorm
| Self::EacR11Snorm
| Self::EacRg11Unorm
| Self::EacRg11Snorm => Some(float),
Self::Astc { .. } => Some(float),
}
}
#[deprecated(since = "0.19.0", note = "Use `block_copy_size` instead.")]
pub fn block_size(&self, aspect: Option<TextureAspect>) -> Option<u32> {
self.block_copy_size(aspect)
}
pub fn block_copy_size(&self, aspect: Option<TextureAspect>) -> Option<u32> {
match *self {
Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1),
Self::Rg8Unorm | Self::Rg8Snorm | Self::Rg8Uint | Self::Rg8Sint => Some(2),
Self::R16Unorm | Self::R16Snorm | Self::R16Uint | Self::R16Sint | Self::R16Float => {
Some(2)
}
Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Rgba8Uint
| Self::Rgba8Sint
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb => Some(4),
Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rg16Uint
| Self::Rg16Sint
| Self::Rg16Float => Some(4),
Self::R32Uint | Self::R32Sint | Self::R32Float => Some(4),
Self::Rgb9e5Ufloat | Self::Rgb10a2Uint | Self::Rgb10a2Unorm | Self::Rg11b10Float => {
Some(4)
}
Self::Rgba16Unorm
| Self::Rgba16Snorm
| Self::Rgba16Uint
| Self::Rgba16Sint
| Self::Rgba16Float => Some(8),
Self::Rg32Uint | Self::Rg32Sint | Self::Rg32Float => Some(8),
Self::Rgba32Uint | Self::Rgba32Sint | Self::Rgba32Float => Some(16),
Self::Stencil8 => Some(1),
Self::Depth16Unorm => Some(2),
Self::Depth32Float => Some(4),
Self::Depth24Plus => None,
Self::Depth24PlusStencil8 => match aspect {
Some(TextureAspect::DepthOnly) => None,
Some(TextureAspect::StencilOnly) => Some(1),
_ => None,
},
Self::Depth32FloatStencil8 => match aspect {
Some(TextureAspect::DepthOnly) => Some(4),
Some(TextureAspect::StencilOnly) => Some(1),
_ => None,
},
Self::NV12 => match aspect {
Some(TextureAspect::Plane0) => Some(1),
Some(TextureAspect::Plane1) => Some(2),
_ => None,
},
Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb | Self::Bc4RUnorm | Self::Bc4RSnorm => {
Some(8)
}
Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc5RgUnorm
| Self::Bc5RgSnorm
| Self::Bc6hRgbUfloat
| Self::Bc6hRgbFloat
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb => Some(16),
Self::Etc2Rgb8Unorm
| Self::Etc2Rgb8UnormSrgb
| Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::EacR11Unorm
| Self::EacR11Snorm => Some(8),
Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb
| Self::EacRg11Unorm
| Self::EacRg11Snorm => Some(16),
Self::Astc { .. } => Some(16),
}
}
pub fn target_pixel_byte_cost(&self) -> Option<u32> {
match *self {
Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1),
Self::Rg8Unorm
| Self::Rg8Snorm
| Self::Rg8Uint
| Self::Rg8Sint
| Self::R16Uint
| Self::R16Sint
| Self::R16Unorm
| Self::R16Snorm
| Self::R16Float => Some(2),
Self::Rgba8Uint
| Self::Rgba8Sint
| Self::Rg16Uint
| Self::Rg16Sint
| Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rg16Float
| Self::R32Uint
| Self::R32Sint
| Self::R32Float => Some(4),
Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb
| Self::Rgba16Uint
| Self::Rgba16Sint
| Self::Rgba16Unorm
| Self::Rgba16Snorm
| Self::Rgba16Float
| Self::Rg32Uint
| Self::Rg32Sint
| Self::Rg32Float
| Self::Rgb10a2Uint
| Self::Rgb10a2Unorm
| Self::Rg11b10Float => Some(8),
Self::Rgba32Uint | Self::Rgba32Sint | Self::Rgba32Float => Some(16),
Self::Stencil8
| Self::Depth16Unorm
| Self::Depth24Plus
| Self::Depth24PlusStencil8
| Self::Depth32Float
| Self::Depth32FloatStencil8
| Self::NV12
| Self::Rgb9e5Ufloat
| Self::Bc1RgbaUnorm
| Self::Bc1RgbaUnormSrgb
| Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc4RUnorm
| Self::Bc4RSnorm
| Self::Bc5RgUnorm
| Self::Bc5RgSnorm
| Self::Bc6hRgbUfloat
| Self::Bc6hRgbFloat
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb
| Self::Etc2Rgb8Unorm
| Self::Etc2Rgb8UnormSrgb
| Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb
| Self::EacR11Unorm
| Self::EacR11Snorm
| Self::EacRg11Unorm
| Self::EacRg11Snorm
| Self::Astc { .. } => None,
}
}
pub fn target_component_alignment(&self) -> Option<u32> {
match *self {
Self::R8Unorm
| Self::R8Snorm
| Self::R8Uint
| Self::R8Sint
| Self::Rg8Unorm
| Self::Rg8Snorm
| Self::Rg8Uint
| Self::Rg8Sint
| Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Rgba8Uint
| Self::Rgba8Sint
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb => Some(1),
Self::R16Uint
| Self::R16Sint
| Self::R16Unorm
| Self::R16Snorm
| Self::R16Float
| Self::Rg16Uint
| Self::Rg16Sint
| Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rg16Float
| Self::Rgba16Uint
| Self::Rgba16Sint
| Self::Rgba16Unorm
| Self::Rgba16Snorm
| Self::Rgba16Float => Some(2),
Self::R32Uint
| Self::R32Sint
| Self::R32Float
| Self::Rg32Uint
| Self::Rg32Sint
| Self::Rg32Float
| Self::Rgba32Uint
| Self::Rgba32Sint
| Self::Rgba32Float
| Self::Rgb10a2Uint
| Self::Rgb10a2Unorm
| Self::Rg11b10Float => Some(4),
Self::Stencil8
| Self::Depth16Unorm
| Self::Depth24Plus
| Self::Depth24PlusStencil8
| Self::Depth32Float
| Self::Depth32FloatStencil8
| Self::NV12
| Self::Rgb9e5Ufloat
| Self::Bc1RgbaUnorm
| Self::Bc1RgbaUnormSrgb
| Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc4RUnorm
| Self::Bc4RSnorm
| Self::Bc5RgUnorm
| Self::Bc5RgSnorm
| Self::Bc6hRgbUfloat
| Self::Bc6hRgbFloat
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb
| Self::Etc2Rgb8Unorm
| Self::Etc2Rgb8UnormSrgb
| Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb
| Self::EacR11Unorm
| Self::EacR11Snorm
| Self::EacRg11Unorm
| Self::EacRg11Snorm
| Self::Astc { .. } => None,
}
}
pub fn components(&self) -> u8 {
self.components_with_aspect(TextureAspect::All)
}
pub fn components_with_aspect(&self, aspect: TextureAspect) -> u8 {
match *self {
Self::R8Unorm
| Self::R8Snorm
| Self::R8Uint
| Self::R8Sint
| Self::R16Unorm
| Self::R16Snorm
| Self::R16Uint
| Self::R16Sint
| Self::R16Float
| Self::R32Uint
| Self::R32Sint
| Self::R32Float => 1,
Self::Rg8Unorm
| Self::Rg8Snorm
| Self::Rg8Uint
| Self::Rg8Sint
| Self::Rg16Unorm
| Self::Rg16Snorm
| Self::Rg16Uint
| Self::Rg16Sint
| Self::Rg16Float
| Self::Rg32Uint
| Self::Rg32Sint
| Self::Rg32Float => 2,
Self::Rgba8Unorm
| Self::Rgba8UnormSrgb
| Self::Rgba8Snorm
| Self::Rgba8Uint
| Self::Rgba8Sint
| Self::Bgra8Unorm
| Self::Bgra8UnormSrgb
| Self::Rgba16Unorm
| Self::Rgba16Snorm
| Self::Rgba16Uint
| Self::Rgba16Sint
| Self::Rgba16Float
| Self::Rgba32Uint
| Self::Rgba32Sint
| Self::Rgba32Float => 4,
Self::Rgb9e5Ufloat | Self::Rg11b10Float => 3,
Self::Rgb10a2Uint | Self::Rgb10a2Unorm => 4,
Self::Stencil8 | Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => 1,
Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => match aspect {
TextureAspect::DepthOnly | TextureAspect::StencilOnly => 1,
_ => 2,
},
Self::NV12 => match aspect {
TextureAspect::Plane0 => 1,
TextureAspect::Plane1 => 2,
_ => 3,
},
Self::Bc4RUnorm | Self::Bc4RSnorm => 1,
Self::Bc5RgUnorm | Self::Bc5RgSnorm => 2,
Self::Bc6hRgbUfloat | Self::Bc6hRgbFloat => 3,
Self::Bc1RgbaUnorm
| Self::Bc1RgbaUnormSrgb
| Self::Bc2RgbaUnorm
| Self::Bc2RgbaUnormSrgb
| Self::Bc3RgbaUnorm
| Self::Bc3RgbaUnormSrgb
| Self::Bc7RgbaUnorm
| Self::Bc7RgbaUnormSrgb => 4,
Self::EacR11Unorm | Self::EacR11Snorm => 1,
Self::EacRg11Unorm | Self::EacRg11Snorm => 2,
Self::Etc2Rgb8Unorm | Self::Etc2Rgb8UnormSrgb => 3,
Self::Etc2Rgb8A1Unorm
| Self::Etc2Rgb8A1UnormSrgb
| Self::Etc2Rgba8Unorm
| Self::Etc2Rgba8UnormSrgb => 4,
Self::Astc { .. } => 4,
}
}
pub fn remove_srgb_suffix(&self) -> TextureFormat {
match *self {
Self::Rgba8UnormSrgb => Self::Rgba8Unorm,
Self::Bgra8UnormSrgb => Self::Bgra8Unorm,
Self::Bc1RgbaUnormSrgb => Self::Bc1RgbaUnorm,
Self::Bc2RgbaUnormSrgb => Self::Bc2RgbaUnorm,
Self::Bc3RgbaUnormSrgb => Self::Bc3RgbaUnorm,
Self::Bc7RgbaUnormSrgb => Self::Bc7RgbaUnorm,
Self::Etc2Rgb8UnormSrgb => Self::Etc2Rgb8Unorm,
Self::Etc2Rgb8A1UnormSrgb => Self::Etc2Rgb8A1Unorm,
Self::Etc2Rgba8UnormSrgb => Self::Etc2Rgba8Unorm,
Self::Astc {
block,
channel: AstcChannel::UnormSrgb,
} => Self::Astc {
block,
channel: AstcChannel::Unorm,
},
_ => *self,
}
}
pub fn add_srgb_suffix(&self) -> TextureFormat {
match *self {
Self::Rgba8Unorm => Self::Rgba8UnormSrgb,
Self::Bgra8Unorm => Self::Bgra8UnormSrgb,
Self::Bc1RgbaUnorm => Self::Bc1RgbaUnormSrgb,
Self::Bc2RgbaUnorm => Self::Bc2RgbaUnormSrgb,
Self::Bc3RgbaUnorm => Self::Bc3RgbaUnormSrgb,
Self::Bc7RgbaUnorm => Self::Bc7RgbaUnormSrgb,
Self::Etc2Rgb8Unorm => Self::Etc2Rgb8UnormSrgb,
Self::Etc2Rgb8A1Unorm => Self::Etc2Rgb8A1UnormSrgb,
Self::Etc2Rgba8Unorm => Self::Etc2Rgba8UnormSrgb,
Self::Astc {
block,
channel: AstcChannel::Unorm,
} => Self::Astc {
block,
channel: AstcChannel::UnormSrgb,
},
_ => *self,
}
}
pub fn is_srgb(&self) -> bool {
*self != self.remove_srgb_suffix()
}
}
#[test]
fn texture_format_serialize() {
assert_eq!(
serde_json::to_string(&TextureFormat::R8Unorm).unwrap(),
"\"r8unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R8Snorm).unwrap(),
"\"r8snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R8Uint).unwrap(),
"\"r8uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R8Sint).unwrap(),
"\"r8sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R16Uint).unwrap(),
"\"r16uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R16Sint).unwrap(),
"\"r16sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R16Unorm).unwrap(),
"\"r16unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R16Snorm).unwrap(),
"\"r16snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R16Float).unwrap(),
"\"r16float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg8Unorm).unwrap(),
"\"rg8unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg8Snorm).unwrap(),
"\"rg8snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg8Uint).unwrap(),
"\"rg8uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg8Sint).unwrap(),
"\"rg8sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R32Uint).unwrap(),
"\"r32uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R32Sint).unwrap(),
"\"r32sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::R32Float).unwrap(),
"\"r32float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg16Uint).unwrap(),
"\"rg16uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg16Sint).unwrap(),
"\"rg16sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg16Unorm).unwrap(),
"\"rg16unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg16Snorm).unwrap(),
"\"rg16snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg16Float).unwrap(),
"\"rg16float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba8Unorm).unwrap(),
"\"rgba8unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba8UnormSrgb).unwrap(),
"\"rgba8unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba8Snorm).unwrap(),
"\"rgba8snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba8Uint).unwrap(),
"\"rgba8uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba8Sint).unwrap(),
"\"rgba8sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bgra8Unorm).unwrap(),
"\"bgra8unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bgra8UnormSrgb).unwrap(),
"\"bgra8unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgb10a2Uint).unwrap(),
"\"rgb10a2uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgb10a2Unorm).unwrap(),
"\"rgb10a2unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg11b10Float).unwrap(),
"\"rg11b10ufloat\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg32Uint).unwrap(),
"\"rg32uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg32Sint).unwrap(),
"\"rg32sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rg32Float).unwrap(),
"\"rg32float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba16Uint).unwrap(),
"\"rgba16uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba16Sint).unwrap(),
"\"rgba16sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba16Unorm).unwrap(),
"\"rgba16unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba16Snorm).unwrap(),
"\"rgba16snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba16Float).unwrap(),
"\"rgba16float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba32Uint).unwrap(),
"\"rgba32uint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba32Sint).unwrap(),
"\"rgba32sint\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgba32Float).unwrap(),
"\"rgba32float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Stencil8).unwrap(),
"\"stencil8\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Depth32Float).unwrap(),
"\"depth32float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Depth16Unorm).unwrap(),
"\"depth16unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Depth32FloatStencil8).unwrap(),
"\"depth32float-stencil8\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Depth24Plus).unwrap(),
"\"depth24plus\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Depth24PlusStencil8).unwrap(),
"\"depth24plus-stencil8\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Rgb9e5Ufloat).unwrap(),
"\"rgb9e5ufloat\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc1RgbaUnorm).unwrap(),
"\"bc1-rgba-unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc1RgbaUnormSrgb).unwrap(),
"\"bc1-rgba-unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc2RgbaUnorm).unwrap(),
"\"bc2-rgba-unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc2RgbaUnormSrgb).unwrap(),
"\"bc2-rgba-unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc3RgbaUnorm).unwrap(),
"\"bc3-rgba-unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc3RgbaUnormSrgb).unwrap(),
"\"bc3-rgba-unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc4RUnorm).unwrap(),
"\"bc4-r-unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc4RSnorm).unwrap(),
"\"bc4-r-snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc5RgUnorm).unwrap(),
"\"bc5-rg-unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc5RgSnorm).unwrap(),
"\"bc5-rg-snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc6hRgbUfloat).unwrap(),
"\"bc6h-rgb-ufloat\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc6hRgbFloat).unwrap(),
"\"bc6h-rgb-float\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc7RgbaUnorm).unwrap(),
"\"bc7-rgba-unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Bc7RgbaUnormSrgb).unwrap(),
"\"bc7-rgba-unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Etc2Rgb8Unorm).unwrap(),
"\"etc2-rgb8unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Etc2Rgb8UnormSrgb).unwrap(),
"\"etc2-rgb8unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Etc2Rgb8A1Unorm).unwrap(),
"\"etc2-rgb8a1unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Etc2Rgb8A1UnormSrgb).unwrap(),
"\"etc2-rgb8a1unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Etc2Rgba8Unorm).unwrap(),
"\"etc2-rgba8unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::Etc2Rgba8UnormSrgb).unwrap(),
"\"etc2-rgba8unorm-srgb\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::EacR11Unorm).unwrap(),
"\"eac-r11unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::EacR11Snorm).unwrap(),
"\"eac-r11snorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::EacRg11Unorm).unwrap(),
"\"eac-rg11unorm\"".to_string()
);
assert_eq!(
serde_json::to_string(&TextureFormat::EacRg11Snorm).unwrap(),
"\"eac-rg11snorm\"".to_string()
);
}
#[test]
fn texture_format_deserialize() {
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r8unorm\"").unwrap(),
TextureFormat::R8Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r8snorm\"").unwrap(),
TextureFormat::R8Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r8uint\"").unwrap(),
TextureFormat::R8Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r8sint\"").unwrap(),
TextureFormat::R8Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r16uint\"").unwrap(),
TextureFormat::R16Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r16sint\"").unwrap(),
TextureFormat::R16Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r16unorm\"").unwrap(),
TextureFormat::R16Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r16snorm\"").unwrap(),
TextureFormat::R16Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r16float\"").unwrap(),
TextureFormat::R16Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg8unorm\"").unwrap(),
TextureFormat::Rg8Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg8snorm\"").unwrap(),
TextureFormat::Rg8Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg8uint\"").unwrap(),
TextureFormat::Rg8Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg8sint\"").unwrap(),
TextureFormat::Rg8Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r32uint\"").unwrap(),
TextureFormat::R32Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r32sint\"").unwrap(),
TextureFormat::R32Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"r32float\"").unwrap(),
TextureFormat::R32Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg16uint\"").unwrap(),
TextureFormat::Rg16Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg16sint\"").unwrap(),
TextureFormat::Rg16Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg16unorm\"").unwrap(),
TextureFormat::Rg16Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg16snorm\"").unwrap(),
TextureFormat::Rg16Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg16float\"").unwrap(),
TextureFormat::Rg16Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba8unorm\"").unwrap(),
TextureFormat::Rgba8Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba8unorm-srgb\"").unwrap(),
TextureFormat::Rgba8UnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba8snorm\"").unwrap(),
TextureFormat::Rgba8Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba8uint\"").unwrap(),
TextureFormat::Rgba8Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba8sint\"").unwrap(),
TextureFormat::Rgba8Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bgra8unorm\"").unwrap(),
TextureFormat::Bgra8Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bgra8unorm-srgb\"").unwrap(),
TextureFormat::Bgra8UnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgb10a2uint\"").unwrap(),
TextureFormat::Rgb10a2Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgb10a2unorm\"").unwrap(),
TextureFormat::Rgb10a2Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg11b10ufloat\"").unwrap(),
TextureFormat::Rg11b10Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg32uint\"").unwrap(),
TextureFormat::Rg32Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg32sint\"").unwrap(),
TextureFormat::Rg32Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rg32float\"").unwrap(),
TextureFormat::Rg32Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba16uint\"").unwrap(),
TextureFormat::Rgba16Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba16sint\"").unwrap(),
TextureFormat::Rgba16Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba16unorm\"").unwrap(),
TextureFormat::Rgba16Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba16snorm\"").unwrap(),
TextureFormat::Rgba16Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba16float\"").unwrap(),
TextureFormat::Rgba16Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba32uint\"").unwrap(),
TextureFormat::Rgba32Uint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba32sint\"").unwrap(),
TextureFormat::Rgba32Sint
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgba32float\"").unwrap(),
TextureFormat::Rgba32Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"stencil8\"").unwrap(),
TextureFormat::Stencil8
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"depth32float\"").unwrap(),
TextureFormat::Depth32Float
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"depth16unorm\"").unwrap(),
TextureFormat::Depth16Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"depth32float-stencil8\"").unwrap(),
TextureFormat::Depth32FloatStencil8
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"depth24plus\"").unwrap(),
TextureFormat::Depth24Plus
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"depth24plus-stencil8\"").unwrap(),
TextureFormat::Depth24PlusStencil8
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"rgb9e5ufloat\"").unwrap(),
TextureFormat::Rgb9e5Ufloat
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc1-rgba-unorm\"").unwrap(),
TextureFormat::Bc1RgbaUnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc1-rgba-unorm-srgb\"").unwrap(),
TextureFormat::Bc1RgbaUnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc2-rgba-unorm\"").unwrap(),
TextureFormat::Bc2RgbaUnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc2-rgba-unorm-srgb\"").unwrap(),
TextureFormat::Bc2RgbaUnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc3-rgba-unorm\"").unwrap(),
TextureFormat::Bc3RgbaUnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc3-rgba-unorm-srgb\"").unwrap(),
TextureFormat::Bc3RgbaUnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc4-r-unorm\"").unwrap(),
TextureFormat::Bc4RUnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc4-r-snorm\"").unwrap(),
TextureFormat::Bc4RSnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc5-rg-unorm\"").unwrap(),
TextureFormat::Bc5RgUnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc5-rg-snorm\"").unwrap(),
TextureFormat::Bc5RgSnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc6h-rgb-ufloat\"").unwrap(),
TextureFormat::Bc6hRgbUfloat
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc6h-rgb-float\"").unwrap(),
TextureFormat::Bc6hRgbFloat
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc7-rgba-unorm\"").unwrap(),
TextureFormat::Bc7RgbaUnorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"bc7-rgba-unorm-srgb\"").unwrap(),
TextureFormat::Bc7RgbaUnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"etc2-rgb8unorm\"").unwrap(),
TextureFormat::Etc2Rgb8Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"etc2-rgb8unorm-srgb\"").unwrap(),
TextureFormat::Etc2Rgb8UnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"etc2-rgb8a1unorm\"").unwrap(),
TextureFormat::Etc2Rgb8A1Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"etc2-rgb8a1unorm-srgb\"").unwrap(),
TextureFormat::Etc2Rgb8A1UnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"etc2-rgba8unorm\"").unwrap(),
TextureFormat::Etc2Rgba8Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"etc2-rgba8unorm-srgb\"").unwrap(),
TextureFormat::Etc2Rgba8UnormSrgb
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"eac-r11unorm\"").unwrap(),
TextureFormat::EacR11Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"eac-r11snorm\"").unwrap(),
TextureFormat::EacR11Snorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"eac-rg11unorm\"").unwrap(),
TextureFormat::EacRg11Unorm
);
assert_eq!(
serde_json::from_str::<TextureFormat>("\"eac-rg11snorm\"").unwrap(),
TextureFormat::EacRg11Snorm
);
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
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_bitflags!(ColorWrites);
impl Default for ColorWrites {
fn default() -> Self {
Self::ALL
}
}
#[derive(Clone, Debug)]
pub enum Maintain<T> {
WaitForSubmissionIndex(T),
Wait,
Poll,
}
impl<T> Maintain<T> {
pub fn wait() -> Self {
Self::Wait
}
pub fn wait_for(submission_index: T) -> Self {
Self::WaitForSubmissionIndex(submission_index)
}
pub fn is_wait(&self) -> bool {
match *self {
Self::WaitForSubmissionIndex(..) | Self::Wait => true,
Self::Poll => false,
}
}
pub fn map_index<U, F>(self, func: F) -> Maintain<U>
where
F: FnOnce(T) -> U,
{
match self {
Self::WaitForSubmissionIndex(i) => Maintain::WaitForSubmissionIndex(func(i)),
Self::Wait => Maintain::Wait,
Self::Poll => Maintain::Poll,
}
}
}
pub enum MaintainResult {
SubmissionQueueEmpty,
Ok,
}
impl MaintainResult {
pub fn is_queue_empty(&self) -> bool {
matches!(self, Self::SubmissionQueueEmpty)
}
pub fn panic_on_timeout(self) {
let _ = self;
}
}
#[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 {
pub fn is_enabled(&self) -> bool {
(self.front != StencilFaceState::IGNORE || self.back != StencilFaceState::IGNORE)
&& (self.read_mask != 0 || self.write_mask != 0)
}
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
}
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 {
pub fn is_enabled(&self) -> bool {
self.constant != 0 || self.slope_scale != 0.0
}
}
impl Hash for DepthBiasState {
fn hash<H: 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(C)]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DepthStencilState {
pub format: TextureFormat,
pub depth_write_enabled: bool,
pub depth_compare: CompareFunction,
#[cfg_attr(feature = "serde", serde(default))]
pub stencil: StencilState,
#[cfg_attr(feature = "serde", serde(default))]
pub bias: DepthBiasState,
}
impl DepthStencilState {
pub fn is_depth_enabled(&self) -> bool {
self.depth_compare != CompareFunction::Always || self.depth_write_enabled
}
pub fn is_depth_read_only(&self) -> bool {
!self.depth_write_enabled
}
pub fn is_stencil_read_only(&self, cull_mode: Option<Face>) -> bool {
self.stencil.is_read_only(cull_mode)
}
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(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,
}
#[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,
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,
};
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
}
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, 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,
Always = 8,
}
impl CompareFunction {
pub fn needs_ref_value(self) -> bool {
match self {
Self::Never | Self::Always => false,
_ => true,
}
}
}
#[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 VertexStepMode {
#[default]
Vertex = 0,
Instance = 1,
}
#[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 VertexAttribute {
pub format: VertexFormat,
pub offset: BufferAddress,
pub shader_location: ShaderLocation,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum VertexFormat {
Uint8x2 = 0,
Uint8x4 = 1,
Sint8x2 = 2,
Sint8x4 = 3,
Unorm8x2 = 4,
Unorm8x4 = 5,
Snorm8x2 = 6,
Snorm8x4 = 7,
Uint16x2 = 8,
Uint16x4 = 9,
Sint16x2 = 10,
Sint16x4 = 11,
Unorm16x2 = 12,
Unorm16x4 = 13,
Snorm16x2 = 14,
Snorm16x4 = 15,
Float16x2 = 16,
Float16x4 = 17,
Float32 = 18,
Float32x2 = 19,
Float32x3 = 20,
Float32x4 = 21,
Uint32 = 22,
Uint32x2 = 23,
Uint32x3 = 24,
Uint32x4 = 25,
Sint32 = 26,
Sint32x2 = 27,
Sint32x3 = 28,
Sint32x4 = 29,
Float64 = 30,
Float64x2 = 31,
Float64x3 = 32,
Float64x4 = 33,
#[cfg_attr(feature = "serde", serde(rename = "unorm10-10-10-2"))]
Unorm10_10_10_2 = 34,
}
impl VertexFormat {
pub const fn size(&self) -> u64 {
match self {
Self::Uint8x2 | Self::Sint8x2 | Self::Unorm8x2 | Self::Snorm8x2 => 2,
Self::Uint8x4
| Self::Sint8x4
| Self::Unorm8x4
| Self::Snorm8x4
| Self::Uint16x2
| Self::Sint16x2
| Self::Unorm16x2
| Self::Snorm16x2
| Self::Float16x2
| Self::Float32
| Self::Uint32
| Self::Sint32
| Self::Unorm10_10_10_2 => 4,
Self::Uint16x4
| Self::Sint16x4
| Self::Unorm16x4
| Self::Snorm16x4
| Self::Float16x4
| Self::Float32x2
| Self::Uint32x2
| Self::Sint32x2
| Self::Float64 => 8,
Self::Float32x3 | Self::Uint32x3 | Self::Sint32x3 => 12,
Self::Float32x4 | Self::Uint32x4 | Self::Sint32x4 | Self::Float64x2 => 16,
Self::Float64x3 => 24,
Self::Float64x4 => 32,
}
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct BufferUsages: u32 {
const MAP_READ = 1 << 0;
const MAP_WRITE = 1 << 1;
const COPY_SRC = 1 << 2;
const COPY_DST = 1 << 3;
const INDEX = 1 << 4;
const VERTEX = 1 << 5;
const UNIFORM = 1 << 6;
const STORAGE = 1 << 7;
const INDIRECT = 1 << 8;
const QUERY_RESOLVE = 1 << 9;
}
}
impl_bitflags!(BufferUsages);
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BufferDescriptor<L> {
pub label: L,
pub size: BufferAddress,
pub usage: BufferUsages,
pub mapped_at_creation: bool,
}
impl<L> BufferDescriptor<L> {
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> BufferDescriptor<K> {
BufferDescriptor {
label: fun(&self.label),
size: self.size,
usage: self.usage,
mapped_at_creation: self.mapped_at_creation,
}
}
}
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CommandEncoderDescriptor<L> {
pub label: L,
}
impl<L> CommandEncoderDescriptor<L> {
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> CommandEncoderDescriptor<K> {
CommandEncoderDescriptor {
label: fun(&self.label),
}
}
}
impl<T> Default for CommandEncoderDescriptor<Option<T>> {
fn default() -> Self {
Self { label: None }
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PresentMode {
AutoVsync = 0,
AutoNoVsync = 1,
#[default]
Fifo = 2,
FifoRelaxed = 3,
Immediate = 4,
Mailbox = 5,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum CompositeAlphaMode {
Auto = 0,
Opaque = 1,
PreMultiplied = 2,
PostMultiplied = 3,
Inherit = 4,
}
impl Default for CompositeAlphaMode {
fn default() -> Self {
Self::Auto
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TextureUsages: u32 {
const COPY_SRC = 1 << 0;
const COPY_DST = 1 << 1;
const TEXTURE_BINDING = 1 << 2;
const STORAGE_BINDING = 1 << 3;
const RENDER_ATTACHMENT = 1 << 4;
}
}
impl_bitflags!(TextureUsages);
#[derive(Debug)]
pub struct SurfaceCapabilities {
pub formats: Vec<TextureFormat>,
pub present_modes: Vec<PresentMode>,
pub alpha_modes: Vec<CompositeAlphaMode>,
pub usages: TextureUsages,
}
impl Default for SurfaceCapabilities {
fn default() -> Self {
Self {
formats: Vec::new(),
present_modes: Vec::new(),
alpha_modes: vec![CompositeAlphaMode::Opaque],
usages: TextureUsages::RENDER_ATTACHMENT,
}
}
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SurfaceConfiguration<V> {
pub usage: TextureUsages,
pub format: TextureFormat,
pub width: u32,
pub height: u32,
pub present_mode: PresentMode,
pub desired_maximum_frame_latency: u32,
pub alpha_mode: CompositeAlphaMode,
pub view_formats: V,
}
impl<V: Clone> SurfaceConfiguration<V> {
pub fn map_view_formats<M>(&self, fun: impl FnOnce(V) -> M) -> SurfaceConfiguration<M> {
SurfaceConfiguration {
usage: self.usage,
format: self.format,
width: self.width,
height: self.height,
present_mode: self.present_mode,
desired_maximum_frame_latency: self.desired_maximum_frame_latency,
alpha_mode: self.alpha_mode,
view_formats: fun(self.view_formats.clone()),
}
}
}
#[repr(C)]
#[derive(Debug)]
pub enum SurfaceStatus {
Good,
Suboptimal,
Timeout,
Outdated,
Lost,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PresentationTimestamp(
pub u128,
);
impl PresentationTimestamp {
pub const INVALID_TIMESTAMP: Self = Self(u128::MAX);
pub fn is_invalid(self) -> bool {
self == Self::INVALID_TIMESTAMP
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Color {
pub r: f64,
pub g: f64,
pub b: f64,
pub a: f64,
}
#[allow(missing_docs)]
impl Color {
pub const TRANSPARENT: Self = Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
};
pub const BLACK: Self = Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
pub const WHITE: Self = Self {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
};
pub const RED: Self = Self {
r: 1.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
pub const GREEN: Self = Self {
r: 0.0,
g: 1.0,
b: 0.0,
a: 1.0,
};
pub const BLUE: Self = Self {
r: 0.0,
g: 0.0,
b: 1.0,
a: 1.0,
};
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TextureDimension {
#[cfg_attr(feature = "serde", serde(rename = "1d"))]
D1,
#[cfg_attr(feature = "serde", serde(rename = "2d"))]
D2,
#[cfg_attr(feature = "serde", serde(rename = "3d"))]
D3,
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Origin2d {
#[allow(missing_docs)]
pub x: u32,
#[allow(missing_docs)]
pub y: u32,
}
impl Origin2d {
pub const ZERO: Self = Self { x: 0, y: 0 };
pub fn to_3d(self, z: u32) -> Origin3d {
Origin3d {
x: self.x,
y: self.y,
z,
}
}
}
impl std::fmt::Debug for Origin2d {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self.x, self.y).fmt(f)
}
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Origin3d {
pub x: u32,
pub y: u32,
pub z: u32,
}
impl Origin3d {
pub const ZERO: Self = Self { x: 0, y: 0, z: 0 };
pub fn to_2d(self) -> Origin2d {
Origin2d {
x: self.x,
y: self.y,
}
}
}
impl Default for Origin3d {
fn default() -> Self {
Self::ZERO
}
}
impl std::fmt::Debug for Origin3d {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self.x, self.y, self.z).fmt(f)
}
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Extent3d {
pub width: u32,
pub height: u32,
#[cfg_attr(feature = "serde", serde(default = "default_depth"))]
pub depth_or_array_layers: u32,
}
impl std::fmt::Debug for Extent3d {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self.width, self.height, self.depth_or_array_layers).fmt(f)
}
}
#[cfg(feature = "serde")]
fn default_depth() -> u32 {
1
}
impl Default for Extent3d {
fn default() -> Self {
Self {
width: 1,
height: 1,
depth_or_array_layers: 1,
}
}
}
impl Extent3d {
pub fn physical_size(&self, format: TextureFormat) -> Self {
let (block_width, block_height) = format.block_dimensions();
let width = ((self.width + block_width - 1) / block_width) * block_width;
let height = ((self.height + block_height - 1) / block_height) * block_height;
Self {
width,
height,
depth_or_array_layers: self.depth_or_array_layers,
}
}
pub fn max_mips(&self, dim: TextureDimension) -> u32 {
match dim {
TextureDimension::D1 => 1,
TextureDimension::D2 => {
let max_dim = self.width.max(self.height);
32 - max_dim.leading_zeros()
}
TextureDimension::D3 => {
let max_dim = self.width.max(self.height.max(self.depth_or_array_layers));
32 - max_dim.leading_zeros()
}
}
}
pub fn mip_level_size(&self, level: u32, dim: TextureDimension) -> Self {
Self {
width: u32::max(1, self.width >> level),
height: match dim {
TextureDimension::D1 => 1,
_ => u32::max(1, self.height >> level),
},
depth_or_array_layers: match dim {
TextureDimension::D1 => 1,
TextureDimension::D2 => self.depth_or_array_layers,
TextureDimension::D3 => u32::max(1, self.depth_or_array_layers >> level),
},
}
}
}
#[test]
fn test_physical_size() {
let format = TextureFormat::Bc1RgbaUnormSrgb; assert_eq!(
Extent3d {
width: 7,
height: 7,
depth_or_array_layers: 1
}
.physical_size(format),
Extent3d {
width: 8,
height: 8,
depth_or_array_layers: 1
}
);
assert_eq!(
Extent3d {
width: 8,
height: 8,
depth_or_array_layers: 1
}
.physical_size(format),
Extent3d {
width: 8,
height: 8,
depth_or_array_layers: 1
}
);
let format = TextureFormat::Astc {
block: AstcBlock::B8x5,
channel: AstcChannel::Unorm,
}; assert_eq!(
Extent3d {
width: 7,
height: 7,
depth_or_array_layers: 1
}
.physical_size(format),
Extent3d {
width: 8,
height: 10,
depth_or_array_layers: 1
}
);
}
#[test]
fn test_max_mips() {
assert_eq!(
Extent3d {
width: 240,
height: 1,
depth_or_array_layers: 1
}
.max_mips(TextureDimension::D1),
1
);
assert_eq!(
Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1
}
.max_mips(TextureDimension::D2),
1
);
assert_eq!(
Extent3d {
width: 60,
height: 60,
depth_or_array_layers: 1
}
.max_mips(TextureDimension::D2),
6
);
assert_eq!(
Extent3d {
width: 240,
height: 1,
depth_or_array_layers: 1000
}
.max_mips(TextureDimension::D2),
8
);
assert_eq!(
Extent3d {
width: 16,
height: 30,
depth_or_array_layers: 60
}
.max_mips(TextureDimension::D3),
6
);
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TextureDescriptor<L, V> {
pub label: L,
pub size: Extent3d,
pub mip_level_count: u32,
pub sample_count: u32,
pub dimension: TextureDimension,
pub format: TextureFormat,
pub usage: TextureUsages,
pub view_formats: V,
}
impl<L, V> TextureDescriptor<L, V> {
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> TextureDescriptor<K, V>
where
V: Clone,
{
TextureDescriptor {
label: fun(&self.label),
size: self.size,
mip_level_count: self.mip_level_count,
sample_count: self.sample_count,
dimension: self.dimension,
format: self.format,
usage: self.usage,
view_formats: self.view_formats.clone(),
}
}
pub fn map_label_and_view_formats<K, M>(
&self,
l_fun: impl FnOnce(&L) -> K,
v_fun: impl FnOnce(V) -> M,
) -> TextureDescriptor<K, M>
where
V: Clone,
{
TextureDescriptor {
label: l_fun(&self.label),
size: self.size,
mip_level_count: self.mip_level_count,
sample_count: self.sample_count,
dimension: self.dimension,
format: self.format,
usage: self.usage,
view_formats: v_fun(self.view_formats.clone()),
}
}
pub fn mip_level_size(&self, level: u32) -> Option<Extent3d> {
if level >= self.mip_level_count {
return None;
}
Some(self.size.mip_level_size(level, self.dimension))
}
pub fn compute_render_extent(&self, mip_level: u32) -> Extent3d {
Extent3d {
width: u32::max(1, self.size.width >> mip_level),
height: u32::max(1, self.size.height >> mip_level),
depth_or_array_layers: 1,
}
}
pub fn array_layer_count(&self) -> u32 {
match self.dimension {
TextureDimension::D1 | TextureDimension::D3 => 1,
TextureDimension::D2 => self.size.depth_or_array_layers,
}
}
}
#[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 TextureAspect {
#[default]
All,
StencilOnly,
DepthOnly,
Plane0,
Plane1,
Plane2,
}
#[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 AddressMode {
#[default]
ClampToEdge = 0,
Repeat = 1,
MirrorRepeat = 2,
ClampToBorder = 3,
}
#[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 FilterMode {
#[default]
Nearest = 0,
Linear = 1,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PushConstantRange {
pub stages: ShaderStages,
pub range: Range<u32>,
}
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CommandBufferDescriptor<L> {
pub label: L,
}
impl<L> CommandBufferDescriptor<L> {
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> CommandBufferDescriptor<K> {
CommandBufferDescriptor {
label: fun(&self.label),
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RenderBundleDepthStencil {
pub format: TextureFormat,
pub depth_read_only: bool,
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> {
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(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImageDataLayout {
pub offset: BufferAddress,
pub bytes_per_row: Option<u32>,
pub rows_per_image: Option<u32>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum BufferBindingType {
#[default]
Uniform,
Storage {
read_only: bool,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TextureSampleType {
Float {
filterable: bool,
},
Depth,
Sint,
Uint,
}
impl Default for TextureSampleType {
fn default() -> Self {
Self::Float { filterable: true }
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum StorageTextureAccess {
WriteOnly,
ReadOnly,
ReadWrite,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum SamplerBindingType {
Filtering,
NonFiltering,
Comparison,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum BindingType {
Buffer {
ty: BufferBindingType,
#[cfg_attr(feature = "serde", serde(default))]
has_dynamic_offset: bool,
#[cfg_attr(feature = "serde", serde(default))]
min_binding_size: Option<BufferSize>,
},
Sampler(SamplerBindingType),
Texture {
sample_type: TextureSampleType,
view_dimension: TextureViewDimension,
multisampled: bool,
},
StorageTexture {
access: StorageTextureAccess,
format: TextureFormat,
view_dimension: TextureViewDimension,
},
AccelerationStructure,
}
impl BindingType {
pub fn has_dynamic_offset(&self) -> bool {
match *self {
Self::Buffer {
has_dynamic_offset, ..
} => has_dynamic_offset,
_ => false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BindGroupLayoutEntry {
pub binding: u32,
pub visibility: ShaderStages,
pub ty: BindingType,
#[cfg_attr(feature = "serde", serde(default))]
pub count: Option<NonZeroU32>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImageCopyBuffer<B> {
pub buffer: B,
pub layout: ImageDataLayout,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImageCopyTexture<T> {
pub texture: T,
pub mip_level: u32,
#[cfg_attr(feature = "serde", serde(default))]
pub origin: Origin3d,
#[cfg_attr(feature = "serde", serde(default))]
pub aspect: TextureAspect,
}
impl<T> ImageCopyTexture<T> {
pub fn to_tagged(
self,
color_space: PredefinedColorSpace,
premultiplied_alpha: bool,
) -> ImageCopyTextureTagged<T> {
ImageCopyTextureTagged {
texture: self.texture,
mip_level: self.mip_level,
origin: self.origin,
aspect: self.aspect,
color_space,
premultiplied_alpha,
}
}
}
#[cfg(target_arch = "wasm32")]
#[derive(Clone, Debug)]
pub struct ImageCopyExternalImage {
pub source: ExternalImageSource,
pub origin: Origin2d,
pub flip_y: bool,
}
#[cfg(target_arch = "wasm32")]
#[derive(Clone, Debug)]
pub enum ExternalImageSource {
ImageBitmap(web_sys::ImageBitmap),
HTMLVideoElement(web_sys::HtmlVideoElement),
HTMLCanvasElement(web_sys::HtmlCanvasElement),
OffscreenCanvas(web_sys::OffscreenCanvas),
}
#[cfg(target_arch = "wasm32")]
impl ExternalImageSource {
pub fn width(&self) -> u32 {
match self {
ExternalImageSource::ImageBitmap(b) => b.width(),
ExternalImageSource::HTMLVideoElement(v) => v.video_width(),
ExternalImageSource::HTMLCanvasElement(c) => c.width(),
ExternalImageSource::OffscreenCanvas(c) => c.width(),
}
}
pub fn height(&self) -> u32 {
match self {
ExternalImageSource::ImageBitmap(b) => b.height(),
ExternalImageSource::HTMLVideoElement(v) => v.video_height(),
ExternalImageSource::HTMLCanvasElement(c) => c.height(),
ExternalImageSource::OffscreenCanvas(c) => c.height(),
}
}
}
#[cfg(target_arch = "wasm32")]
impl std::ops::Deref for ExternalImageSource {
type Target = js_sys::Object;
fn deref(&self) -> &Self::Target {
match self {
Self::ImageBitmap(b) => b,
Self::HTMLVideoElement(v) => v,
Self::HTMLCanvasElement(c) => c,
Self::OffscreenCanvas(c) => c,
}
}
}
#[cfg(all(
target_arch = "wasm32",
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
))]
unsafe impl Send for ExternalImageSource {}
#[cfg(all(
target_arch = "wasm32",
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
))]
unsafe impl Sync for ExternalImageSource {}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PredefinedColorSpace {
Srgb,
DisplayP3,
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImageCopyTextureTagged<T> {
pub texture: T,
pub mip_level: u32,
pub origin: Origin3d,
pub aspect: TextureAspect,
pub color_space: PredefinedColorSpace,
pub premultiplied_alpha: bool,
}
impl<T: Copy> ImageCopyTextureTagged<T> {
pub fn to_untagged(self) -> ImageCopyTexture<T> {
ImageCopyTexture {
texture: self.texture,
mip_level: self.mip_level,
origin: self.origin,
aspect: self.aspect,
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct ImageSubresourceRange {
pub aspect: TextureAspect,
pub base_mip_level: u32,
pub mip_level_count: Option<u32>,
pub base_array_layer: u32,
pub array_layer_count: Option<u32>,
}
impl ImageSubresourceRange {
pub fn is_full_resource(
&self,
format: TextureFormat,
mip_levels: u32,
array_layers: u32,
) -> bool {
let mip_level_count = self.mip_level_count.unwrap_or(mip_levels);
let array_layer_count = self.array_layer_count.unwrap_or(array_layers);
let aspect_eq = Some(format) == format.aspect_specific_format(self.aspect);
let base_mip_level_eq = self.base_mip_level == 0;
let mip_level_count_eq = mip_level_count == mip_levels;
let base_array_layer_eq = self.base_array_layer == 0;
let array_layer_count_eq = array_layer_count == array_layers;
aspect_eq
&& base_mip_level_eq
&& mip_level_count_eq
&& base_array_layer_eq
&& array_layer_count_eq
}
pub fn mip_range(&self, mip_level_count: u32) -> Range<u32> {
self.base_mip_level..match self.mip_level_count {
Some(mip_level_count) => self.base_mip_level + mip_level_count,
None => mip_level_count,
}
}
pub fn layer_range(&self, array_layer_count: u32) -> Range<u32> {
self.base_array_layer..match self.array_layer_count {
Some(array_layer_count) => self.base_array_layer + array_layer_count,
None => array_layer_count,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SamplerBorderColor {
TransparentBlack,
OpaqueBlack,
OpaqueWhite,
Zero,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct QuerySetDescriptor<L> {
pub label: L,
pub ty: QueryType,
pub count: u32,
}
impl<L> QuerySetDescriptor<L> {
pub fn map_label<'a, K>(&'a self, fun: impl FnOnce(&'a L) -> K) -> QuerySetDescriptor<K> {
QuerySetDescriptor {
label: fun(&self.label),
ty: self.ty,
count: self.count,
}
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum QueryType {
Occlusion,
PipelineStatistics(PipelineStatisticsTypes),
Timestamp,
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PipelineStatisticsTypes : u8 {
const VERTEX_SHADER_INVOCATIONS = 1 << 0;
const CLIPPER_INVOCATIONS = 1 << 1;
const CLIPPER_PRIMITIVES_OUT = 1 << 2;
const FRAGMENT_SHADER_INVOCATIONS = 1 << 3;
const COMPUTE_SHADER_INVOCATIONS = 1 << 4;
}
}
impl_bitflags!(PipelineStatisticsTypes);
#[repr(C)]
#[derive(Copy, Clone, Debug, Default)]
pub struct DrawIndirectArgs {
pub vertex_count: u32,
pub instance_count: u32,
pub first_vertex: u32,
pub first_instance: u32,
}
impl DrawIndirectArgs {
pub fn as_bytes(&self) -> &[u8] {
unsafe {
std::mem::transmute(std::slice::from_raw_parts(
self as *const _ as *const u8,
std::mem::size_of::<Self>(),
))
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default)]
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 {
pub fn as_bytes(&self) -> &[u8] {
unsafe {
std::mem::transmute(std::slice::from_raw_parts(
self as *const _ as *const u8,
std::mem::size_of::<Self>(),
))
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default)]
pub struct DispatchIndirectArgs {
pub x: u32,
pub y: u32,
pub z: u32,
}
impl DispatchIndirectArgs {
pub fn as_bytes(&self) -> &[u8] {
unsafe {
std::mem::transmute(std::slice::from_raw_parts(
self as *const _ as *const u8,
std::mem::size_of::<Self>(),
))
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ShaderBoundChecks {
runtime_checks: bool,
}
impl ShaderBoundChecks {
pub fn new() -> Self {
ShaderBoundChecks {
runtime_checks: true,
}
}
pub unsafe fn unchecked() -> Self {
ShaderBoundChecks {
runtime_checks: false,
}
}
pub fn runtime_checks(&self) -> bool {
self.runtime_checks
}
}
impl Default for ShaderBoundChecks {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Default)]
pub enum Dx12Compiler {
#[default]
Fxc,
Dxc {
dxil_path: Option<PathBuf>,
dxc_path: Option<PathBuf>,
},
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
pub enum Gles3MinorVersion {
#[default]
Automatic,
Version0,
Version1,
Version2,
}
#[derive(Debug)]
pub struct InstanceDescriptor {
pub backends: Backends,
pub flags: InstanceFlags,
pub dx12_shader_compiler: Dx12Compiler,
pub gles_minor_version: Gles3MinorVersion,
}
impl Default for InstanceDescriptor {
fn default() -> Self {
Self {
backends: Backends::all(),
flags: InstanceFlags::default(),
dx12_shader_compiler: Dx12Compiler::default(),
gles_minor_version: Gles3MinorVersion::default(),
}
}
}
bitflags::bitflags!(
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AccelerationStructureFlags: u8 {
const ALLOW_UPDATE = 1 << 0;
const ALLOW_COMPACTION = 1 << 1;
const PREFER_FAST_TRACE = 1 << 2;
const PREFER_FAST_BUILD = 1 << 3;
const LOW_MEMORY = 1 << 4;
}
);
impl_bitflags!(AccelerationStructureFlags);
bitflags::bitflags!(
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AccelerationStructureGeometryFlags: u8 {
const OPAQUE = 1 << 0;
const NO_DUPLICATE_ANY_HIT_INVOCATION = 1 << 1;
}
);
impl_bitflags!(AccelerationStructureGeometryFlags);
pub use send_sync::*;
#[doc(hidden)]
mod send_sync {
pub trait WasmNotSendSync: WasmNotSend + WasmNotSync {}
impl<T: WasmNotSend + WasmNotSync> WasmNotSendSync for T {}
#[cfg(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
))]
pub trait WasmNotSend: Send {}
#[cfg(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
))]
impl<T: Send> WasmNotSend for T {}
#[cfg(not(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
)))]
pub trait WasmNotSend {}
#[cfg(not(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
)))]
impl<T> WasmNotSend for T {}
#[cfg(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
))]
pub trait WasmNotSync: Sync {}
#[cfg(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
))]
impl<T: Sync> WasmNotSync for T {}
#[cfg(not(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
)))]
pub trait WasmNotSync {}
#[cfg(not(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
)))]
impl<T> WasmNotSync for T {}
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DeviceLostReason {
Unknown = 0,
Destroyed = 1,
Dropped = 2,
ReplacedCallback = 3,
DeviceInvalid = 4,
}