1103: Fix Assorted Low-Hanging Validation and Error Message Issues r=kvark a=cwfitzgerald

**Connections**

Closes #1085
Closes #393
Closes #1053

**Description**

These commits are independent and should be reviewed individually. Combined into a single PR to reduce noise.

Overview of what was done:
- Add validation for empty texture and buffer usage flags. (#393)
- Add allowed texture usage flags to `format.describe()` (#1085)
  Validate new textures follow the allowed usage flags.
- Properly validates vertex and buffers are bound. (#1053)
  Improves error messages when no vertex buffer is bound. (Before it said the limit was 0, now it says something is unbound)
- Improve the vertex buffer overrun messages by keeping track of which slot has the smallest index.

**Testing**

Tested on examples by artificially creating the situation I am trying to validate, as well as running clean examples to make sure they pass validation.

Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
bors[bot] 2020-12-22 04:29:38 +00:00 committed by GitHub
commit 2287ae3f8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 262 additions and 140 deletions

View File

@ -313,20 +313,22 @@ impl RenderBundleEncoder {
first_instance,
} => {
let scope = PassErrorScope::Draw;
let (vertex_limit, instance_limit) = state.vertex_limits();
let vertex_limits = state.vertex_limits();
let last_vertex = first_vertex + vertex_count;
if last_vertex > vertex_limit {
if last_vertex > vertex_limits.vertex_limit {
return Err(DrawError::VertexBeyondLimit {
last_vertex,
vertex_limit,
vertex_limit: vertex_limits.vertex_limit,
slot: vertex_limits.vertex_limit_slot,
})
.map_pass_err(scope);
}
let last_instance = first_instance + instance_count;
if last_instance > instance_limit {
if last_instance > vertex_limits.instance_limit {
return Err(DrawError::InstanceBeyondLimit {
last_instance,
instance_limit,
instance_limit: vertex_limits.instance_limit,
slot: vertex_limits.instance_limit_slot,
})
.map_pass_err(scope);
}
@ -343,7 +345,7 @@ impl RenderBundleEncoder {
} => {
let scope = PassErrorScope::DrawIndexed;
//TODO: validate that base_vertex + max_index() is within the provided range
let (_, instance_limit) = state.vertex_limits();
let vertex_limits = state.vertex_limits();
let index_limit = state.index.limit();
let last_index = first_index + index_count;
if last_index > index_limit {
@ -354,10 +356,11 @@ impl RenderBundleEncoder {
.map_pass_err(scope);
}
let last_instance = first_instance + instance_count;
if last_instance > instance_limit {
if last_instance > vertex_limits.instance_limit {
return Err(DrawError::InstanceBeyondLimit {
last_instance,
instance_limit,
instance_limit: vertex_limits.instance_limit,
slot: vertex_limits.instance_limit_slot,
})
.map_pass_err(scope);
}
@ -855,6 +858,18 @@ impl PushConstantState {
}
}
#[derive(Debug)]
struct VertexLimitState {
/// Length of the shortest vertex rate vertex buffer
vertex_limit: u32,
/// Buffer slot which the shortest vertex rate vertex buffer is bound to
vertex_limit_slot: u32,
/// Length of the shortest instance rate vertex buffer
instance_limit: u32,
/// Buffer slot which the shortest instance rate vertex buffer is bound to
instance_limit_slot: u32,
}
#[derive(Debug)]
struct State {
trackers: TrackerSet,
@ -869,20 +884,34 @@ struct State {
}
impl State {
fn vertex_limits(&self) -> (u32, u32) {
let mut vertex_limit = !0;
let mut instance_limit = !0;
for vbs in &self.vertex {
fn vertex_limits(&self) -> VertexLimitState {
let mut vert_state = VertexLimitState {
vertex_limit: u32::MAX,
vertex_limit_slot: 0,
instance_limit: u32::MAX,
instance_limit_slot: 0,
};
for (idx, vbs) in self.vertex.iter().enumerate() {
if vbs.stride == 0 {
continue;
}
let limit = ((vbs.range.end - vbs.range.start) / vbs.stride) as u32;
match vbs.rate {
wgt::InputStepMode::Vertex => vertex_limit = vertex_limit.min(limit),
wgt::InputStepMode::Instance => instance_limit = instance_limit.min(limit),
wgt::InputStepMode::Vertex => {
if limit < vert_state.vertex_limit {
vert_state.vertex_limit = limit;
vert_state.vertex_limit_slot = idx as _;
}
}
wgt::InputStepMode::Instance => {
if limit < vert_state.instance_limit {
vert_state.instance_limit = limit;
vert_state.instance_limit_slot = idx as _;
}
}
}
}
(vertex_limit, instance_limit)
vert_state
}
fn invalidate_group_from(&mut self, slot: usize) {

View File

@ -26,23 +26,37 @@ pub enum DrawError {
MissingBlendColor,
#[error("render pipeline must be set")]
MissingPipeline,
#[error("vertex buffer {index} must be set")]
MissingVertexBuffer { index: u32 },
#[error("index buffer must be set")]
MissingIndexBuffer,
#[error("current render pipeline has a layout which is incompatible with a currently set bind group, first differing at entry index {index}")]
IncompatibleBindGroup {
index: u32,
//expected: BindGroupLayoutId,
//provided: Option<(BindGroupLayoutId, BindGroupId)>,
},
#[error("vertex {last_vertex} extends beyond limit {vertex_limit}")]
VertexBeyondLimit { last_vertex: u32, vertex_limit: u32 },
#[error("instance {last_instance} extends beyond limit {instance_limit}")]
#[error("vertex {last_vertex} extends beyond limit {vertex_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Vertex` step-rate vertex buffer?")]
VertexBeyondLimit {
last_vertex: u32,
vertex_limit: u32,
slot: u32,
},
#[error("instance {last_instance} extends beyond limit {instance_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Instance` step-rate vertex buffer?")]
InstanceBeyondLimit {
last_instance: u32,
instance_limit: u32,
slot: u32,
},
#[error("index {last_index} extends beyond limit {index_limit}")]
#[error("index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")]
IndexBeyondLimit { last_index: u32, index_limit: u32 },
#[error("pipeline index format and buffer index format do not match")]
UnmatchedIndexFormats,
#[error(
"pipeline index format ({pipeline:?}) and buffer index format ({buffer:?}) do not match"
)]
UnmatchedIndexFormats {
pipeline: wgt::IndexFormat,
buffer: wgt::IndexFormat,
},
}
/// Error encountered when encoding a render command.

View File

@ -226,7 +226,7 @@ impl OptionalState {
#[derive(Debug, Default)]
struct IndexState {
bound_buffer_view: Option<(id::Valid<id::BufferId>, Range<BufferAddress>)>,
format: IndexFormat,
format: Option<IndexFormat>,
pipeline_format: Option<IndexFormat>,
limit: u32,
}
@ -235,7 +235,10 @@ impl IndexState {
fn update_limit(&mut self) {
self.limit = match self.bound_buffer_view {
Some((_, ref range)) => {
let shift = match self.format {
let format = self
.format
.expect("IndexState::update_limit must be called after a index buffer is set");
let shift = match format {
IndexFormat::Uint16 => 1,
IndexFormat::Uint32 => 2,
};
@ -256,6 +259,7 @@ struct VertexBufferState {
total_size: BufferAddress,
stride: BufferAddress,
rate: InputStepMode,
bound: bool,
}
impl VertexBufferState {
@ -263,28 +267,47 @@ impl VertexBufferState {
total_size: 0,
stride: 0,
rate: InputStepMode::Vertex,
bound: false,
};
}
#[derive(Debug, Default)]
struct VertexState {
inputs: ArrayVec<[VertexBufferState; MAX_VERTEX_BUFFERS]>,
/// Length of the shortest vertex rate vertex buffer
vertex_limit: u32,
/// Buffer slot which the shortest vertex rate vertex buffer is bound to
vertex_limit_slot: u32,
/// Length of the shortest instance rate vertex buffer
instance_limit: u32,
/// Buffer slot which the shortest instance rate vertex buffer is bound to
instance_limit_slot: u32,
/// Total amount of buffers required by the pipeline.
buffers_required: u32,
}
impl VertexState {
fn update_limits(&mut self) {
self.vertex_limit = !0;
self.instance_limit = !0;
for vbs in &self.inputs {
if vbs.stride == 0 {
self.vertex_limit = u32::MAX;
self.instance_limit = u32::MAX;
for (idx, vbs) in self.inputs.iter().enumerate() {
if vbs.stride == 0 || !vbs.bound {
continue;
}
let limit = (vbs.total_size / vbs.stride) as u32;
match vbs.rate {
InputStepMode::Vertex => self.vertex_limit = self.vertex_limit.min(limit),
InputStepMode::Instance => self.instance_limit = self.instance_limit.min(limit),
InputStepMode::Vertex => {
if limit < self.vertex_limit {
self.vertex_limit = limit;
self.vertex_limit_slot = idx as _;
}
}
InputStepMode::Instance => {
if limit < self.instance_limit {
self.instance_limit = limit;
self.instance_limit_slot = idx as _;
}
}
}
}
}
@ -310,7 +333,15 @@ struct State {
impl State {
fn is_ready(&self) -> Result<(), DrawError> {
//TODO: vertex buffers
// Determine how many vertex buffers have already been bound
let bound_buffers = self.vertex.inputs.iter().take_while(|v| v.bound).count() as u32;
// Compare with the needed quantity
if bound_buffers < self.vertex.buffers_required {
return Err(DrawError::MissingVertexBuffer {
index: bound_buffers,
});
}
let bind_mask = self.binder.invalid_mask();
if bind_mask != 0 {
//let (expected, provided) = self.binder.entries[index as usize].info();
@ -324,9 +355,17 @@ impl State {
if self.blend_color == OptionalState::Required {
return Err(DrawError::MissingBlendColor);
}
// Pipeline expects an index buffer
if let Some(pipeline_index_format) = self.index.pipeline_format {
if pipeline_index_format != self.index.format {
return Err(DrawError::UnmatchedIndexFormats);
// We have a buffer bound
let buffer_index_format = self.index.format.ok_or(DrawError::MissingIndexBuffer)?;
// The buffers are different formats
if pipeline_index_format != buffer_index_format {
return Err(DrawError::UnmatchedIndexFormats {
pipeline: pipeline_index_format,
buffer: buffer_index_format,
});
}
}
Ok(())
@ -1188,9 +1227,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
state.index.pipeline_format = pipeline.index_format;
let vertex_strides_len = pipeline.vertex_strides.len();
state.vertex.buffers_required = vertex_strides_len as u32;
while state.vertex.inputs.len() < vertex_strides_len {
state.vertex.inputs.push(VertexBufferState::EMPTY);
}
// Update vertex buffer limits
for (vbs, &(stride, rate)) in
state.vertex.inputs.iter_mut().zip(&pipeline.vertex_strides)
@ -1229,14 +1271,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
};
state.index.bound_buffer_view = Some((id::Valid(buffer_id), offset..end));
state.index.format = index_format;
state.index.format = Some(index_format);
state.index.update_limit();
let range = hal::buffer::SubRange {
offset,
size: Some(end - offset),
};
let index_type = conv::map_index_format(state.index.format);
let index_type = conv::map_index_format(index_format);
unsafe {
raw.bind_index_buffer(buf_raw, range, index_type);
}
@ -1265,10 +1307,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.vertex
.inputs
.extend(iter::repeat(VertexBufferState::EMPTY).take(empty_slots));
state.vertex.inputs[slot as usize].total_size = match size {
let vertex_state = &mut state.vertex.inputs[slot as usize];
vertex_state.total_size = match size {
Some(s) => s.get(),
None => buffer.size - offset,
};
vertex_state.bound = true;
let range = hal::buffer::SubRange {
offset,
@ -1400,6 +1444,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(DrawError::VertexBeyondLimit {
last_vertex,
vertex_limit,
slot: state.vertex.vertex_limit_slot,
})
.map_pass_err(scope);
}
@ -1409,6 +1454,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(DrawError::InstanceBeyondLimit {
last_instance,
instance_limit,
slot: state.vertex.instance_limit_slot,
})
.map_pass_err(scope);
}
@ -1446,6 +1492,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(DrawError::InstanceBeyondLimit {
last_instance,
instance_limit,
slot: state.vertex.instance_limit_slot,
})
.map_pass_err(scope);
}

View File

@ -438,6 +438,10 @@ impl<B: GfxBackend> Device<B> {
}
}
if desc.usage.is_empty() {
return Err(resource::CreateBufferError::EmptyUsage);
}
let mem_usage = {
use gpu_alloc::UsageFlags as Uf;
use wgt::BufferUsage as Bu;
@ -516,7 +520,8 @@ impl<B: GfxBackend> Device<B> {
) -> Result<resource::Texture<B>, resource::CreateTextureError> {
debug_assert_eq!(self_id.backend(), B::VARIANT);
let features = desc.format.describe().features;
let format_desc = desc.format.describe();
let features = format_desc.features;
if !self.features.contains(features) {
return Err(resource::CreateTextureError::MissingFeature(
features,
@ -537,6 +542,18 @@ impl<B: GfxBackend> Device<B> {
_ => {}
}
if desc.usage.is_empty() {
return Err(resource::CreateTextureError::EmptyUsage);
}
let missing_features = desc.usage - format_desc.allowed_usages;
if !missing_features.is_empty() {
return Err(resource::CreateTextureError::InvalidUsages(
missing_features,
desc.format,
));
}
let kind = conv::map_texture_dimension_size(desc.dimension, desc.size, desc.sample_count)?;
let format = conv::map_texture_format(desc.format, self.private_features);
let aspects = format.surface_desc().aspects;

View File

@ -174,6 +174,8 @@ pub enum CreateBufferError {
AccessError(#[from] BufferAccessError),
#[error("buffers that are mapped at creation have to be aligned to `COPY_BUFFER_ALIGNMENT`")]
UnalignedSize,
#[error("Buffers cannot have empty usage flags")]
EmptyUsage,
#[error("`MAP` usage can only be combined with the opposite `COPY`, requested {0:?}")]
UsageMismatch(wgt::BufferUsage),
}
@ -230,10 +232,14 @@ pub enum CreateTextureError {
Device(#[from] DeviceError),
#[error("D24Plus textures cannot be copied")]
CannotCopyD24Plus,
#[error("Textures cannot have empty usage flags")]
EmptyUsage,
#[error(transparent)]
InvalidDimension(#[from] TextureDimensionError),
#[error("texture descriptor mip level count ({0}) is invalid")]
InvalidMipLevelCount(u32),
#[error("The texture usages {0:?} are not allowed on a texture of type {1:?}")]
InvalidUsages(wgt::TextureUsage, wgt::TextureFormat),
#[error("Feature {0:?} must be enabled to create a texture of type {1:?}")]
MissingFeature(wgt::Features, wgt::TextureFormat),
}

View File

@ -766,6 +766,8 @@ pub struct TextureFormatInfo {
pub block_size: u8,
/// Format will have colors be converted from srgb to linear on read and from linear to srgb on write.
pub srgb: bool,
/// Allowed usage flags for the format.
pub allowed_usages: TextureUsage,
}
/// Underlying texture data format.
@ -1158,135 +1160,141 @@ pub enum TextureFormat {
impl TextureFormat {
/// Get useful information about the texture format.
pub fn describe(&self) -> TextureFormatInfo {
#![allow(bindings_with_variant_name, non_snake_case)]
// Features
let NATIVE = Features::empty();
let BC = Features::TEXTURE_COMPRESSION_BC;
let ETC2 = Features::TEXTURE_COMPRESSION_ETC2;
let ASTC_LDR = Features::TEXTURE_COMPRESSION_ASTC_LDR;
let native = Features::empty();
let bc = Features::TEXTURE_COMPRESSION_BC;
let etc2 = Features::TEXTURE_COMPRESSION_ETC2;
let astc_ldr = Features::TEXTURE_COMPRESSION_ASTC_LDR;
// Sample Types
let Uint = TextureSampleType::Uint;
let Sint = TextureSampleType::Sint;
let Nearest = TextureSampleType::Float { filterable: false };
let Float = TextureSampleType::Float { filterable: true };
let Depth = TextureSampleType::Depth;
let uint = TextureSampleType::Uint;
let sint = TextureSampleType::Sint;
let nearest = TextureSampleType::Float { filterable: false };
let float = TextureSampleType::Float { filterable: true };
let depth = TextureSampleType::Depth;
// Color spaces
let Linear = false;
let Srgb = true;
let linear = false;
let srgb = true;
let (features, sample_type, srgb, block_dimensions, block_size) = match self {
// Flags
let basic = TextureUsage::COPY_SRC | TextureUsage::COPY_DST | TextureUsage::SAMPLED;
let attachment = basic | TextureUsage::RENDER_ATTACHMENT;
let storage = basic | TextureUsage::STORAGE;
let all_flags = TextureUsage::all();
// See https://gpuweb.github.io/gpuweb/#texture-format-caps for reference
let (features, sample_type, srgb, block_dimensions, block_size, allowed_usages) = match self
{
// Normal 8 bit textures
Self::R8Unorm => (NATIVE, Float, Linear, (1, 1), 1),
Self::R8Snorm => (NATIVE, Float, Linear, (1, 1), 1),
Self::R8Uint => (NATIVE, Uint, Linear, (1, 1), 1),
Self::R8Sint => (NATIVE, Sint, Linear, (1, 1), 1),
Self::R8Unorm => (native, float, linear, (1, 1), 1, attachment),
Self::R8Snorm => (native, float, linear, (1, 1), 1, basic),
Self::R8Uint => (native, uint, linear, (1, 1), 1, attachment),
Self::R8Sint => (native, sint, linear, (1, 1), 1, attachment),
// Normal 16 bit textures
Self::R16Uint => (NATIVE, Uint, Linear, (1, 1), 2),
Self::R16Sint => (NATIVE, Sint, Linear, (1, 1), 2),
Self::R16Float => (NATIVE, Float, Linear, (1, 1), 2),
Self::Rg8Unorm => (NATIVE, Float, Linear, (1, 1), 2),
Self::Rg8Snorm => (NATIVE, Float, Linear, (1, 1), 2),
Self::Rg8Uint => (NATIVE, Uint, Linear, (1, 1), 2),
Self::Rg8Sint => (NATIVE, Sint, Linear, (1, 1), 2),
Self::R16Uint => (native, uint, linear, (1, 1), 2, attachment),
Self::R16Sint => (native, sint, linear, (1, 1), 2, attachment),
Self::R16Float => (native, float, linear, (1, 1), 2, attachment),
Self::Rg8Unorm => (native, float, linear, (1, 1), 2, attachment),
Self::Rg8Snorm => (native, float, linear, (1, 1), 2, attachment),
Self::Rg8Uint => (native, uint, linear, (1, 1), 2, attachment),
Self::Rg8Sint => (native, sint, linear, (1, 1), 2, basic),
// Normal 32 bit textures
Self::R32Uint => (NATIVE, Uint, Linear, (1, 1), 4),
Self::R32Sint => (NATIVE, Sint, Linear, (1, 1), 4),
Self::R32Float => (NATIVE, Nearest, Linear, (1, 1), 4),
Self::Rg16Uint => (NATIVE, Uint, Linear, (1, 1), 4),
Self::Rg16Sint => (NATIVE, Sint, Linear, (1, 1), 4),
Self::Rg16Float => (NATIVE, Float, Linear, (1, 1), 4),
Self::Rgba8Unorm => (NATIVE, Float, Linear, (1, 1), 4),
Self::Rgba8UnormSrgb => (NATIVE, Float, Srgb, (1, 1), 4),
Self::Rgba8Snorm => (NATIVE, Float, Linear, (1, 1), 4),
Self::Rgba8Uint => (NATIVE, Uint, Linear, (1, 1), 4),
Self::Rgba8Sint => (NATIVE, Sint, Linear, (1, 1), 4),
Self::Bgra8Unorm => (NATIVE, Float, Linear, (1, 1), 4),
Self::Bgra8UnormSrgb => (NATIVE, Float, Srgb, (1, 1), 4),
Self::R32Uint => (native, uint, linear, (1, 1), 4, all_flags),
Self::R32Sint => (native, sint, linear, (1, 1), 4, all_flags),
Self::R32Float => (native, nearest, linear, (1, 1), 4, all_flags),
Self::Rg16Uint => (native, uint, linear, (1, 1), 4, attachment),
Self::Rg16Sint => (native, sint, linear, (1, 1), 4, attachment),
Self::Rg16Float => (native, float, linear, (1, 1), 4, attachment),
Self::Rgba8Unorm => (native, float, linear, (1, 1), 4, all_flags),
Self::Rgba8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment),
Self::Rgba8Snorm => (native, float, linear, (1, 1), 4, storage),
Self::Rgba8Uint => (native, uint, linear, (1, 1), 4, all_flags),
Self::Rgba8Sint => (native, sint, linear, (1, 1), 4, all_flags),
Self::Bgra8Unorm => (native, float, linear, (1, 1), 4, attachment),
Self::Bgra8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment),
// Packed 32 bit textures
Self::Rgb10a2Unorm => (NATIVE, Float, Linear, (1, 1), 4),
Self::Rg11b10Float => (NATIVE, Float, Linear, (1, 1), 4),
Self::Rgb10a2Unorm => (native, float, linear, (1, 1), 4, attachment),
Self::Rg11b10Float => (native, float, linear, (1, 1), 4, basic),
// Packed 32 bit textures
Self::Rg32Uint => (NATIVE, Uint, Linear, (1, 1), 8),
Self::Rg32Sint => (NATIVE, Sint, Linear, (1, 1), 8),
Self::Rg32Float => (NATIVE, Nearest, Linear, (1, 1), 8),
Self::Rgba16Uint => (NATIVE, Uint, Linear, (1, 1), 8),
Self::Rgba16Sint => (NATIVE, Sint, Linear, (1, 1), 8),
Self::Rgba16Float => (NATIVE, Float, Linear, (1, 1), 8),
Self::Rg32Uint => (native, uint, linear, (1, 1), 8, all_flags),
Self::Rg32Sint => (native, sint, linear, (1, 1), 8, all_flags),
Self::Rg32Float => (native, nearest, linear, (1, 1), 8, all_flags),
Self::Rgba16Uint => (native, uint, linear, (1, 1), 8, all_flags),
Self::Rgba16Sint => (native, sint, linear, (1, 1), 8, all_flags),
Self::Rgba16Float => (native, float, linear, (1, 1), 8, all_flags),
// Packed 32 bit textures
Self::Rgba32Uint => (NATIVE, Uint, Linear, (1, 1), 16),
Self::Rgba32Sint => (NATIVE, Sint, Linear, (1, 1), 16),
Self::Rgba32Float => (NATIVE, Nearest, Linear, (1, 1), 16),
Self::Rgba32Uint => (native, uint, linear, (1, 1), 16, all_flags),
Self::Rgba32Sint => (native, sint, linear, (1, 1), 16, all_flags),
Self::Rgba32Float => (native, nearest, linear, (1, 1), 16, all_flags),
// Depth-stencil textures
Self::Depth32Float => (NATIVE, Depth, Linear, (1, 1), 4),
Self::Depth24Plus => (NATIVE, Depth, Linear, (1, 1), 4),
Self::Depth24PlusStencil8 => (NATIVE, Depth, Linear, (1, 1), 4),
Self::Depth32Float => (native, depth, linear, (1, 1), 4, attachment),
Self::Depth24Plus => (native, depth, linear, (1, 1), 4, attachment),
Self::Depth24PlusStencil8 => (native, depth, linear, (1, 1), 4, attachment),
// BCn compressed textures
Self::Bc1RgbaUnorm => (BC, Float, Linear, (4, 4), 8),
Self::Bc1RgbaUnormSrgb => (BC, Float, Srgb, (4, 4), 8),
Self::Bc2RgbaUnorm => (BC, Float, Linear, (4, 4), 16),
Self::Bc2RgbaUnormSrgb => (BC, Float, Srgb, (4, 4), 16),
Self::Bc3RgbaUnorm => (BC, Float, Linear, (4, 4), 16),
Self::Bc3RgbaUnormSrgb => (BC, Float, Srgb, (4, 4), 16),
Self::Bc4RUnorm => (BC, Float, Linear, (4, 4), 8),
Self::Bc4RSnorm => (BC, Float, Linear, (4, 4), 8),
Self::Bc5RgUnorm => (BC, Float, Linear, (4, 4), 16),
Self::Bc5RgSnorm => (BC, Float, Linear, (4, 4), 16),
Self::Bc6hRgbUfloat => (BC, Float, Linear, (4, 4), 16),
Self::Bc6hRgbSfloat => (BC, Float, Linear, (4, 4), 16),
Self::Bc7RgbaUnorm => (BC, Float, Linear, (4, 4), 16),
Self::Bc7RgbaUnormSrgb => (BC, Float, Srgb, (4, 4), 16),
Self::Bc1RgbaUnorm => (bc, float, linear, (4, 4), 8, basic),
Self::Bc1RgbaUnormSrgb => (bc, float, srgb, (4, 4), 8, basic),
Self::Bc2RgbaUnorm => (bc, float, linear, (4, 4), 16, basic),
Self::Bc2RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic),
Self::Bc3RgbaUnorm => (bc, float, linear, (4, 4), 16, basic),
Self::Bc3RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic),
Self::Bc4RUnorm => (bc, float, linear, (4, 4), 8, basic),
Self::Bc4RSnorm => (bc, float, linear, (4, 4), 8, basic),
Self::Bc5RgUnorm => (bc, float, linear, (4, 4), 16, basic),
Self::Bc5RgSnorm => (bc, float, linear, (4, 4), 16, basic),
Self::Bc6hRgbUfloat => (bc, float, linear, (4, 4), 16, basic),
Self::Bc6hRgbSfloat => (bc, float, linear, (4, 4), 16, basic),
Self::Bc7RgbaUnorm => (bc, float, linear, (4, 4), 16, basic),
Self::Bc7RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic),
// ETC compressed textures
Self::Etc2RgbUnorm => (ETC2, Float, Linear, (4, 4), 8),
Self::Etc2RgbUnormSrgb => (ETC2, Float, Srgb, (4, 4), 8),
Self::Etc2RgbA1Unorm => (ETC2, Float, Linear, (4, 4), 8),
Self::Etc2RgbA1UnormSrgb => (ETC2, Float, Srgb, (4, 4), 8),
Self::Etc2RgbA8Unorm => (ETC2, Float, Linear, (4, 4), 16),
Self::Etc2RgbA8UnormSrgb => (ETC2, Float, Srgb, (4, 4), 16),
Self::EacRUnorm => (ETC2, Float, Linear, (4, 4), 8),
Self::EacRSnorm => (ETC2, Float, Linear, (4, 4), 8),
Self::EtcRgUnorm => (ETC2, Float, Linear, (4, 4), 16),
Self::EtcRgSnorm => (ETC2, Float, Linear, (4, 4), 16),
Self::Etc2RgbUnorm => (etc2, float, linear, (4, 4), 8, basic),
Self::Etc2RgbUnormSrgb => (etc2, float, srgb, (4, 4), 8, basic),
Self::Etc2RgbA1Unorm => (etc2, float, linear, (4, 4), 8, basic),
Self::Etc2RgbA1UnormSrgb => (etc2, float, srgb, (4, 4), 8, basic),
Self::Etc2RgbA8Unorm => (etc2, float, linear, (4, 4), 16, basic),
Self::Etc2RgbA8UnormSrgb => (etc2, float, srgb, (4, 4), 16, basic),
Self::EacRUnorm => (etc2, float, linear, (4, 4), 8, basic),
Self::EacRSnorm => (etc2, float, linear, (4, 4), 8, basic),
Self::EtcRgUnorm => (etc2, float, linear, (4, 4), 16, basic),
Self::EtcRgSnorm => (etc2, float, linear, (4, 4), 16, basic),
// ASTC compressed textures
Self::Astc4x4RgbaUnorm => (ASTC_LDR, Float, Linear, (4, 4), 16),
Self::Astc4x4RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (4, 4), 16),
Self::Astc5x4RgbaUnorm => (ASTC_LDR, Float, Linear, (5, 4), 16),
Self::Astc5x4RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (5, 4), 16),
Self::Astc5x5RgbaUnorm => (ASTC_LDR, Float, Linear, (5, 5), 16),
Self::Astc5x5RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (5, 5), 16),
Self::Astc6x5RgbaUnorm => (ASTC_LDR, Float, Linear, (6, 5), 16),
Self::Astc6x5RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (6, 5), 16),
Self::Astc6x6RgbaUnorm => (ASTC_LDR, Float, Linear, (6, 6), 16),
Self::Astc6x6RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (6, 6), 16),
Self::Astc8x5RgbaUnorm => (ASTC_LDR, Float, Linear, (8, 5), 16),
Self::Astc8x5RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (8, 5), 16),
Self::Astc8x6RgbaUnorm => (ASTC_LDR, Float, Linear, (8, 6), 16),
Self::Astc8x6RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (8, 6), 16),
Self::Astc10x5RgbaUnorm => (ASTC_LDR, Float, Linear, (10, 5), 16),
Self::Astc10x5RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (10, 5), 16),
Self::Astc10x6RgbaUnorm => (ASTC_LDR, Float, Linear, (10, 6), 16),
Self::Astc10x6RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (10, 6), 16),
Self::Astc8x8RgbaUnorm => (ASTC_LDR, Float, Linear, (8, 8), 16),
Self::Astc8x8RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (8, 8), 16),
Self::Astc10x8RgbaUnorm => (ASTC_LDR, Float, Linear, (10, 8), 16),
Self::Astc10x8RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (10, 8), 16),
Self::Astc10x10RgbaUnorm => (ASTC_LDR, Float, Linear, (10, 10), 16),
Self::Astc10x10RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (10, 10), 16),
Self::Astc12x10RgbaUnorm => (ASTC_LDR, Float, Linear, (12, 10), 16),
Self::Astc12x10RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (12, 10), 16),
Self::Astc12x12RgbaUnorm => (ASTC_LDR, Float, Linear, (12, 12), 16),
Self::Astc12x12RgbaUnormSrgb => (ASTC_LDR, Float, Srgb, (12, 12), 16),
Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, (4, 4), 16, basic),
Self::Astc4x4RgbaUnormSrgb => (astc_ldr, float, srgb, (4, 4), 16, basic),
Self::Astc5x4RgbaUnorm => (astc_ldr, float, linear, (5, 4), 16, basic),
Self::Astc5x4RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 4), 16, basic),
Self::Astc5x5RgbaUnorm => (astc_ldr, float, linear, (5, 5), 16, basic),
Self::Astc5x5RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 5), 16, basic),
Self::Astc6x5RgbaUnorm => (astc_ldr, float, linear, (6, 5), 16, basic),
Self::Astc6x5RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 5), 16, basic),
Self::Astc6x6RgbaUnorm => (astc_ldr, float, linear, (6, 6), 16, basic),
Self::Astc6x6RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 6), 16, basic),
Self::Astc8x5RgbaUnorm => (astc_ldr, float, linear, (8, 5), 16, basic),
Self::Astc8x5RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 5), 16, basic),
Self::Astc8x6RgbaUnorm => (astc_ldr, float, linear, (8, 6), 16, basic),
Self::Astc8x6RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 6), 16, basic),
Self::Astc10x5RgbaUnorm => (astc_ldr, float, linear, (10, 5), 16, basic),
Self::Astc10x5RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 5), 16, basic),
Self::Astc10x6RgbaUnorm => (astc_ldr, float, linear, (10, 6), 16, basic),
Self::Astc10x6RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 6), 16, basic),
Self::Astc8x8RgbaUnorm => (astc_ldr, float, linear, (8, 8), 16, basic),
Self::Astc8x8RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 8), 16, basic),
Self::Astc10x8RgbaUnorm => (astc_ldr, float, linear, (10, 8), 16, basic),
Self::Astc10x8RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 8), 16, basic),
Self::Astc10x10RgbaUnorm => (astc_ldr, float, linear, (10, 10), 16, basic),
Self::Astc10x10RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 10), 16, basic),
Self::Astc12x10RgbaUnorm => (astc_ldr, float, linear, (12, 10), 16, basic),
Self::Astc12x10RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 10), 16, basic),
Self::Astc12x12RgbaUnorm => (astc_ldr, float, linear, (12, 12), 16, basic),
Self::Astc12x12RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 12), 16, basic),
};
TextureFormatInfo {
@ -1295,6 +1303,7 @@ impl TextureFormat {
block_dimensions,
block_size,
srgb,
allowed_usages,
}
}
}