mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #1241
1241: Update Extent3d::depth and Limits to latest upstream r=grovesNL a=kvark **Connections** - https://github.com/gpuweb/gpuweb/pull/1390 - https://github.com/gpuweb/gpuweb/pull/1328 - https://github.com/gpuweb/gpuweb/pull/1163 - https://github.com/gpuweb/gpuweb/pull/1274 **Description** Just an API update up to spec. **Testing** Tested on wgpu-rs examples Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
size: (
|
||||
width: 64,
|
||||
height: 64,
|
||||
depth: 1,
|
||||
depth_or_array_layers: 1,
|
||||
),
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
@@ -127,7 +127,7 @@
|
||||
size: (
|
||||
width: 64,
|
||||
height: 64,
|
||||
depth: 1,
|
||||
depth_or_array_layers: 1,
|
||||
),
|
||||
),
|
||||
]),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -122,7 +122,7 @@ pub(crate) fn texture_copy_view_to_hal<B: hal::Backend>(
|
||||
let (layer, layer_count, z) = match texture.dimension {
|
||||
wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => (
|
||||
view.origin.z as hal::image::Layer,
|
||||
size.depth as hal::image::Layer,
|
||||
size.depth_or_array_layers as hal::image::Layer,
|
||||
0,
|
||||
),
|
||||
wgt::TextureDimension::D3 => (0, 1, view.origin.z as i32),
|
||||
@@ -162,7 +162,7 @@ pub(crate) fn validate_linear_texture_data(
|
||||
// Convert all inputs to BufferAddress (u64) to prevent overflow issues
|
||||
let copy_width = copy_size.width as BufferAddress;
|
||||
let copy_height = copy_size.height as BufferAddress;
|
||||
let copy_depth = copy_size.depth as BufferAddress;
|
||||
let copy_depth = copy_size.depth_or_array_layers as BufferAddress;
|
||||
|
||||
let offset = layout.offset;
|
||||
let rows_per_image = layout.rows_per_image as BufferAddress;
|
||||
@@ -244,7 +244,7 @@ pub(crate) fn validate_texture_copy_range(
|
||||
|
||||
match texture_dimension {
|
||||
hal::image::Kind::D1(..) => {
|
||||
if (copy_size.height, copy_size.depth) != (1, 1) {
|
||||
if (copy_size.height, copy_size.depth_or_array_layers) != (1, 1) {
|
||||
return Err(TransferError::InvalidCopySize);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ pub(crate) fn validate_texture_copy_range(
|
||||
side: texture_side,
|
||||
});
|
||||
}
|
||||
let z_copy_max = texture_copy_view.origin.z + copy_size.depth;
|
||||
let z_copy_max = texture_copy_view.origin.z + copy_size.depth_or_array_layers;
|
||||
if z_copy_max > extent.depth {
|
||||
return Err(TransferError::TextureOverrun {
|
||||
start_offset: texture_copy_view.origin.z,
|
||||
@@ -469,7 +469,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
});
|
||||
}
|
||||
|
||||
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth == 0 {
|
||||
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
|
||||
tracing::trace!("Ignoring copy_buffer_to_texture of size 0");
|
||||
return Ok(());
|
||||
}
|
||||
@@ -564,7 +564,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let image_extent = Extent3d {
|
||||
width: copy_size.width.min(max_image_extent.width),
|
||||
height: copy_size.height.min(max_image_extent.height),
|
||||
depth: copy_size.depth,
|
||||
depth_or_array_layers: copy_size.depth_or_array_layers,
|
||||
};
|
||||
|
||||
let buffer_width = (source.layout.bytes_per_row / bytes_per_block) * block_width as u32;
|
||||
@@ -620,7 +620,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
});
|
||||
}
|
||||
|
||||
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth == 0 {
|
||||
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
|
||||
tracing::trace!("Ignoring copy_texture_to_buffer of size 0");
|
||||
return Ok(());
|
||||
}
|
||||
@@ -718,7 +718,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let image_extent = Extent3d {
|
||||
width: copy_size.width.min(max_image_extent.width),
|
||||
height: copy_size.height.min(max_image_extent.height),
|
||||
depth: copy_size.depth,
|
||||
depth_or_array_layers: copy_size.depth_or_array_layers,
|
||||
};
|
||||
|
||||
let buffer_width =
|
||||
@@ -781,7 +781,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
});
|
||||
}
|
||||
|
||||
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth == 0 {
|
||||
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
|
||||
tracing::trace!("Ignoring copy_texture_to_texture of size 0");
|
||||
return Ok(());
|
||||
}
|
||||
@@ -859,7 +859,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
height: copy_size
|
||||
.height
|
||||
.min(max_src_image_extent.height.min(max_dst_image_extent.height)),
|
||||
depth: copy_size.depth,
|
||||
depth_or_array_layers: copy_size.depth_or_array_layers,
|
||||
};
|
||||
|
||||
let region = hal::command::ImageCopy {
|
||||
|
||||
@@ -160,7 +160,7 @@ pub fn map_extent(extent: &wgt::Extent3d, dim: wgt::TextureDimension) -> hal::im
|
||||
height: extent.height,
|
||||
depth: match dim {
|
||||
wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => 1,
|
||||
wgt::TextureDimension::D3 => extent.depth,
|
||||
wgt::TextureDimension::D3 => extent.depth_or_array_layers,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -518,52 +518,63 @@ pub fn map_texture_dimension_size(
|
||||
wgt::Extent3d {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
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 == 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.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.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)
|
||||
}
|
||||
})
|
||||
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);
|
||||
@@ -660,7 +665,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
let mut view_caps = hal::image::ViewCapabilities::empty();
|
||||
// 2D textures with array layer counts that are multiples of 6 could be cubemaps
|
||||
// Following gpuweb/gpuweb#68 always add the hint in that case
|
||||
if desc.dimension == TextureDimension::D2 && desc.size.depth % 6 == 0 {
|
||||
if desc.dimension == TextureDimension::D2 && desc.size.depth_or_array_layers % 6 == 0 {
|
||||
view_caps |= hal::image::ViewCapabilities::KIND_CUBE;
|
||||
};
|
||||
|
||||
@@ -874,7 +879,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
extent: wgt::Extent3d {
|
||||
width: hal_extent.width,
|
||||
height: hal_extent.height,
|
||||
depth: view_layer_count,
|
||||
depth_or_array_layers: view_layer_count,
|
||||
},
|
||||
samples: texture.kind.num_samples(),
|
||||
framebuffer_attachment: texture.framebuffer_attachment.clone(),
|
||||
@@ -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
|
||||
|
||||
@@ -321,7 +321,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
});
|
||||
}
|
||||
|
||||
if size.width == 0 || size.height == 0 || size.depth == 0 {
|
||||
if size.width == 0 || size.height == 0 || size.depth_or_array_layers == 0 {
|
||||
tracing::trace!("Ignoring write_texture of size 0");
|
||||
return Ok(());
|
||||
}
|
||||
@@ -359,7 +359,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
);
|
||||
let stage_bytes_per_row = align_to(bytes_per_block * width_blocks, bytes_per_row_alignment);
|
||||
|
||||
let block_rows_in_copy = (size.depth - 1) * block_rows_per_image + height_blocks;
|
||||
let block_rows_in_copy =
|
||||
(size.depth_or_array_layers - 1) * block_rows_per_image + height_blocks;
|
||||
let stage_size = stage_bytes_per_row as u64 * block_rows_in_copy as u64;
|
||||
let mut stage = device.prepare_stage(stage_size)?;
|
||||
|
||||
@@ -403,7 +404,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
// Copy row by row into the optimal alignment.
|
||||
let copy_bytes_per_row =
|
||||
stage_bytes_per_row.min(data_layout.bytes_per_row) as usize;
|
||||
for layer in 0..size.depth {
|
||||
for layer in 0..size.depth_or_array_layers {
|
||||
let rows_offset = layer * block_rows_per_image;
|
||||
for row in 0..height_blocks {
|
||||
ptr::copy_nonoverlapping(
|
||||
@@ -432,7 +433,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let image_extent = wgt::Extent3d {
|
||||
width: size.width.min(max_image_extent.width),
|
||||
height: size.height.min(max_image_extent.height),
|
||||
depth: size.depth,
|
||||
depth_or_array_layers: size.depth_or_array_layers,
|
||||
};
|
||||
|
||||
let region = hal::command::BufferImageCopy {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
extent: wgt::Extent3d {
|
||||
width: sc.desc.width,
|
||||
height: sc.desc.height,
|
||||
depth: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
samples: 1,
|
||||
framebuffer_attachment: sc.framebuffer_attachment.clone(),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -2164,7 +2198,7 @@ pub struct Extent3d {
|
||||
///
|
||||
pub height: u32,
|
||||
///
|
||||
pub depth: u32,
|
||||
pub depth_or_array_layers: u32,
|
||||
}
|
||||
|
||||
impl Default for Extent3d {
|
||||
@@ -2172,7 +2206,7 @@ impl Default for Extent3d {
|
||||
Self {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth: 1,
|
||||
depth_or_array_layers: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2187,18 +2221,18 @@ impl Extent3d {
|
||||
/// # use wgpu_types as wgpu;
|
||||
/// let format = wgpu::TextureFormat::Bc1RgbaUnormSrgb; // 4x4 blocks
|
||||
/// assert_eq!(
|
||||
/// wgpu::Extent3d { width: 7, height: 7, depth: 1 }.physical_size(format),
|
||||
/// wgpu::Extent3d { width: 8, height: 8, depth: 1 }
|
||||
/// wgpu::Extent3d { width: 7, height: 7, depth_or_array_layers: 1 }.physical_size(format),
|
||||
/// wgpu::Extent3d { width: 8, height: 8, depth_or_array_layers: 1 }
|
||||
/// );
|
||||
/// // Doesn't change, already aligned
|
||||
/// assert_eq!(
|
||||
/// wgpu::Extent3d { width: 8, height: 8, depth: 1 }.physical_size(format),
|
||||
/// wgpu::Extent3d { width: 8, height: 8, depth: 1 }
|
||||
/// wgpu::Extent3d { width: 8, height: 8, depth_or_array_layers: 1 }.physical_size(format),
|
||||
/// wgpu::Extent3d { width: 8, height: 8, depth_or_array_layers: 1 }
|
||||
/// );
|
||||
/// let format = wgpu::TextureFormat::Astc8x5RgbaUnorm; // 8x5 blocks
|
||||
/// assert_eq!(
|
||||
/// wgpu::Extent3d { width: 7, height: 7, depth: 1 }.physical_size(format),
|
||||
/// wgpu::Extent3d { width: 8, height: 10, depth: 1 }
|
||||
/// wgpu::Extent3d { width: 7, height: 7, depth_or_array_layers: 1 }.physical_size(format),
|
||||
/// wgpu::Extent3d { width: 8, height: 10, depth_or_array_layers: 1 }
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
@@ -2214,7 +2248,7 @@ impl Extent3d {
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
depth: self.depth,
|
||||
depth_or_array_layers: self.depth_or_array_layers,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2225,12 +2259,12 @@ impl Extent3d {
|
||||
///
|
||||
/// ```rust
|
||||
/// # use wgpu_types as wgpu;
|
||||
/// assert_eq!(wgpu::Extent3d { width: 1, height: 1, depth: 1 }.max_mips(), 1);
|
||||
/// assert_eq!(wgpu::Extent3d { width: 60, height: 60, depth: 1 }.max_mips(), 6);
|
||||
/// assert_eq!(wgpu::Extent3d { width: 240, height: 1, depth: 1 }.max_mips(), 8);
|
||||
/// assert_eq!(wgpu::Extent3d { width: 1, height: 1, depth_or_array_layers: 1 }.max_mips(), 1);
|
||||
/// assert_eq!(wgpu::Extent3d { width: 60, height: 60, depth_or_array_layers: 1 }.max_mips(), 6);
|
||||
/// assert_eq!(wgpu::Extent3d { width: 240, height: 1, depth_or_array_layers: 1 }.max_mips(), 8);
|
||||
/// ```
|
||||
pub fn max_mips(&self) -> u8 {
|
||||
let max_dim = self.width.max(self.height.max(self.depth));
|
||||
let max_dim = self.width.max(self.height.max(self.depth_or_array_layers));
|
||||
let max_levels = 32 - max_dim.leading_zeros();
|
||||
|
||||
max_levels as u8
|
||||
@@ -2245,15 +2279,15 @@ impl Extent3d {
|
||||
///
|
||||
/// ```rust
|
||||
/// # use wgpu_types as wgpu;
|
||||
/// let extent = wgpu::Extent3d { width: 100, height: 60, depth: 1 };
|
||||
/// let extent = wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 };
|
||||
///
|
||||
/// assert_eq!(extent.at_mip_level(0), Some(wgpu::Extent3d { width: 100, height: 60, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(1), Some(wgpu::Extent3d { width: 50, height: 30, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(2), Some(wgpu::Extent3d { width: 25, height: 15, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(3), Some(wgpu::Extent3d { width: 12, height: 7, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(4), Some(wgpu::Extent3d { width: 6, height: 3, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(5), Some(wgpu::Extent3d { width: 3, height: 1, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(6), Some(wgpu::Extent3d { width: 1, height: 1, depth: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(0), Some(wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(1), Some(wgpu::Extent3d { width: 50, height: 30, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(2), Some(wgpu::Extent3d { width: 25, height: 15, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(3), Some(wgpu::Extent3d { width: 12, height: 7, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(4), Some(wgpu::Extent3d { width: 6, height: 3, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(5), Some(wgpu::Extent3d { width: 3, height: 1, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(6), Some(wgpu::Extent3d { width: 1, height: 1, depth_or_array_layers: 1 }));
|
||||
/// assert_eq!(extent.at_mip_level(7), None);
|
||||
/// ```
|
||||
pub fn at_mip_level(&self, level: u8) -> Option<Self> {
|
||||
@@ -2263,10 +2297,10 @@ impl Extent3d {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Extent3d {
|
||||
Some(Self {
|
||||
width: u32::max(1, self.width >> level as u32),
|
||||
height: u32::max(1, self.height >> level as u32),
|
||||
depth: u32::max(1, self.depth >> level as u32),
|
||||
depth_or_array_layers: u32::max(1, self.depth_or_array_layers >> level as u32),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user