mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-02-19 18:33:30 +00:00
Native Extension: Expose fill buffer & clear image (#1335)
* Add command buffer fill buffer method * Added test for buffer fill * Added image clear + test * image/buffer clear methods are now pure clear to zero * fix cargo clippy & int type issues * clear buffer alignment is now given by COPY_BUFFER_ALIGNMENT * joined buffer/image clear player tests * ImageSubresourceRange is now used in TextureViewDescriptor
This commit is contained in:
parent
7ce535cc97
commit
f62d0d5edc
@ -81,6 +81,15 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
trace::Command::CopyTextureToTexture { src, dst, size } => self
|
||||
.command_encoder_copy_texture_to_texture::<B>(encoder, &src, &dst, &size)
|
||||
.unwrap(),
|
||||
trace::Command::ClearBuffer { dst, offset, size } => self
|
||||
.command_encoder_clear_buffer::<B>(encoder, dst, offset, size)
|
||||
.unwrap(),
|
||||
trace::Command::ClearImage {
|
||||
dst,
|
||||
subresource_range,
|
||||
} => self
|
||||
.command_encoder_clear_image::<B>(encoder, dst, subresource_range)
|
||||
.unwrap(),
|
||||
trace::Command::WriteTimestamp {
|
||||
query_set_id,
|
||||
query_index,
|
||||
|
@ -1,9 +1,10 @@
|
||||
(
|
||||
backends: (bits: 0xF),
|
||||
tests: [
|
||||
"buffer-copy.ron",
|
||||
"buffer-zero-init.ron",
|
||||
"bind-group.ron",
|
||||
"buffer-copy.ron",
|
||||
"clear-buffer-image.ron",
|
||||
"buffer-zero-init.ron",
|
||||
"quad.ron",
|
||||
],
|
||||
)
|
36
player/tests/data/buffer-clear.ron
Normal file
36
player/tests/data/buffer-clear.ron
Normal file
@ -0,0 +1,36 @@
|
||||
(
|
||||
features: (bits: 0x0000_0001_0000_0000),
|
||||
expectations: [
|
||||
(
|
||||
name: "basic",
|
||||
buffer: (index: 0, epoch: 1),
|
||||
offset: 0,
|
||||
data: Raw([
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
]),
|
||||
)
|
||||
],
|
||||
actions: [
|
||||
CreateBuffer(
|
||||
Id(0, 1, Empty),
|
||||
(
|
||||
label: None,
|
||||
size: 16,
|
||||
usage: (
|
||||
bits: 41,
|
||||
),
|
||||
mapped_at_creation: false,
|
||||
),
|
||||
),
|
||||
Submit(1, [
|
||||
ClearBuffer(
|
||||
dst: Id(0, 1, Empty),
|
||||
offset: 4,
|
||||
size: Some(8),
|
||||
)
|
||||
]),
|
||||
],
|
||||
)
|
98
player/tests/data/clear-buffer-image.ron
Normal file
98
player/tests/data/clear-buffer-image.ron
Normal file
@ -0,0 +1,98 @@
|
||||
(
|
||||
features: (bits: 0x0000_0001_0000_0000),
|
||||
expectations: [
|
||||
(
|
||||
name: "Quad",
|
||||
buffer: (index: 0, epoch: 1),
|
||||
offset: 0,
|
||||
data: File("clear-image.bin", 16384),
|
||||
),
|
||||
(
|
||||
name: "buffer clear",
|
||||
buffer: (index: 1, epoch: 1),
|
||||
offset: 0,
|
||||
data: Raw([
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
]),
|
||||
)
|
||||
],
|
||||
actions: [
|
||||
CreateTexture(Id(0, 1, Empty), (
|
||||
label: Some("Output Texture"),
|
||||
size: (
|
||||
width: 64,
|
||||
height: 64,
|
||||
depth_or_array_layers: 1,
|
||||
),
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: D2,
|
||||
format: Rgba8Unorm,
|
||||
usage: (
|
||||
bits: 27,
|
||||
),
|
||||
)),
|
||||
CreateBuffer(
|
||||
Id(0, 1, Empty),
|
||||
(
|
||||
label: Some("Output Buffer"),
|
||||
size: 16384,
|
||||
usage: (
|
||||
bits: 9,
|
||||
),
|
||||
mapped_at_creation: false,
|
||||
),
|
||||
),
|
||||
CreateBuffer(
|
||||
Id(1, 1, Empty),
|
||||
(
|
||||
label: Some("Buffer to be cleared"),
|
||||
size: 16,
|
||||
usage: (
|
||||
bits: 41,
|
||||
),
|
||||
mapped_at_creation: false,
|
||||
),
|
||||
),
|
||||
Submit(1, [
|
||||
ClearImage(
|
||||
dst: Id(0, 1, Empty),
|
||||
subresource_range: ImageSubresourceRange(
|
||||
aspect: All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: None,
|
||||
),
|
||||
),
|
||||
CopyTextureToBuffer(
|
||||
src: (
|
||||
texture: Id(0, 1, Empty),
|
||||
mip_level: 0,
|
||||
array_layer: 0,
|
||||
),
|
||||
dst: (
|
||||
buffer: Id(0, 1, Empty),
|
||||
layout: (
|
||||
offset: 0,
|
||||
bytes_per_row: Some(256),
|
||||
rows_per_image: None,
|
||||
),
|
||||
),
|
||||
size: (
|
||||
width: 64,
|
||||
height: 64,
|
||||
depth_or_array_layers: 1,
|
||||
),
|
||||
),
|
||||
ClearBuffer(
|
||||
dst: Id(1, 1, Empty),
|
||||
offset: 4,
|
||||
size: Some(8),
|
||||
)
|
||||
]),
|
||||
],
|
||||
)
|
BIN
player/tests/data/clear-image.bin
Normal file
BIN
player/tests/data/clear-image.bin
Normal file
Binary file not shown.
@ -91,6 +91,7 @@ impl<B: GfxBackend> CommandAllocator<B> {
|
||||
device: &B::Device,
|
||||
limits: wgt::Limits,
|
||||
downlevel: wgt::DownlevelProperties,
|
||||
features: wgt::Features,
|
||||
private_features: PrivateFeatures,
|
||||
label: &crate::Label,
|
||||
#[cfg(feature = "trace")] enable_tracing: bool,
|
||||
@ -135,6 +136,7 @@ impl<B: GfxBackend> CommandAllocator<B> {
|
||||
limits,
|
||||
downlevel,
|
||||
private_features,
|
||||
support_fill_buffer_texture: features.contains(wgt::Features::CLEAR_COMMANDS),
|
||||
has_labels: label.is_some(),
|
||||
#[cfg(feature = "trace")]
|
||||
commands: if enable_tracing {
|
||||
|
295
wgpu-core/src/command/clear.rs
Normal file
295
wgpu-core/src/command/clear.rs
Normal file
@ -0,0 +1,295 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::{num::NonZeroU32, ops::Range};
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
use crate::device::trace::Command as TraceCommand;
|
||||
use crate::{
|
||||
command::CommandBuffer,
|
||||
conv,
|
||||
device::all_buffer_stages,
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Token},
|
||||
id::{BufferId, CommandEncoderId, TextureId},
|
||||
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
|
||||
resource::{BufferUse, TextureUse},
|
||||
track::TextureSelector,
|
||||
};
|
||||
|
||||
use hal::command::CommandBuffer as _;
|
||||
use thiserror::Error;
|
||||
use wgt::{
|
||||
BufferAddress, BufferSize, BufferUsage, ImageSubresourceRange, TextureAspect, TextureUsage,
|
||||
};
|
||||
|
||||
/// Error encountered while attempting a clear.
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum ClearError {
|
||||
#[error("to use clear_buffer/texture the CLEAR_COMMANDS feature needs to be enabled")]
|
||||
MissingClearCommandsFeature,
|
||||
#[error("command encoder {0:?} is invalid")]
|
||||
InvalidCommandEncoder(CommandEncoderId),
|
||||
#[error("buffer {0:?} is invalid or destroyed")]
|
||||
InvalidBuffer(BufferId),
|
||||
#[error("texture {0:?} is invalid or destroyed")]
|
||||
InvalidTexture(TextureId),
|
||||
#[error("buffer clear size {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")]
|
||||
UnalignedFillSize(BufferSize),
|
||||
#[error("buffer offset {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")]
|
||||
UnalignedBufferOffset(BufferAddress),
|
||||
#[error("clear of {start_offset}..{end_offset} would end up overrunning the bounds of the buffer of size {buffer_size}")]
|
||||
BufferOverrun {
|
||||
start_offset: BufferAddress,
|
||||
end_offset: BufferAddress,
|
||||
buffer_size: BufferAddress,
|
||||
},
|
||||
#[error("destination buffer/texture is missing the `COPY_DST` usage flag")]
|
||||
MissingCopyDstUsageFlag(Option<BufferId>, Option<TextureId>),
|
||||
#[error("texture lacks the aspects that were specified in the image subresource range. Texture has {texture_aspects:?}, specified was {subresource_range_aspects:?}")]
|
||||
MissingTextureAspect {
|
||||
texture_aspects: hal::format::Aspects,
|
||||
subresource_range_aspects: TextureAspect,
|
||||
},
|
||||
#[error("image subresource level range is outside of the texture's level range. texture range is {texture_level_range:?}, \
|
||||
whereas subesource range specified start {subresource_base_mip_level} and count {subresource_mip_level_count:?}")]
|
||||
InvalidTextureLevelRange {
|
||||
texture_level_range: Range<hal::image::Level>,
|
||||
subresource_base_mip_level: u32,
|
||||
subresource_mip_level_count: Option<NonZeroU32>,
|
||||
},
|
||||
#[error("image subresource layer range is outside of the texture's layer range. texture range is {texture_layer_range:?}, \
|
||||
whereas subesource range specified start {subresource_base_array_layer} and count {subresource_array_layer_count:?}")]
|
||||
InvalidTextureLayerRange {
|
||||
texture_layer_range: Range<hal::image::Layer>,
|
||||
subresource_base_array_layer: u32,
|
||||
subresource_array_layer_count: Option<NonZeroU32>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
pub fn command_encoder_clear_buffer<B: GfxBackend>(
|
||||
&self,
|
||||
command_encoder_id: CommandEncoderId,
|
||||
dst: BufferId,
|
||||
offset: BufferAddress,
|
||||
size: Option<BufferSize>,
|
||||
) -> Result<(), ClearError> {
|
||||
profiling::scope!("CommandEncoder::fill_buffer");
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (mut cmd_buf_guard, mut token) = hub.command_buffers.write(&mut token);
|
||||
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, command_encoder_id)
|
||||
.map_err(|_| ClearError::InvalidCommandEncoder(command_encoder_id))?;
|
||||
let (buffer_guard, _) = hub.buffers.read(&mut token);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf.commands {
|
||||
list.push(TraceCommand::ClearBuffer { dst, offset, size });
|
||||
}
|
||||
|
||||
if !cmd_buf.support_fill_buffer_texture {
|
||||
return Err(ClearError::MissingClearCommandsFeature);
|
||||
}
|
||||
|
||||
let (dst_buffer, dst_pending) = cmd_buf
|
||||
.trackers
|
||||
.buffers
|
||||
.use_replace(&*buffer_guard, dst, (), BufferUse::COPY_DST)
|
||||
.map_err(ClearError::InvalidBuffer)?;
|
||||
let &(ref dst_raw, _) = dst_buffer
|
||||
.raw
|
||||
.as_ref()
|
||||
.ok_or(ClearError::InvalidBuffer(dst))?;
|
||||
if !dst_buffer.usage.contains(BufferUsage::COPY_DST) {
|
||||
return Err(ClearError::MissingCopyDstUsageFlag(Some(dst), None));
|
||||
}
|
||||
|
||||
// Check if offset & size are valid.
|
||||
if offset % wgt::COPY_BUFFER_ALIGNMENT != 0 {
|
||||
return Err(ClearError::UnalignedBufferOffset(offset));
|
||||
}
|
||||
if let Some(size) = size {
|
||||
if size.get() % wgt::COPY_BUFFER_ALIGNMENT != 0 {
|
||||
return Err(ClearError::UnalignedFillSize(size));
|
||||
}
|
||||
let destination_end_offset = offset + size.get();
|
||||
if destination_end_offset > dst_buffer.size {
|
||||
return Err(ClearError::BufferOverrun {
|
||||
start_offset: offset,
|
||||
end_offset: destination_end_offset,
|
||||
buffer_size: dst_buffer.size,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let num_bytes_filled = size.map_or(dst_buffer.size - offset, |s| s.get());
|
||||
if num_bytes_filled == 0 {
|
||||
log::trace!("Ignoring fill_buffer of size 0");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Mark dest as initialized.
|
||||
cmd_buf.buffer_memory_init_actions.extend(
|
||||
dst_buffer
|
||||
.initialization_status
|
||||
.check(offset..(offset + num_bytes_filled))
|
||||
.map(|range| MemoryInitTrackerAction {
|
||||
id: dst,
|
||||
range,
|
||||
kind: MemoryInitKind::ImplicitlyInitialized,
|
||||
}),
|
||||
);
|
||||
|
||||
// actual hal barrier & operation
|
||||
let dst_barrier = dst_pending
|
||||
.map(|pending| pending.into_hal(dst_buffer))
|
||||
.next();
|
||||
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
|
||||
unsafe {
|
||||
cmd_buf_raw.pipeline_barrier(
|
||||
all_buffer_stages()..hal::pso::PipelineStage::TRANSFER,
|
||||
hal::memory::Dependencies::empty(),
|
||||
dst_barrier.into_iter(),
|
||||
);
|
||||
cmd_buf_raw.fill_buffer(
|
||||
dst_raw,
|
||||
hal::buffer::SubRange {
|
||||
offset,
|
||||
size: size.map(|s| s.get()),
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn command_encoder_clear_image<B: GfxBackend>(
|
||||
&self,
|
||||
command_encoder_id: CommandEncoderId,
|
||||
dst: TextureId,
|
||||
subresource_range: ImageSubresourceRange,
|
||||
) -> Result<(), ClearError> {
|
||||
profiling::scope!("CommandEncoder::clear_image");
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (mut cmd_buf_guard, mut token) = hub.command_buffers.write(&mut token);
|
||||
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, command_encoder_id)
|
||||
.map_err(|_| ClearError::InvalidCommandEncoder(command_encoder_id))?;
|
||||
let (_, mut token) = hub.buffers.read(&mut token); // skip token
|
||||
let (texture_guard, _) = hub.textures.read(&mut token);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf.commands {
|
||||
list.push(TraceCommand::ClearImage {
|
||||
dst,
|
||||
subresource_range: subresource_range.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
if !cmd_buf.support_fill_buffer_texture {
|
||||
return Err(ClearError::MissingClearCommandsFeature);
|
||||
}
|
||||
|
||||
let dst_texture = texture_guard
|
||||
.get(dst)
|
||||
.map_err(|_| ClearError::InvalidTexture(dst))?;
|
||||
|
||||
// Check if subresource aspects are valid.
|
||||
let aspects = match subresource_range.aspect {
|
||||
wgt::TextureAspect::All => dst_texture.aspects,
|
||||
wgt::TextureAspect::DepthOnly => hal::format::Aspects::DEPTH,
|
||||
wgt::TextureAspect::StencilOnly => hal::format::Aspects::STENCIL,
|
||||
};
|
||||
if !dst_texture.aspects.contains(aspects) {
|
||||
return Err(ClearError::MissingTextureAspect {
|
||||
texture_aspects: dst_texture.aspects,
|
||||
subresource_range_aspects: subresource_range.aspect,
|
||||
});
|
||||
};
|
||||
// Check if subresource level range is valid
|
||||
let subresource_level_end = if let Some(count) = subresource_range.mip_level_count {
|
||||
(subresource_range.base_mip_level + count.get()) as u8
|
||||
} else {
|
||||
dst_texture.full_range.levels.end
|
||||
};
|
||||
if dst_texture.full_range.levels.start > subresource_range.base_mip_level as u8
|
||||
|| dst_texture.full_range.levels.end < subresource_level_end
|
||||
{
|
||||
return Err(ClearError::InvalidTextureLevelRange {
|
||||
texture_level_range: dst_texture.full_range.levels.clone(),
|
||||
subresource_base_mip_level: subresource_range.base_mip_level,
|
||||
subresource_mip_level_count: subresource_range.mip_level_count,
|
||||
});
|
||||
}
|
||||
// Check if subresource layer range is valid
|
||||
let subresource_layer_end = if let Some(count) = subresource_range.array_layer_count {
|
||||
(subresource_range.base_array_layer + count.get()) as u16
|
||||
} else {
|
||||
dst_texture.full_range.layers.end
|
||||
};
|
||||
if dst_texture.full_range.layers.start > subresource_range.base_array_layer as u16
|
||||
|| dst_texture.full_range.layers.end < subresource_layer_end
|
||||
{
|
||||
return Err(ClearError::InvalidTextureLayerRange {
|
||||
texture_layer_range: dst_texture.full_range.layers.clone(),
|
||||
subresource_base_array_layer: subresource_range.base_array_layer,
|
||||
subresource_array_layer_count: subresource_range.array_layer_count,
|
||||
});
|
||||
}
|
||||
|
||||
// query from tracker with usage (and check usage)
|
||||
let (dst_texture, dst_pending) = cmd_buf
|
||||
.trackers
|
||||
.textures
|
||||
.use_replace(
|
||||
&*texture_guard,
|
||||
dst,
|
||||
TextureSelector {
|
||||
levels: subresource_range.base_mip_level as u8..subresource_level_end,
|
||||
layers: subresource_range.base_array_layer as u16..subresource_layer_end,
|
||||
},
|
||||
TextureUse::COPY_DST,
|
||||
)
|
||||
.map_err(ClearError::InvalidTexture)?;
|
||||
let &(ref dst_raw, _) = dst_texture
|
||||
.raw
|
||||
.as_ref()
|
||||
.ok_or(ClearError::InvalidTexture(dst))?;
|
||||
if !dst_texture.usage.contains(TextureUsage::COPY_DST) {
|
||||
return Err(ClearError::MissingCopyDstUsageFlag(None, Some(dst)));
|
||||
}
|
||||
|
||||
// actual hal barrier & operation
|
||||
let dst_barrier = dst_pending
|
||||
.map(|pending| pending.into_hal(dst_texture))
|
||||
.next();
|
||||
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
|
||||
unsafe {
|
||||
cmd_buf_raw.pipeline_barrier(
|
||||
all_buffer_stages()..hal::pso::PipelineStage::TRANSFER,
|
||||
hal::memory::Dependencies::empty(),
|
||||
dst_barrier.into_iter(),
|
||||
);
|
||||
cmd_buf_raw.clear_image(
|
||||
dst_raw,
|
||||
hal::image::Layout::TransferDstOptimal,
|
||||
hal::command::ClearValue {
|
||||
color: hal::command::ClearColor {
|
||||
float32: conv::map_color_f32(&wgt::Color::TRANSPARENT),
|
||||
},
|
||||
},
|
||||
std::iter::once(hal::image::SubresourceRange {
|
||||
aspects,
|
||||
level_start: subresource_range.base_mip_level as u8,
|
||||
level_count: subresource_range.mip_level_count.map(|c| c.get() as u8),
|
||||
layer_start: subresource_range.base_array_layer as u16,
|
||||
layer_count: subresource_range.array_layer_count.map(|c| c.get() as u16),
|
||||
}),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
mod allocator;
|
||||
mod bind;
|
||||
mod bundle;
|
||||
mod clear;
|
||||
mod compute;
|
||||
mod draw;
|
||||
mod query;
|
||||
@ -50,6 +51,7 @@ pub struct CommandBuffer<B: hal::Backend> {
|
||||
limits: wgt::Limits,
|
||||
downlevel: wgt::DownlevelProperties,
|
||||
private_features: PrivateFeatures,
|
||||
support_fill_buffer_texture: bool,
|
||||
has_labels: bool,
|
||||
#[cfg(feature = "trace")]
|
||||
pub(crate) commands: Option<Vec<crate::device::trace::Command>>,
|
||||
|
@ -318,9 +318,8 @@ impl<B: GfxBackend> Device<B> {
|
||||
let mem_allocator = alloc::MemoryAllocator::new(mem_props, hal_limits);
|
||||
let descriptors = descriptor::DescriptorAllocator::new();
|
||||
#[cfg(not(feature = "trace"))]
|
||||
match trace_path {
|
||||
Some(_) => log::error!("Feature 'trace' is not enabled"),
|
||||
None => (),
|
||||
if let Some(_) = trace_path {
|
||||
log::error!("Feature 'trace' is not enabled");
|
||||
}
|
||||
|
||||
let spv_options = {
|
||||
@ -793,7 +792,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
None => match texture.kind {
|
||||
hal::image::Kind::D1(..) => wgt::TextureViewDimension::D1,
|
||||
hal::image::Kind::D2(_, _, depth, _)
|
||||
if depth > 1 && desc.array_layer_count.is_none() =>
|
||||
if depth > 1 && desc.range.array_layer_count.is_none() =>
|
||||
{
|
||||
wgt::TextureViewDimension::D2Array
|
||||
}
|
||||
@ -803,9 +802,9 @@ impl<B: GfxBackend> Device<B> {
|
||||
};
|
||||
|
||||
let required_level_count =
|
||||
desc.base_mip_level + desc.mip_level_count.map_or(1, |count| count.get());
|
||||
let required_layer_count =
|
||||
desc.base_array_layer + desc.array_layer_count.map_or(1, |count| count.get());
|
||||
desc.range.base_mip_level + desc.range.mip_level_count.map_or(1, |count| count.get());
|
||||
let required_layer_count = desc.range.base_array_layer
|
||||
+ desc.range.array_layer_count.map_or(1, |count| count.get());
|
||||
let level_end = texture.full_range.levels.end;
|
||||
let layer_end = texture.full_range.layers.end;
|
||||
if required_level_count > level_end as u32 {
|
||||
@ -821,7 +820,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
});
|
||||
};
|
||||
|
||||
let aspects = match desc.aspect {
|
||||
let aspects = match desc.range.aspect {
|
||||
wgt::TextureAspect::All => texture.aspects,
|
||||
wgt::TextureAspect::DepthOnly => hal::format::Aspects::DEPTH,
|
||||
wgt::TextureAspect::StencilOnly => hal::format::Aspects::STENCIL,
|
||||
@ -834,14 +833,16 @@ impl<B: GfxBackend> Device<B> {
|
||||
}
|
||||
|
||||
let end_level = desc
|
||||
.range
|
||||
.mip_level_count
|
||||
.map_or(level_end, |_| required_level_count as u8);
|
||||
let end_layer = desc
|
||||
.range
|
||||
.array_layer_count
|
||||
.map_or(layer_end, |_| required_layer_count as u16);
|
||||
let selector = TextureSelector {
|
||||
levels: desc.base_mip_level as u8..end_level,
|
||||
layers: desc.base_array_layer as u16..end_layer,
|
||||
levels: desc.range.base_mip_level as u8..end_level,
|
||||
layers: desc.range.base_array_layer as u16..end_layer,
|
||||
};
|
||||
|
||||
let view_layer_count = (selector.layers.end - selector.layers.start) as u32;
|
||||
@ -863,12 +864,15 @@ impl<B: GfxBackend> Device<B> {
|
||||
let format = desc.format.unwrap_or(texture.format);
|
||||
let range = hal::image::SubresourceRange {
|
||||
aspects,
|
||||
level_start: desc.base_mip_level as _,
|
||||
level_count: desc.mip_level_count.map(|v| v.get() as _),
|
||||
layer_start: desc.base_array_layer as _,
|
||||
layer_count: desc.array_layer_count.map(|v| v.get() as _),
|
||||
level_start: desc.range.base_mip_level as _,
|
||||
level_count: desc.range.mip_level_count.map(|v| v.get() as _),
|
||||
layer_start: desc.range.base_array_layer as _,
|
||||
layer_count: desc.range.array_layer_count.map(|v| v.get() as _),
|
||||
};
|
||||
let hal_extent = texture.kind.extent().at_level(desc.base_mip_level as _);
|
||||
let hal_extent = texture
|
||||
.kind
|
||||
.extent()
|
||||
.at_level(desc.range.base_mip_level as _);
|
||||
|
||||
let raw = unsafe {
|
||||
self.raw
|
||||
@ -3872,6 +3876,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
&device.raw,
|
||||
device.limits.clone(),
|
||||
device.downlevel,
|
||||
device.features,
|
||||
device.private_features,
|
||||
&desc.label,
|
||||
#[cfg(feature = "trace")]
|
||||
|
@ -142,6 +142,15 @@ pub enum Command {
|
||||
dst: crate::command::ImageCopyTexture,
|
||||
size: wgt::Extent3d,
|
||||
},
|
||||
ClearBuffer {
|
||||
dst: id::BufferId,
|
||||
offset: wgt::BufferAddress,
|
||||
size: Option<wgt::BufferSize>,
|
||||
},
|
||||
ClearImage {
|
||||
dst: id::TextureId,
|
||||
subresource_range: wgt::ImageSubresourceRange,
|
||||
},
|
||||
WriteTimestamp {
|
||||
query_set_id: id::QuerySetId,
|
||||
query_index: u32,
|
||||
|
@ -217,7 +217,8 @@ impl<B: GfxBackend> Adapter<B> {
|
||||
let mut features = wgt::Features::default()
|
||||
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS
|
||||
| wgt::Features::PUSH_CONSTANTS
|
||||
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
|
||||
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
|
||||
| wgt::Features::CLEAR_COMMANDS;
|
||||
for &(hi, lo) in FEATURE_MAP.iter() {
|
||||
features.set(hi, adapter_features.contains(lo));
|
||||
}
|
||||
|
@ -14,12 +14,7 @@ use crate::{
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
num::{NonZeroU32, NonZeroU8},
|
||||
ops::Range,
|
||||
ptr::NonNull,
|
||||
};
|
||||
use std::{borrow::Borrow, num::NonZeroU8, ops::Range, ptr::NonNull};
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// The internal enum mirrored from `BufferUsage`. The values don't have to match!
|
||||
@ -297,20 +292,8 @@ pub struct TextureViewDescriptor<'a> {
|
||||
/// The dimension of the texture view. For 1D textures, this must be `1D`. For 2D textures it must be one of
|
||||
/// `D2`, `D2Array`, `Cube`, and `CubeArray`. For 3D textures it must be `3D`
|
||||
pub dimension: Option<wgt::TextureViewDimension>,
|
||||
/// Aspect of the texture. Color textures must be [`TextureAspect::All`](wgt::TextureAspect::All).
|
||||
pub aspect: wgt::TextureAspect,
|
||||
/// Base mip level.
|
||||
pub base_mip_level: u32,
|
||||
/// Mip level count.
|
||||
/// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
|
||||
/// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
|
||||
pub mip_level_count: Option<NonZeroU32>,
|
||||
/// Base array layer.
|
||||
pub base_array_layer: u32,
|
||||
/// Layer count.
|
||||
/// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
|
||||
/// If `None`, considered to include the rest of the array layers, but at least 1 in total.
|
||||
pub array_layer_count: Option<NonZeroU32>,
|
||||
/// Range within the texture that is accessible via this view.
|
||||
pub range: wgt::ImageSubresourceRange,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -38,7 +38,7 @@ pub type DynamicOffset = u32;
|
||||
pub const COPY_BYTES_PER_ROW_ALIGNMENT: u32 = 256;
|
||||
/// Bound uniform/storage buffer offsets must be aligned to this number.
|
||||
pub const BIND_BUFFER_ALIGNMENT: BufferAddress = 256;
|
||||
/// Buffer to buffer copy offsets and sizes must be aligned to this number.
|
||||
/// Buffer to buffer copy as well as buffer clear offsets and sizes must be aligned to this number.
|
||||
pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4;
|
||||
/// Size to align mappings.
|
||||
pub const MAP_ALIGNMENT: BufferAddress = 8;
|
||||
@ -535,6 +535,14 @@ bitflags::bitflags! {
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const VERTEX_WRITABLE_STORAGE = 0x0000_0020_0000_0000;
|
||||
/// Enables clear to zero for buffers & images.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - All
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const CLEAR_COMMANDS = 0x0000_0001_0000_0000;
|
||||
|
||||
/// Features which are part of the upstream WebGPU standard.
|
||||
const ALL_WEBGPU = 0x0000_0000_0000_FFFF;
|
||||
/// Features that are only available when targeting native (not web).
|
||||
@ -2163,7 +2171,7 @@ bitflags::bitflags! {
|
||||
/// operation.
|
||||
const COPY_SRC = 4;
|
||||
/// Allow a buffer to be the destination buffer for a [`CommandEncoder::copy_buffer_to_buffer`], [`CommandEncoder::copy_texture_to_buffer`],
|
||||
/// or [`Queue::write_buffer`] operation.
|
||||
/// [`CommandEncoder::fill_buffer`] or [`Queue::write_buffer`] operation.
|
||||
const COPY_DST = 8;
|
||||
/// Allow a buffer to be the index buffer in a draw operation.
|
||||
const INDEX = 16;
|
||||
@ -2992,6 +3000,28 @@ pub struct ImageCopyTexture<T> {
|
||||
pub origin: Origin3d,
|
||||
}
|
||||
|
||||
/// Subresource range within an image
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub struct ImageSubresourceRange {
|
||||
/// Aspect of the texture. Color textures must be [`TextureAspect::All`](wgt::TextureAspect::All).
|
||||
pub aspect: TextureAspect,
|
||||
/// Base mip level.
|
||||
pub base_mip_level: u32,
|
||||
/// Mip level count.
|
||||
/// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
|
||||
/// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
|
||||
pub mip_level_count: Option<NonZeroU32>,
|
||||
/// Base array layer.
|
||||
pub base_array_layer: u32,
|
||||
/// Layer count.
|
||||
/// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
|
||||
/// If `None`, considered to include the rest of the array layers, but at least 1 in total.
|
||||
pub array_layer_count: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
/// Color variation to use when sampler addressing mode is [`AddressMode::ClampToBorder`]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
|
Loading…
Reference in New Issue
Block a user