mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Add limits for textures sizes and vertex imputs
This commit is contained in:
parent
103e7763a3
commit
62ca24580d
@ -89,8 +89,14 @@ pub enum CreateBindGroupError {
|
||||
SwapChainImage,
|
||||
#[error("buffer offset {0} does not respect `BIND_BUFFER_ALIGNMENT`")]
|
||||
UnalignedBufferOffset(wgt::BufferAddress),
|
||||
#[error("uniform buffer binding range exceeds `max_uniform_buffer_binding_size` limit")]
|
||||
UniformBufferRangeTooLarge,
|
||||
#[error(
|
||||
"buffer binding {binding} range {given} exceeds `max_*_buffer_binding_size` limit {limit}"
|
||||
)]
|
||||
BufferRangeTooLarge {
|
||||
binding: u32,
|
||||
given: u32,
|
||||
limit: u32,
|
||||
},
|
||||
#[error("binding {binding} has a different type ({actual:?}) than the one in the layout ({expected:?})")]
|
||||
WrongBindingType {
|
||||
// Index of the binding
|
||||
|
||||
@ -521,49 +521,60 @@ pub fn map_texture_dimension_size(
|
||||
depth_or_array_layers,
|
||||
}: wgt::Extent3d,
|
||||
sample_size: u32,
|
||||
limits: &wgt::Limits,
|
||||
) -> Result<hal::image::Kind, resource::TextureDimensionError> {
|
||||
use hal::image::Kind as H;
|
||||
use resource::TextureDimensionError as Tde;
|
||||
use resource::{TextureDimensionError as Tde, TextureErrorDimension as Ted};
|
||||
use wgt::TextureDimension::*;
|
||||
|
||||
let zero_dim = if width == 0 {
|
||||
Some(resource::TextureErrorDimension::X)
|
||||
} else if height == 0 {
|
||||
Some(resource::TextureErrorDimension::Y)
|
||||
} else if depth_or_array_layers == 0 {
|
||||
Some(resource::TextureErrorDimension::Z)
|
||||
} else {
|
||||
None
|
||||
let layers = depth_or_array_layers.try_into().unwrap_or(!0);
|
||||
let (kind, extent_limits, sample_limit) = match dimension {
|
||||
D1 => (
|
||||
H::D1(width, layers),
|
||||
[
|
||||
limits.max_texture_dimension_1d,
|
||||
1,
|
||||
limits.max_texture_array_layers,
|
||||
],
|
||||
1,
|
||||
),
|
||||
D2 => (
|
||||
H::D2(width, height, layers, sample_size as u8),
|
||||
[
|
||||
limits.max_texture_dimension_2d,
|
||||
limits.max_texture_dimension_2d,
|
||||
limits.max_texture_array_layers,
|
||||
],
|
||||
32,
|
||||
),
|
||||
D3 => (
|
||||
H::D3(width, height, depth_or_array_layers),
|
||||
[
|
||||
limits.max_texture_dimension_3d,
|
||||
limits.max_texture_dimension_3d,
|
||||
limits.max_texture_dimension_3d,
|
||||
],
|
||||
1,
|
||||
),
|
||||
};
|
||||
if let Some(dim) = zero_dim {
|
||||
return Err(resource::TextureDimensionError::Zero(dim));
|
||||
|
||||
for (&dim, (&given, &limit)) in [Ted::X, Ted::Y, Ted::Z].iter().zip(
|
||||
[width, height, depth_or_array_layers]
|
||||
.iter()
|
||||
.zip(extent_limits.iter()),
|
||||
) {
|
||||
if given == 0 {
|
||||
return Err(Tde::Zero(dim));
|
||||
}
|
||||
if given > limit {
|
||||
return Err(Tde::LimitExceeded { dim, given, limit });
|
||||
}
|
||||
}
|
||||
if sample_size == 0 || sample_size > sample_limit || !is_power_of_two(sample_size) {
|
||||
return Err(Tde::InvalidSampleCount(sample_size));
|
||||
}
|
||||
|
||||
Ok(match dimension {
|
||||
D1 => {
|
||||
if height != 1 {
|
||||
return Err(Tde::InvalidHeight);
|
||||
}
|
||||
if sample_size != 1 {
|
||||
return Err(Tde::InvalidSampleCount(sample_size));
|
||||
}
|
||||
let layers = depth_or_array_layers.try_into().unwrap_or(!0);
|
||||
H::D1(width, layers)
|
||||
}
|
||||
D2 => {
|
||||
if sample_size > 32 || !is_power_of_two(sample_size) {
|
||||
return Err(Tde::InvalidSampleCount(sample_size));
|
||||
}
|
||||
let layers = depth_or_array_layers.try_into().unwrap_or(!0);
|
||||
H::D2(width, height, layers, sample_size as u8)
|
||||
}
|
||||
D3 => {
|
||||
if sample_size != 1 {
|
||||
return Err(Tde::InvalidSampleCount(sample_size));
|
||||
}
|
||||
H::D3(width, height, depth_or_array_layers)
|
||||
}
|
||||
})
|
||||
Ok(kind)
|
||||
}
|
||||
|
||||
pub fn map_texture_view_dimension(dimension: wgt::TextureViewDimension) -> hal::image::ViewKind {
|
||||
|
||||
@ -643,7 +643,12 @@ impl<B: GfxBackend> Device<B> {
|
||||
));
|
||||
}
|
||||
|
||||
let kind = conv::map_texture_dimension_size(desc.dimension, desc.size, desc.sample_count)?;
|
||||
let kind = conv::map_texture_dimension_size(
|
||||
desc.dimension,
|
||||
desc.size,
|
||||
desc.sample_count,
|
||||
&self.limits,
|
||||
)?;
|
||||
let format = conv::map_texture_format(desc.format, self.private_features);
|
||||
let aspects = format.surface_desc().aspects;
|
||||
let usage = conv::map_texture_usage(desc.usage, aspects);
|
||||
@ -1312,10 +1317,12 @@ impl<B: GfxBackend> Device<B> {
|
||||
})
|
||||
}
|
||||
};
|
||||
let (pub_usage, internal_use) = match binding_ty {
|
||||
wgt::BufferBindingType::Uniform => {
|
||||
(wgt::BufferUsage::UNIFORM, resource::BufferUse::UNIFORM)
|
||||
}
|
||||
let (pub_usage, internal_use, range_limit) = match binding_ty {
|
||||
wgt::BufferBindingType::Uniform => (
|
||||
wgt::BufferUsage::UNIFORM,
|
||||
resource::BufferUse::UNIFORM,
|
||||
self.limits.max_uniform_buffer_binding_size,
|
||||
),
|
||||
wgt::BufferBindingType::Storage { read_only } => (
|
||||
wgt::BufferUsage::STORAGE,
|
||||
if read_only {
|
||||
@ -1323,6 +1330,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
} else {
|
||||
resource::BufferUse::STORAGE_STORE
|
||||
},
|
||||
self.limits.max_storage_buffer_binding_size,
|
||||
),
|
||||
};
|
||||
|
||||
@ -1355,10 +1363,12 @@ impl<B: GfxBackend> Device<B> {
|
||||
None => (buffer.size - bb.offset, buffer.size),
|
||||
};
|
||||
|
||||
if binding_ty == wgt::BufferBindingType::Uniform
|
||||
&& (self.limits.max_uniform_buffer_binding_size as u64) < bind_size
|
||||
{
|
||||
return Err(Error::UniformBufferRangeTooLarge);
|
||||
if bind_size > range_limit as u64 {
|
||||
return Err(Error::BufferRangeTooLarge {
|
||||
binding,
|
||||
given: bind_size as u32,
|
||||
limit: range_limit,
|
||||
});
|
||||
}
|
||||
|
||||
// Record binding info for validating dynamic offsets
|
||||
@ -2029,6 +2039,13 @@ impl<B: GfxBackend> Device<B> {
|
||||
if vb_state.attributes.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if vb_state.array_stride > self.limits.max_vertex_buffer_array_stride as u64 {
|
||||
return Err(pipeline::CreateRenderPipelineError::VertexStrideTooLarge {
|
||||
index: i as u32,
|
||||
given: vb_state.array_stride as u32,
|
||||
limit: self.limits.max_vertex_buffer_array_stride,
|
||||
});
|
||||
}
|
||||
if vb_state.array_stride % wgt::VERTEX_STRIDE_ALIGNMENT != 0 {
|
||||
return Err(pipeline::CreateRenderPipelineError::UnalignedVertexStride {
|
||||
index: i as u32,
|
||||
@ -2084,6 +2101,21 @@ impl<B: GfxBackend> Device<B> {
|
||||
}
|
||||
}
|
||||
|
||||
if vertex_buffers.len() > self.limits.max_vertex_buffers as usize {
|
||||
return Err(pipeline::CreateRenderPipelineError::TooManyVertexBuffers {
|
||||
given: vertex_buffers.len() as u32,
|
||||
limit: self.limits.max_vertex_buffers,
|
||||
});
|
||||
}
|
||||
if attributes.len() > self.limits.max_vertex_attributes as usize {
|
||||
return Err(
|
||||
pipeline::CreateRenderPipelineError::TooManyVertexAttributes {
|
||||
given: attributes.len() as u32,
|
||||
limit: self.limits.max_vertex_attributes,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if desc.primitive.strip_index_format.is_some()
|
||||
&& desc.primitive.topology != wgt::PrimitiveTopology::LineStrip
|
||||
&& desc.primitive.topology != wgt::PrimitiveTopology::TriangleStrip
|
||||
|
||||
@ -217,6 +217,20 @@ impl<B: GfxBackend> Adapter<B> {
|
||||
// TODO: fix all gfx-hal backends to produce limits we care about, and remove .max
|
||||
let desc_limits = &properties.limits.descriptor_limits;
|
||||
let limits = wgt::Limits {
|
||||
max_texture_dimension_1d: properties
|
||||
.limits
|
||||
.max_image_1d_size
|
||||
.max(default_limits.max_texture_dimension_1d),
|
||||
max_texture_dimension_2d: properties
|
||||
.limits
|
||||
.max_image_2d_size
|
||||
.max(default_limits.max_texture_dimension_1d),
|
||||
max_texture_dimension_3d: properties
|
||||
.limits
|
||||
.max_image_3d_size
|
||||
.max(default_limits.max_texture_dimension_1d),
|
||||
max_texture_array_layers: (properties.limits.max_image_array_layers as u32)
|
||||
.max(default_limits.max_texture_array_layers),
|
||||
max_bind_groups: (properties.limits.max_bound_descriptor_sets as u32)
|
||||
.min(MAX_BIND_GROUPS as u32)
|
||||
.max(default_limits.max_bind_groups),
|
||||
@ -243,6 +257,15 @@ impl<B: GfxBackend> Adapter<B> {
|
||||
.max(default_limits.max_uniform_buffers_per_shader_stage),
|
||||
max_uniform_buffer_binding_size: (properties.limits.max_uniform_buffer_range as u32)
|
||||
.max(default_limits.max_uniform_buffer_binding_size),
|
||||
max_storage_buffer_binding_size: (properties.limits.max_storage_buffer_range as u32)
|
||||
.max(default_limits.max_storage_buffer_binding_size),
|
||||
max_vertex_buffers: (properties.limits.max_vertex_input_bindings as u32)
|
||||
.max(default_limits.max_vertex_buffers),
|
||||
max_vertex_attributes: (properties.limits.max_vertex_input_attributes as u32)
|
||||
.max(default_limits.max_vertex_attributes),
|
||||
max_vertex_buffer_array_stride: (properties.limits.max_vertex_input_binding_stride
|
||||
as u32)
|
||||
.max(default_limits.max_vertex_buffer_array_stride),
|
||||
max_push_constant_size: (properties.limits.max_push_constants_size as u32)
|
||||
.max(MIN_PUSH_CONSTANT_SIZE), // As an extension, the default is always 0, so define a separate minimum.
|
||||
};
|
||||
|
||||
@ -203,6 +203,12 @@ pub enum CreateRenderPipelineError {
|
||||
IncompatibleOutputFormat { index: u8 },
|
||||
#[error("invalid sample count {0}")]
|
||||
InvalidSampleCount(u32),
|
||||
#[error("the number of vertex buffers {given} exceeds the limit {limit}")]
|
||||
TooManyVertexBuffers { given: u32, limit: u32 },
|
||||
#[error("the total number of vertex attributes {given} exceeds the limit {limit}")]
|
||||
TooManyVertexAttributes { given: u32, limit: u32 },
|
||||
#[error("vertex buffer {index} stride {given} exceeds the limit {limit}")]
|
||||
VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
|
||||
#[error("vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
|
||||
UnalignedVertexStride {
|
||||
index: u32,
|
||||
|
||||
@ -213,7 +213,7 @@ pub struct Texture<B: hal::Backend> {
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TextureErrorDimension {
|
||||
X,
|
||||
Y,
|
||||
@ -224,8 +224,12 @@ pub enum TextureErrorDimension {
|
||||
pub enum TextureDimensionError {
|
||||
#[error("Dimension {0:?} is zero")]
|
||||
Zero(TextureErrorDimension),
|
||||
#[error("1D textures must have height set to 1")]
|
||||
InvalidHeight,
|
||||
#[error("Dimension {0:?} value {given} exceeds the limit of {limit}")]
|
||||
LimitExceeded {
|
||||
dim: TextureErrorDimension,
|
||||
given: u32,
|
||||
limit: u32,
|
||||
},
|
||||
#[error("sample count {0} is invalid")]
|
||||
InvalidSampleCount(u32),
|
||||
}
|
||||
|
||||
@ -442,6 +442,20 @@ bitflags::bitflags! {
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct Limits {
|
||||
/// Maximum allowed value for the `size.width` of a texture created with `TextureDimension::D1`.
|
||||
/// Defaults to 8192. Higher is "better".
|
||||
pub max_texture_dimension_1d: u32,
|
||||
/// Maximum allowed value for the `size.width` and `size.height` of a texture created with `TextureDimension::D2`.
|
||||
/// Defaults to 8192. Higher is "better".
|
||||
pub max_texture_dimension_2d: u32,
|
||||
/// Maximum allowed value for the `size.width`, `size.height`, and `size.depth_or_array_layers`
|
||||
/// of a texture created with `TextureDimension::D3`.
|
||||
/// Defaults to 2048. Higher is "better".
|
||||
pub max_texture_dimension_3d: u32,
|
||||
/// Maximum allowed value for the `size.depth_or_array_layers` of a texture created with
|
||||
/// `TextureDimension::D1` or `TextureDimension::D2`.
|
||||
/// Defaults to 2048. Higher is "better".
|
||||
pub max_texture_array_layers: u32,
|
||||
/// Amount of bind groups that can be attached to a pipeline at the same time. Defaults to 4. Higher is "better".
|
||||
pub max_bind_groups: u32,
|
||||
/// Amount of uniform buffer bindings that can be dynamic in a single pipeline. Defaults to 8. Higher is "better".
|
||||
@ -460,6 +474,18 @@ pub struct Limits {
|
||||
pub max_uniform_buffers_per_shader_stage: u32,
|
||||
/// Maximum size in bytes of a binding to a uniform buffer. Defaults to 16384. Higher is "better".
|
||||
pub max_uniform_buffer_binding_size: u32,
|
||||
/// Maximum size in bytes of a binding to a storage buffer. Defaults to 128 MB. Higher is "better".
|
||||
pub max_storage_buffer_binding_size: u32,
|
||||
/// Maximum length of `VertexState::buffers` when creating a `RenderPipeline`.
|
||||
/// Defaults to 8. Higher is "better".
|
||||
pub max_vertex_buffers: u32,
|
||||
/// Maximum length of `VertexBufferLayout::attributes`, summed over all `VertexState::buffers`,
|
||||
/// when creating a `RenderPipeline`.
|
||||
/// Defaults to 16. Higher is "better".
|
||||
pub max_vertex_attributes: u32,
|
||||
/// Maximum value for `VertexBufferLayout::array_stride` when creating a `RenderPipeline`.
|
||||
/// Defaults to 2048. Higher is "better".
|
||||
pub max_vertex_buffer_array_stride: u32,
|
||||
/// Amount of storage available for push constants in bytes. Defaults to 0. Higher is "better".
|
||||
/// Requesting more than 0 during device creation requires [`Features::PUSH_CONSTANTS`] to be enabled.
|
||||
///
|
||||
@ -475,6 +501,10 @@ pub struct Limits {
|
||||
impl Default for Limits {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_texture_dimension_1d: 8192,
|
||||
max_texture_dimension_2d: 8192,
|
||||
max_texture_dimension_3d: 2048,
|
||||
max_texture_array_layers: 2048,
|
||||
max_bind_groups: 4,
|
||||
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: 4,
|
||||
@ -484,6 +514,10 @@ impl Default for Limits {
|
||||
max_storage_textures_per_shader_stage: 4,
|
||||
max_uniform_buffers_per_shader_stage: 12,
|
||||
max_uniform_buffer_binding_size: 16384,
|
||||
max_storage_buffer_binding_size: 128 << 20,
|
||||
max_vertex_buffers: 8,
|
||||
max_vertex_attributes: 16,
|
||||
max_vertex_buffer_array_stride: 2048,
|
||||
max_push_constant_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user