Store pointers instead of IDs when tracing (1/2)

This updates pass operations.

The trace player is temporarily broken.
This commit is contained in:
Andy Leiserson 2025-09-25 16:28:35 -07:00 committed by Teodor Tanasoaia
parent a502e73c1d
commit e584f382e0
26 changed files with 956 additions and 1289 deletions

3
Cargo.lock generated
View File

@ -3792,6 +3792,9 @@ name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
dependencies = [
"serde",
]
[[package]]
name = "smithay-client-toolkit"

View File

@ -3,6 +3,7 @@ resolver = "2"
members = [
"cts_runner",
"deno_webgpu",
"player",
# default members
"benches",
@ -15,7 +16,6 @@ members = [
"naga/fuzz",
"naga/hlsl-snapshots",
"naga/xtask",
"player",
"tests",
"wgpu-core",
"wgpu-core/platform-deps/*",
@ -38,7 +38,6 @@ default-members = [
"naga/fuzz",
"naga/hlsl-snapshots",
"naga/xtask",
"player",
"tests",
"wgpu-core",
"wgpu-core/platform-deps/*",

View File

@ -18,7 +18,7 @@ pub trait GlobalPlay {
fn encode_commands(
&self,
encoder: wgc::id::CommandEncoderId,
commands: Vec<Command>,
commands: Vec<Command<IdReferences>>,
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
) -> wgc::id::CommandBufferId;
fn process(
@ -36,7 +36,7 @@ impl GlobalPlay for wgc::global::Global {
fn encode_commands(
&self,
encoder: wgc::id::CommandEncoderId,
commands: Vec<Command>,
commands: Vec<Command<IdReferences>>,
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
) -> wgc::id::CommandBufferId {
for command in commands {
@ -71,13 +71,13 @@ impl GlobalPlay for wgc::global::Global {
.command_encoder_clear_texture(encoder, dst, &subresource_range)
.unwrap(),
Command::WriteTimestamp {
query_set_id,
query_set,
query_index,
} => self
.command_encoder_write_timestamp(encoder, query_set_id, query_index)
.command_encoder_write_timestamp(encoder, query_set, query_index)
.unwrap(),
Command::ResolveQuerySet {
query_set_id,
query_set,
start_query,
query_count,
destination,
@ -85,7 +85,7 @@ impl GlobalPlay for wgc::global::Global {
} => self
.command_encoder_resolve_query_set(
encoder,
query_set_id,
query_set,
start_query,
query_count,
destination,
@ -100,29 +100,29 @@ impl GlobalPlay for wgc::global::Global {
.command_encoder_insert_debug_marker(encoder, &marker)
.unwrap(),
Command::RunComputePass {
base,
pass,
timestamp_writes,
} => {
self.compute_pass_end_with_unresolved_commands(
encoder,
base,
pass,
timestamp_writes.as_ref(),
);
}
Command::RunRenderPass {
base,
target_colors,
target_depth_stencil,
pass,
color_attachments,
depth_stencil_attachment,
timestamp_writes,
occlusion_query_set_id,
occlusion_query_set,
} => {
self.render_pass_end_with_unresolved_commands(
encoder,
base,
&target_colors,
target_depth_stencil.as_ref(),
pass,
&color_attachments,
depth_stencil_attachment.as_ref(),
timestamp_writes.as_ref(),
occlusion_query_set_id,
occlusion_query_set,
);
}
Command::BuildAccelerationStructures { blas, tlas } => {
@ -175,6 +175,7 @@ impl GlobalPlay for wgc::global::Global {
)
.unwrap();
}
Command::TransitionResources { .. } => unimplemented!("not supported in a trace"),
}
}
let (cmd_buf, error) = self.command_encoder_finish(
@ -233,12 +234,8 @@ impl GlobalPlay for wgc::global::Global {
Action::DestroyTexture(id) => {
self.texture_drop(id);
}
Action::CreateTextureView {
id,
parent_id,
desc,
} => {
let (_, error) = self.texture_create_view(parent_id, &desc, Some(id));
Action::CreateTextureView { id, parent, desc } => {
let (_, error) = self.texture_create_view(parent, &desc, Some(id));
if let Some(e) = error {
panic!("{e}");
}
@ -268,8 +265,8 @@ impl GlobalPlay for wgc::global::Global {
Action::DestroySampler(id) => {
self.sampler_drop(id);
}
Action::GetSurfaceTexture { id, parent_id } => {
self.surface_get_current_texture(parent_id, Some(id))
Action::GetSurfaceTexture { id, parent } => {
self.surface_get_current_texture(parent, Some(id))
.unwrap()
.texture
.unwrap();

View File

@ -69,7 +69,7 @@ observe_locks = ["std", "dep:ron", "serde/serde_derive"]
# --------------------------------------------------------------------
## Enables serialization via `serde` on common wgpu types.
serde = ["dep:serde", "wgpu-types/serde", "arrayvec/serde", "hashbrown/serde"]
serde = ["dep:serde", "wgpu-types/serde", "arrayvec/serde", "hashbrown/serde", "smallvec/serde"]
## Enable API tracing.
trace = ["serde", "std", "dep:ron", "naga/serialize", "wgpu-types/trace"]

View File

@ -96,11 +96,13 @@ use thiserror::Error;
use wgpu_hal::ShouldBeNonZeroExt;
use wgt::error::{ErrorType, WebGpuError};
#[cfg(feature = "trace")]
use crate::command::ArcReferences;
use crate::{
binding_model::{BindError, BindGroup, PipelineLayout},
command::{
BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, MapPassErr,
PassErrorScope, RenderCommandError, StateChange,
BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, IdReferences, MapPassErr,
PassErrorScope, RenderCommand, RenderCommandError, StateChange,
},
device::{
AttachmentData, Device, DeviceError, MissingDownlevelFlags, RenderPassContext,
@ -120,11 +122,7 @@ use crate::{
Label, LabelHelpers,
};
use super::{
pass,
render_command::{ArcRenderCommand, RenderCommand},
DrawCommandFamily, DrawKind,
};
use super::{pass, render_command::ArcRenderCommand, DrawCommandFamily, DrawKind};
/// Describes a [`RenderBundleEncoder`].
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
@ -158,7 +156,7 @@ pub struct RenderBundleEncoderDescriptor<'a> {
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct RenderBundleEncoder {
base: BasePass<RenderCommand, Infallible>,
base: BasePass<RenderCommand<IdReferences>, Infallible>,
parent_id: id::DeviceId,
pub(crate) context: RenderPassContext,
pub(crate) is_depth_read_only: bool,
@ -175,7 +173,7 @@ impl RenderBundleEncoder {
pub fn new(
desc: &RenderBundleEncoderDescriptor,
parent_id: id::DeviceId,
base: Option<BasePass<RenderCommand, Infallible>>,
base: Option<BasePass<RenderCommand<IdReferences>, Infallible>>,
) -> Result<Self, CreateRenderBundleError> {
let (is_depth_read_only, is_stencil_read_only) = match desc.depth_stencil {
Some(ds) => {
@ -252,11 +250,6 @@ impl RenderBundleEncoder {
}
}
#[cfg(feature = "trace")]
pub(crate) fn to_base_pass(&self) -> BasePass<RenderCommand, Infallible> {
self.base.clone()
}
pub fn parent(&self) -> id::DeviceId {
self.parent_id
}
@ -305,12 +298,12 @@ impl RenderBundleEncoder {
let base = &self.base;
for &command in &base.commands {
for command in &base.commands {
match command {
RenderCommand::SetBindGroup {
&RenderCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group_id,
bind_group,
} => {
let scope = PassErrorScope::SetBindGroup;
set_bind_group(
@ -319,11 +312,11 @@ impl RenderBundleEncoder {
&base.dynamic_offsets,
index,
num_dynamic_offsets,
bind_group_id,
bind_group,
)
.map_pass_err(scope)?;
}
RenderCommand::SetPipeline(pipeline_id) => {
&RenderCommand::SetPipeline(pipeline) => {
let scope = PassErrorScope::SetPipelineRender;
set_pipeline(
&mut state,
@ -331,12 +324,12 @@ impl RenderBundleEncoder {
&self.context,
self.is_depth_read_only,
self.is_stencil_read_only,
pipeline_id,
pipeline,
)
.map_pass_err(scope)?;
}
RenderCommand::SetIndexBuffer {
buffer_id,
&RenderCommand::SetIndexBuffer {
buffer,
index_format,
offset,
size,
@ -345,24 +338,24 @@ impl RenderBundleEncoder {
set_index_buffer(
&mut state,
&buffer_guard,
buffer_id,
buffer,
index_format,
offset,
size,
)
.map_pass_err(scope)?;
}
RenderCommand::SetVertexBuffer {
&RenderCommand::SetVertexBuffer {
slot,
buffer_id,
buffer,
offset,
size,
} => {
let scope = PassErrorScope::SetVertexBuffer;
set_vertex_buffer(&mut state, &buffer_guard, slot, buffer_id, offset, size)
set_vertex_buffer(&mut state, &buffer_guard, slot, buffer, offset, size)
.map_pass_err(scope)?;
}
RenderCommand::SetPushConstant {
&RenderCommand::SetPushConstant {
stages,
offset,
size_bytes,
@ -372,7 +365,7 @@ impl RenderBundleEncoder {
set_push_constant(&mut state, stages, offset, size_bytes, values_offset)
.map_pass_err(scope)?;
}
RenderCommand::Draw {
&RenderCommand::Draw {
vertex_count,
instance_count,
first_vertex,
@ -392,7 +385,7 @@ impl RenderBundleEncoder {
)
.map_pass_err(scope)?;
}
RenderCommand::DrawIndexed {
&RenderCommand::DrawIndexed {
index_count,
instance_count,
first_index,
@ -414,7 +407,7 @@ impl RenderBundleEncoder {
)
.map_pass_err(scope)?;
}
RenderCommand::DrawMeshTasks {
&RenderCommand::DrawMeshTasks {
group_count_x,
group_count_y,
group_count_z,
@ -432,11 +425,13 @@ impl RenderBundleEncoder {
)
.map_pass_err(scope)?;
}
RenderCommand::DrawIndirect {
buffer_id,
&RenderCommand::DrawIndirect {
buffer,
offset,
count: 1,
family,
vertex_or_index_limit: None,
instance_limit: None,
} => {
let scope = PassErrorScope::Draw {
kind: DrawKind::DrawIndirect,
@ -446,32 +441,39 @@ impl RenderBundleEncoder {
&mut state,
&base.dynamic_offsets,
&buffer_guard,
buffer_id,
buffer,
offset,
family,
)
.map_pass_err(scope)?;
}
RenderCommand::DrawIndirect { .. }
| RenderCommand::MultiDrawIndirectCount { .. }
| RenderCommand::PushDebugGroup { color: _, len: _ }
| RenderCommand::InsertDebugMarker { color: _, len: _ }
| RenderCommand::PopDebugGroup => {
&RenderCommand::DrawIndirect {
count,
vertex_or_index_limit,
instance_limit,
..
} => {
unreachable!("unexpected (multi-)draw indirect with count {count}, vertex_or_index_limits {vertex_or_index_limit:?}, instance_limit {instance_limit:?} found in a render bundle");
}
&RenderCommand::MultiDrawIndirectCount { .. }
| &RenderCommand::PushDebugGroup { color: _, len: _ }
| &RenderCommand::InsertDebugMarker { color: _, len: _ }
| &RenderCommand::PopDebugGroup => {
unimplemented!("not supported by a render bundle")
}
// Must check the TIMESTAMP_QUERY_INSIDE_PASSES feature
RenderCommand::WriteTimestamp { .. }
| RenderCommand::BeginOcclusionQuery { .. }
| RenderCommand::EndOcclusionQuery
| RenderCommand::BeginPipelineStatisticsQuery { .. }
| RenderCommand::EndPipelineStatisticsQuery => {
&RenderCommand::WriteTimestamp { .. }
| &RenderCommand::BeginOcclusionQuery { .. }
| &RenderCommand::EndOcclusionQuery
| &RenderCommand::BeginPipelineStatisticsQuery { .. }
| &RenderCommand::EndPipelineStatisticsQuery => {
unimplemented!("not supported by a render bundle")
}
RenderCommand::ExecuteBundle(_)
| RenderCommand::SetBlendConstant(_)
| RenderCommand::SetStencilReference(_)
| RenderCommand::SetViewport { .. }
| RenderCommand::SetScissor(_) => unreachable!("not supported by a render bundle"),
&RenderCommand::ExecuteBundle(_)
| &RenderCommand::SetBlendConstant(_)
| &RenderCommand::SetStencilReference(_)
| &RenderCommand::SetViewport { .. }
| &RenderCommand::SetScissor(_) => unreachable!("not supported by a render bundle"),
}
}
@ -518,13 +520,13 @@ impl RenderBundleEncoder {
pub fn set_index_buffer(
&mut self,
buffer_id: id::BufferId,
buffer: id::BufferId,
index_format: wgt::IndexFormat,
offset: wgt::BufferAddress,
size: Option<wgt::BufferSize>,
) {
self.base.commands.push(RenderCommand::SetIndexBuffer {
buffer_id,
buffer,
index_format,
offset,
size,
@ -899,8 +901,8 @@ fn multi_draw_indirect(
count: 1,
family,
vertex_or_index_limit,
instance_limit,
vertex_or_index_limit: Some(vertex_or_index_limit),
instance_limit: Some(instance_limit),
});
Ok(())
}
@ -941,6 +943,7 @@ pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor<Label<'a>>;
//Note: here, `RenderBundle` is just wrapping a raw stream of render commands.
// The plan is to back it by an actual Vulkan secondary buffer, D3D12 Bundle,
// or Metal indirect command buffer.
/// cbindgen:ignore
#[derive(Debug)]
pub struct RenderBundle {
// Normalized command stream. It can be executed verbatim,
@ -971,6 +974,11 @@ unsafe impl Send for RenderBundle {}
unsafe impl Sync for RenderBundle {}
impl RenderBundle {
#[cfg(feature = "trace")]
pub(crate) fn to_base_pass(&self) -> BasePass<RenderCommand<ArcReferences>, Infallible> {
self.base.clone()
}
/// Actually encode the contents into a native command buffer.
///
/// This is partially duplicating the logic of `render_pass_end`.
@ -1142,8 +1150,9 @@ impl RenderBundle {
buffer,
*offset,
*family,
*vertex_or_index_limit,
*instance_limit,
vertex_or_index_limit
.expect("finalized render bundle missing vertex_or_index_limit"),
instance_limit.expect("finalized render bundle missing instance_limit"),
)?;
let dst_buffer =
@ -1590,7 +1599,7 @@ impl State {
/// Error encountered when finishing recording a render bundle.
#[derive(Clone, Debug, Error)]
pub(super) enum RenderBundleErrorInner {
pub enum RenderBundleErrorInner {
#[error(transparent)]
Device(#[from] DeviceError),
#[error(transparent)]
@ -1692,7 +1701,7 @@ pub mod bundle_ffi {
bundle.base.commands.push(RenderCommand::SetBindGroup {
index,
num_dynamic_offsets: offset_length,
bind_group_id,
bind_group: bind_group_id,
});
}
@ -1719,7 +1728,7 @@ pub mod bundle_ffi {
) {
bundle.base.commands.push(RenderCommand::SetVertexBuffer {
slot,
buffer_id,
buffer: buffer_id,
offset,
size,
});
@ -1813,10 +1822,12 @@ pub mod bundle_ffi {
offset: BufferAddress,
) {
bundle.base.commands.push(RenderCommand::DrawIndirect {
buffer_id,
buffer: buffer_id,
offset,
count: 1,
family: DrawCommandFamily::Draw,
vertex_or_index_limit: None,
instance_limit: None,
});
}
@ -1826,10 +1837,12 @@ pub mod bundle_ffi {
offset: BufferAddress,
) {
bundle.base.commands.push(RenderCommand::DrawIndirect {
buffer_id,
buffer: buffer_id,
offset,
count: 1,
family: DrawCommandFamily::DrawIndexed,
vertex_or_index_limit: None,
instance_limit: None,
});
}

View File

@ -1,8 +1,6 @@
use alloc::{sync::Arc, vec::Vec};
use core::ops::Range;
#[cfg(feature = "trace")]
use crate::command::Command as TraceCommand;
use crate::{
api_log,
command::{encoder::EncodingState, ArcCommand, EncoderStateError},
@ -119,11 +117,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::ClearBuffer { dst, offset, size });
}
cmd_buf_data.push_with(|| -> Result<_, ClearError> {
Ok(ArcCommand::ClearBuffer {
dst: self.resolve_buffer_id(dst)?,
@ -147,14 +140,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::ClearTexture {
dst,
subresource_range: *subresource_range,
});
}
cmd_buf_data.push_with(|| -> Result<_, ClearError> {
Ok(ArcCommand::ClearTexture {
dst: self.resolve_texture_id(dst)?,

View File

@ -456,73 +456,6 @@ impl Global {
}
}
/// Note that this differs from [`Self::compute_pass_end`], it will
/// create a new pass, replay the commands and end the pass.
///
/// # Panics
/// On any error.
#[doc(hidden)]
#[cfg(any(feature = "serde", feature = "replay"))]
pub fn compute_pass_end_with_unresolved_commands(
&self,
encoder_id: id::CommandEncoderId,
base: BasePass<super::ComputeCommand, Infallible>,
timestamp_writes: Option<&PassTimestampWrites>,
) {
#[cfg(feature = "trace")]
{
let cmd_enc = self.hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
let cmd_buf_data = cmd_buf_data.get_inner();
if let Some(ref mut list) = cmd_buf_data.trace_commands {
list.push(crate::command::Command::RunComputePass {
base: BasePass {
label: base.label.clone(),
error: None,
commands: base.commands.clone(),
dynamic_offsets: base.dynamic_offsets.clone(),
string_data: base.string_data.clone(),
push_constant_data: base.push_constant_data.clone(),
},
timestamp_writes: timestamp_writes.cloned(),
});
}
}
let BasePass {
label,
error: _,
commands,
dynamic_offsets,
string_data,
push_constant_data,
} = base;
let (mut compute_pass, encoder_error) = self.command_encoder_begin_compute_pass(
encoder_id,
&ComputePassDescriptor {
label: label.as_deref().map(Cow::Borrowed),
timestamp_writes: timestamp_writes.cloned(),
},
);
if let Some(err) = encoder_error {
panic!("{:?}", err);
};
compute_pass.base = BasePass {
label,
error: None,
commands: super::ComputeCommand::resolve_compute_command_ids(&self.hub, &commands)
.unwrap(),
dynamic_offsets,
string_data,
push_constant_data,
};
self.compute_pass_end(&mut compute_pass).unwrap();
}
pub fn compute_pass_end(&self, pass: &mut ComputePass) -> Result<(), EncoderStateError> {
profiling::scope!(
"CommandEncoder::run_compute_pass {}",

View File

@ -1,208 +1,18 @@
use alloc::sync::Arc;
use crate::command::{serde_object_reference_struct, ArcReferences, ReferenceType};
use crate::{
binding_model::BindGroup,
id,
pipeline::ComputePipeline,
resource::{Buffer, QuerySet},
};
use macro_rules_attribute::apply;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ComputeCommand {
SetBindGroup {
index: u32,
num_dynamic_offsets: usize,
bind_group_id: Option<id::BindGroupId>,
},
SetPipeline(id::ComputePipelineId),
/// Set a range of push constants to values stored in `push_constant_data`.
SetPushConstant {
/// The byte offset within the push constant storage to write to. This
/// must be a multiple of four.
offset: u32,
/// The number of bytes to write. This must be a multiple of four.
size_bytes: u32,
/// Index in `push_constant_data` of the start of the data
/// to be written.
///
/// Note: this is not a byte offset like `offset`. Rather, it is the
/// index of the first `u32` element in `push_constant_data` to read.
values_offset: u32,
},
Dispatch([u32; 3]),
DispatchIndirect {
buffer_id: id::BufferId,
offset: wgt::BufferAddress,
},
PushDebugGroup {
color: u32,
len: usize,
},
PopDebugGroup,
InsertDebugMarker {
color: u32,
len: usize,
},
WriteTimestamp {
query_set_id: id::QuerySetId,
query_index: u32,
},
BeginPipelineStatisticsQuery {
query_set_id: id::QuerySetId,
query_index: u32,
},
EndPipelineStatisticsQuery,
}
impl ComputeCommand {
/// Resolves all ids in a list of commands into the corresponding resource Arc.
#[cfg(any(feature = "serde", feature = "replay"))]
pub fn resolve_compute_command_ids(
hub: &crate::hub::Hub,
commands: &[ComputeCommand],
) -> Result<alloc::vec::Vec<ArcComputeCommand>, super::ComputePassError> {
use super::{ComputePassError, PassErrorScope};
use alloc::vec::Vec;
let buffers_guard = hub.buffers.read();
let bind_group_guard = hub.bind_groups.read();
let query_set_guard = hub.query_sets.read();
let pipelines_guard = hub.compute_pipelines.read();
let resolved_commands: Vec<ArcComputeCommand> = commands
.iter()
.map(|c| -> Result<ArcComputeCommand, ComputePassError> {
Ok(match *c {
ComputeCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group_id,
} => {
if bind_group_id.is_none() {
return Ok(ArcComputeCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group: None,
});
}
let bind_group_id = bind_group_id.unwrap();
let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| {
ComputePassError {
scope: PassErrorScope::SetBindGroup,
inner: e.into(),
}
})?;
ArcComputeCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group: Some(bg),
}
}
ComputeCommand::SetPipeline(pipeline_id) => ArcComputeCommand::SetPipeline(
pipelines_guard
.get(pipeline_id)
.get()
.map_err(|e| ComputePassError {
scope: PassErrorScope::SetPipelineCompute,
inner: e.into(),
})?,
),
ComputeCommand::SetPushConstant {
offset,
size_bytes,
values_offset,
} => ArcComputeCommand::SetPushConstant {
offset,
size_bytes,
values_offset,
},
ComputeCommand::Dispatch(dim) => ArcComputeCommand::Dispatch(dim),
ComputeCommand::DispatchIndirect { buffer_id, offset } => {
ArcComputeCommand::DispatchIndirect {
buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
ComputePassError {
scope: PassErrorScope::Dispatch { indirect: true },
inner: e.into(),
}
})?,
offset,
}
}
ComputeCommand::PushDebugGroup { color, len } => {
ArcComputeCommand::PushDebugGroup { color, len }
}
ComputeCommand::PopDebugGroup => ArcComputeCommand::PopDebugGroup,
ComputeCommand::InsertDebugMarker { color, len } => {
ArcComputeCommand::InsertDebugMarker { color, len }
}
ComputeCommand::WriteTimestamp {
query_set_id,
query_index,
} => ArcComputeCommand::WriteTimestamp {
query_set: query_set_guard.get(query_set_id).get().map_err(|e| {
ComputePassError {
scope: PassErrorScope::WriteTimestamp,
inner: e.into(),
}
})?,
query_index,
},
ComputeCommand::BeginPipelineStatisticsQuery {
query_set_id,
query_index,
} => ArcComputeCommand::BeginPipelineStatisticsQuery {
query_set: query_set_guard.get(query_set_id).get().map_err(|e| {
ComputePassError {
scope: PassErrorScope::BeginPipelineStatisticsQuery,
inner: e.into(),
}
})?,
query_index,
},
ComputeCommand::EndPipelineStatisticsQuery => {
ArcComputeCommand::EndPipelineStatisticsQuery
}
})
})
.collect::<Result<Vec<_>, ComputePassError>>()?;
Ok(resolved_commands)
}
}
/// Equivalent to `ComputeCommand` but the Ids resolved into resource Arcs.
/// cbindgen:ignore
#[derive(Clone, Debug)]
pub enum ArcComputeCommand {
#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
pub enum ComputeCommand<R: ReferenceType> {
SetBindGroup {
index: u32,
num_dynamic_offsets: usize,
bind_group: Option<Arc<BindGroup>>,
bind_group: Option<R::BindGroup>,
},
SetPipeline(Arc<ComputePipeline>),
SetPipeline(R::ComputePipeline),
/// Set a range of push constants to values stored in `push_constant_data`.
SetPushConstant {
@ -224,12 +34,12 @@ pub enum ArcComputeCommand {
Dispatch([u32; 3]),
DispatchIndirect {
buffer: Arc<Buffer>,
buffer: R::Buffer,
offset: wgt::BufferAddress,
},
PushDebugGroup {
#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
//#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
color: u32,
len: usize,
},
@ -237,20 +47,22 @@ pub enum ArcComputeCommand {
PopDebugGroup,
InsertDebugMarker {
#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
color: u32,
len: usize,
},
WriteTimestamp {
query_set: Arc<QuerySet>,
query_set: R::QuerySet,
query_index: u32,
},
BeginPipelineStatisticsQuery {
query_set: Arc<QuerySet>,
query_set: R::QuerySet,
query_index: u32,
},
EndPipelineStatisticsQuery,
}
/// cbindgen:ignore
pub type ArcComputeCommand = ComputeCommand<ArcReferences>;

View File

@ -2,15 +2,18 @@ use core::convert::Infallible;
use alloc::{string::String, sync::Arc, vec::Vec};
#[cfg(feature = "serde")]
use macro_rules_attribute::attribute_alias;
use macro_rules_attribute::{apply, attribute_alias};
use crate::{
command::ColorAttachments,
id,
instance::Surface,
resource::{Buffer, QuerySet, Texture},
};
pub trait ReferenceType {
type Buffer: Clone + core::fmt::Debug;
type Surface: Clone; // Surface does not implement Debug, although it probably could.
type Texture: Clone + core::fmt::Debug;
type TextureView: Clone + core::fmt::Debug;
type QuerySet: Clone + core::fmt::Debug;
@ -22,14 +25,26 @@ pub trait ReferenceType {
type Tlas: Clone + core::fmt::Debug;
}
/// Reference wgpu objects via numeric IDs assigned by [`crate::identity::IdentityManager`].
#[derive(Clone, Debug)]
pub struct IdReferences;
/// Reference wgpu objects via the integer value of pointers.
///
/// This is used for trace recording and playback. Recording stores the pointer
/// value of `Arc` references in the trace. Playback uses the integer values
/// as keys to a `HashMap`.
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct PointerReferences;
/// Reference wgpu objects via `Arc`s.
#[derive(Clone, Debug)]
pub struct ArcReferences;
impl ReferenceType for IdReferences {
type Buffer = id::BufferId;
type Surface = id::SurfaceId;
type Texture = id::TextureId;
type TextureView = id::TextureViewId;
type QuerySet = id::QuerySetId;
@ -41,8 +56,23 @@ impl ReferenceType for IdReferences {
type Tlas = id::TlasId;
}
impl ReferenceType for PointerReferences {
type Buffer = id::PointerId<id::markers::Buffer>;
type Surface = id::PointerId<id::markers::Surface>;
type Texture = id::PointerId<id::markers::Texture>;
type TextureView = id::PointerId<id::markers::TextureView>;
type QuerySet = id::PointerId<id::markers::QuerySet>;
type BindGroup = id::PointerId<id::markers::BindGroup>;
type RenderPipeline = id::PointerId<id::markers::RenderPipeline>;
type RenderBundle = id::PointerId<id::markers::RenderBundle>;
type ComputePipeline = id::PointerId<id::markers::ComputePipeline>;
type Blas = id::PointerId<id::markers::Blas>;
type Tlas = id::PointerId<id::markers::Tlas>;
}
impl ReferenceType for ArcReferences {
type Buffer = Arc<Buffer>;
type Surface = Arc<Surface>;
type Texture = Arc<Texture>;
type TextureView = Arc<crate::resource::TextureView>;
type QuerySet = Arc<QuerySet>;
@ -60,6 +90,7 @@ attribute_alias! {
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound =
"R::Buffer: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::Surface: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::Texture: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::TextureView: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::QuerySet: serde::Serialize + for<'d> serde::Deserialize<'d>,\
@ -68,139 +99,80 @@ attribute_alias! {
R::RenderBundle: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::ComputePipeline: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::Blas: serde::Serialize + for<'d> serde::Deserialize<'d>,\
R::Tlas: serde::Serialize + for<'d> serde::Deserialize<'d>"
R::Tlas: serde::Serialize + for<'d> serde::Deserialize<'d>,\
wgt::BufferTransition<R::Buffer>: serde::Serialize + for<'d> serde::Deserialize<'d>,\
wgt::TextureTransition<R::Texture>: serde::Serialize + for<'d> serde::Deserialize<'d>"
)];
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Command {
#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
pub enum Command<R: ReferenceType> {
CopyBufferToBuffer {
src: id::BufferId,
src: R::Buffer,
src_offset: wgt::BufferAddress,
dst: id::BufferId,
dst: R::Buffer,
dst_offset: wgt::BufferAddress,
size: Option<wgt::BufferAddress>,
},
CopyBufferToTexture {
src: wgt::TexelCopyBufferInfo<id::BufferId>,
dst: wgt::TexelCopyTextureInfo<id::TextureId>,
src: wgt::TexelCopyBufferInfo<R::Buffer>,
dst: wgt::TexelCopyTextureInfo<R::Texture>,
size: wgt::Extent3d,
},
CopyTextureToBuffer {
src: wgt::TexelCopyTextureInfo<id::TextureId>,
dst: wgt::TexelCopyBufferInfo<id::BufferId>,
src: wgt::TexelCopyTextureInfo<R::Texture>,
dst: wgt::TexelCopyBufferInfo<R::Buffer>,
size: wgt::Extent3d,
},
CopyTextureToTexture {
src: wgt::TexelCopyTextureInfo<id::TextureId>,
dst: wgt::TexelCopyTextureInfo<id::TextureId>,
src: wgt::TexelCopyTextureInfo<R::Texture>,
dst: wgt::TexelCopyTextureInfo<R::Texture>,
size: wgt::Extent3d,
},
ClearBuffer {
dst: id::BufferId,
dst: R::Buffer,
offset: wgt::BufferAddress,
size: Option<wgt::BufferAddress>,
},
ClearTexture {
dst: id::TextureId,
dst: R::Texture,
subresource_range: wgt::ImageSubresourceRange,
},
WriteTimestamp {
query_set_id: id::QuerySetId,
query_set: R::QuerySet,
query_index: u32,
},
ResolveQuerySet {
query_set_id: id::QuerySetId,
query_set: R::QuerySet,
start_query: u32,
query_count: u32,
destination: id::BufferId,
destination: R::Buffer,
destination_offset: wgt::BufferAddress,
},
PushDebugGroup(String),
PopDebugGroup,
InsertDebugMarker(String),
RunComputePass {
base: crate::command::BasePass<crate::command::ComputeCommand, Infallible>,
timestamp_writes: Option<crate::command::PassTimestampWrites>,
pass: crate::command::BasePass<crate::command::ComputeCommand<R>, Infallible>,
timestamp_writes: Option<crate::command::PassTimestampWrites<R::QuerySet>>,
},
RunRenderPass {
base: crate::command::BasePass<crate::command::RenderCommand, Infallible>,
target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
timestamp_writes: Option<crate::command::PassTimestampWrites>,
occlusion_query_set_id: Option<id::QuerySetId>,
pass: crate::command::BasePass<crate::command::RenderCommand<R>, Infallible>,
color_attachments: ColorAttachments<R::TextureView>,
depth_stencil_attachment:
Option<crate::command::ResolvedRenderPassDepthStencilAttachment<R::TextureView>>,
timestamp_writes: Option<crate::command::PassTimestampWrites<R::QuerySet>>,
occlusion_query_set: Option<R::QuerySet>,
},
BuildAccelerationStructures {
blas: Vec<crate::ray_tracing::TraceBlasBuildEntry>,
tlas: Vec<crate::ray_tracing::TraceTlasPackage>,
blas: Vec<crate::ray_tracing::OwnedBlasBuildEntry<R>>,
tlas: Vec<crate::ray_tracing::OwnedTlasPackage<R>>,
},
TransitionResources {
buffer_transitions: Vec<wgt::BufferTransition<R::Buffer>>,
texture_transitions: Vec<wgt::TextureTransition<R::Texture>>,
},
}
#[derive(Clone, Debug)]
pub enum ArcCommand {
CopyBufferToBuffer {
src: Arc<Buffer>,
src_offset: wgt::BufferAddress,
dst: Arc<Buffer>,
dst_offset: wgt::BufferAddress,
size: Option<wgt::BufferAddress>,
},
CopyBufferToTexture {
src: wgt::TexelCopyBufferInfo<Arc<Buffer>>,
dst: wgt::TexelCopyTextureInfo<Arc<Texture>>,
size: wgt::Extent3d,
},
CopyTextureToBuffer {
src: wgt::TexelCopyTextureInfo<Arc<Texture>>,
dst: wgt::TexelCopyBufferInfo<Arc<Buffer>>,
size: wgt::Extent3d,
},
CopyTextureToTexture {
src: wgt::TexelCopyTextureInfo<Arc<Texture>>,
dst: wgt::TexelCopyTextureInfo<Arc<Texture>>,
size: wgt::Extent3d,
},
ClearBuffer {
dst: Arc<Buffer>,
offset: wgt::BufferAddress,
size: Option<wgt::BufferAddress>,
},
ClearTexture {
dst: Arc<Texture>,
subresource_range: wgt::ImageSubresourceRange,
},
WriteTimestamp {
query_set: Arc<QuerySet>,
query_index: u32,
},
ResolveQuerySet {
query_set: Arc<QuerySet>,
start_query: u32,
query_count: u32,
destination: Arc<Buffer>,
destination_offset: wgt::BufferAddress,
},
PushDebugGroup(String),
PopDebugGroup,
InsertDebugMarker(String),
RunComputePass {
pass: super::BasePass<super::ArcComputeCommand, Infallible>,
timestamp_writes: Option<super::ArcPassTimestampWrites>,
},
RunRenderPass {
pass: super::BasePass<super::ArcRenderCommand, Infallible>,
color_attachments: super::ArcRenderPassColorAttachmentArray,
depth_stencil_attachment: Option<super::ArcRenderPassDepthStencilAttachment>,
timestamp_writes: Option<super::ArcPassTimestampWrites>,
occlusion_query_set: Option<Arc<QuerySet>>,
},
BuildAccelerationStructures {
blas: Vec<crate::ray_tracing::ArcBlasBuildEntry>,
tlas: Vec<crate::ray_tracing::ArcTlasPackage>,
},
TransitionResources {
buffer_transitions: Vec<wgt::BufferTransition<Arc<Buffer>>>,
texture_transitions: Vec<wgt::TextureTransition<Arc<Texture>>>,
},
}
pub type ArcCommand = Command<ArcReferences>;

View File

@ -1,7 +1,9 @@
//! Types that are useful for FFI bindings to `wgpu`.
use crate::id;
use crate::{command::IdReferences, id};
pub type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<id::BufferId>;
pub type TexelCopyTextureInfo = wgt::TexelCopyTextureInfo<id::TextureId>;
pub type CopyExternalImageDestInfo = wgt::CopyExternalImageDestInfo<id::TextureId>;
pub type Command = super::Command<IdReferences>;

View File

@ -36,20 +36,25 @@ use core::ops;
pub(crate) use self::clear::clear_texture;
#[cfg(feature = "serde")]
pub(crate) use self::encoder_command::serde_object_reference_struct;
#[cfg(feature = "trace")]
pub(crate) use self::encoder_command::PointerReferences;
pub use self::{
bundle::*,
clear::ClearError,
compute::*,
compute_command::{ArcComputeCommand, ComputeCommand},
compute_command::ArcComputeCommand,
draw::*,
encoder_command::{ArcCommand, ArcReferences, Command, IdReferences, ReferenceType},
query::*,
render::*,
render_command::{ArcRenderCommand, RenderCommand},
render_command::ArcRenderCommand,
transfer::*,
};
pub(crate) use allocator::CommandAllocator;
/// cbindgen:ignore
pub use self::{compute_command::ComputeCommand, render_command::RenderCommand};
pub(crate) use timestamp_writes::ArcPassTimestampWrites;
pub use timestamp_writes::PassTimestampWrites;
@ -83,9 +88,6 @@ use wgt::error::{ErrorType, WebGpuError};
use thiserror::Error;
#[cfg(feature = "trace")]
type TraceCommand = Command;
/// cbindgen:ignore
pub type TexelCopyBufferInfo = ffi::TexelCopyBufferInfo;
/// cbindgen:ignore
@ -150,14 +152,6 @@ pub(crate) enum CommandEncoderStatus {
}
impl CommandEncoderStatus {
#[cfg(feature = "trace")]
fn trace(&mut self) -> Option<&mut Vec<TraceCommand>> {
match self {
Self::Recording(cmd_buf_data) => cmd_buf_data.trace_commands.as_mut(),
_ => None,
}
}
/// Push a command provided by a closure onto the encoder.
///
/// If the encoder is in the [`Self::Recording`] state, calls the closure to
@ -279,20 +273,6 @@ impl CommandEncoderStatus {
}
}
#[cfg(all(feature = "trace", any(feature = "serde", feature = "replay")))]
fn get_inner(&mut self) -> &mut CommandBufferMutable {
match self {
Self::Locked(inner) | Self::Finished(inner) | Self::Recording(inner) => inner,
// This is unreachable because this function is only used when
// playing back a recorded trace. If only to avoid having to
// implement serialization for all the error types, we don't support
// storing the errors in a trace.
Self::Consumed => unreachable!("command encoder is consumed"),
Self::Error(_) => unreachable!("passes in a trace do not store errors"),
Self::Transitioning => unreachable!(),
}
}
/// Locks the encoder by putting it in the [`Self::Locked`] state.
///
/// Render or compute passes call this on start. At the end of the pass,
@ -784,10 +764,12 @@ pub struct CommandBufferMutable {
indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
pub(crate) commands: Vec<ArcCommand>,
pub(crate) commands: Vec<Command<ArcReferences>>,
/// If tracing, `command_encoder_finish` replaces the `Arc`s in `commands`
/// with integer pointers, and moves them into `trace_commands`.
#[cfg(feature = "trace")]
pub(crate) trace_commands: Option<Vec<TraceCommand>>,
pub(crate) trace_commands: Option<Vec<Command<PointerReferences>>>,
}
impl CommandBufferMutable {
@ -974,7 +956,31 @@ impl CommandEncoder {
}
let mut commands = mem::take(&mut cmd_buf_data.commands);
for command in commands.drain(..) {
#[cfg(not(feature = "trace"))]
let command_iter = commands.drain(..);
#[cfg(feature = "trace")]
let mut trace_commands = None;
#[cfg(feature = "trace")]
let command_iter = {
if self.device.trace.lock().is_some() {
trace_commands = Some(
cmd_buf_data
.trace_commands
.insert(Vec::with_capacity(commands.len())),
);
}
commands.drain(..).inspect(|cmd| {
use crate::device::trace::IntoTrace;
if let Some(ref mut trace) = trace_commands {
trace.push(cmd.clone().to_trace());
}
})
};
for command in command_iter {
if matches!(
command,
ArcCommand::RunRenderPass { .. } | ArcCommand::RunComputePass { .. }
@ -1585,11 +1591,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::PushDebugGroup(label.to_owned()));
}
cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
Ok(ArcCommand::PushDebugGroup(label.to_owned()))
})
@ -1608,11 +1609,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::InsertDebugMarker(label.to_owned()));
}
cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
Ok(ArcCommand::InsertDebugMarker(label.to_owned()))
})
@ -1630,11 +1626,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::PopDebugGroup);
}
cmd_buf_data
.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::PopDebugGroup) })
}

View File

@ -1,8 +1,6 @@
use alloc::{sync::Arc, vec, vec::Vec};
use core::{iter, mem};
#[cfg(feature = "trace")]
use crate::command::Command as TraceCommand;
use crate::{
command::{encoder::EncodingState, ArcCommand, EncoderStateError},
device::{Device, DeviceError, MissingFeatures},
@ -366,14 +364,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::WriteTimestamp {
query_set_id,
query_index,
});
}
cmd_buf_data.push_with(|| -> Result<_, QueryError> {
Ok(ArcCommand::WriteTimestamp {
query_set: self.resolve_query_set(query_set_id)?,
@ -396,17 +386,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::ResolveQuerySet {
query_set_id,
start_query,
query_count,
destination,
destination_offset,
});
}
cmd_buf_data.push_with(|| -> Result<_, QueryError> {
Ok(ArcCommand::ResolveQuerySet {
query_set: self.resolve_query_set(query_set_id)?,

View File

@ -23,8 +23,7 @@ use crate::{
ray_tracing::{
ArcBlasBuildEntry, ArcBlasGeometries, ArcBlasTriangleGeometry, ArcTlasInstance,
ArcTlasPackage, BlasBuildEntry, BlasGeometries, BuildAccelerationStructureError,
OwnedBlasBuildEntry, OwnedTlasPackage, TlasPackage, TraceBlasBuildEntry,
TraceBlasGeometries, TraceBlasTriangleGeometry, TraceTlasInstance, TraceTlasPackage,
OwnedBlasBuildEntry, OwnedTlasPackage, TlasPackage,
},
resource::{Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas},
scratch::ScratchBuffer,
@ -122,73 +121,14 @@ impl Global {
let hub = &self.hub;
let cmd_enc = hub.command_encoders.get(command_encoder_id);
let trace_blas: Vec<TraceBlasBuildEntry> = blas_iter
.map(|blas_entry| {
let geometries = match blas_entry.geometries {
BlasGeometries::TriangleGeometries(triangle_geometries) => {
TraceBlasGeometries::TriangleGeometries(
triangle_geometries
.map(|tg| TraceBlasTriangleGeometry {
size: tg.size.clone(),
vertex_buffer: tg.vertex_buffer,
index_buffer: tg.index_buffer,
transform_buffer: tg.transform_buffer,
first_vertex: tg.first_vertex,
vertex_stride: tg.vertex_stride,
first_index: tg.first_index,
transform_buffer_offset: tg.transform_buffer_offset,
})
.collect(),
)
}
};
TraceBlasBuildEntry {
blas: blas_entry.blas_id,
geometries,
}
})
.collect();
let trace_tlas: Vec<TraceTlasPackage> = tlas_iter
.map(|package: TlasPackage| {
let instances = package
.instances
.map(|instance| {
instance.map(|instance| TraceTlasInstance {
blas: instance.blas_id,
transform: *instance.transform,
custom_data: instance.custom_data,
mask: instance.mask,
})
})
.collect();
TraceTlasPackage {
tlas: package.tlas_id,
instances,
lowest_unmodified: package.lowest_unmodified,
}
})
.collect();
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(crate::command::Command::BuildAccelerationStructures {
blas: trace_blas.clone(),
tlas: trace_tlas.clone(),
});
}
cmd_buf_data.push_with(|| -> Result<_, BuildAccelerationStructureError> {
let blas = trace_blas
.iter()
let blas = blas_iter
.map(|blas_entry| {
let geometries = match &blas_entry.geometries {
TraceBlasGeometries::TriangleGeometries(triangle_geometries) => {
let geometries = match blas_entry.geometries {
BlasGeometries::TriangleGeometries(triangle_geometries) => {
let tri_geo = triangle_geometries
.iter()
.map(|tg| {
Ok(ArcBlasTriangleGeometry {
size: tg.size.clone(),
@ -212,25 +152,23 @@ impl Global {
}
};
Ok(ArcBlasBuildEntry {
blas: self.resolve_blas_id(blas_entry.blas)?,
blas: self.resolve_blas_id(blas_entry.blas_id)?,
geometries,
})
})
.collect::<Result<_, BuildAccelerationStructureError>>()?;
let tlas = trace_tlas
.iter()
let tlas = tlas_iter
.map(|tlas_package| {
let instances = tlas_package
.instances
.iter()
.map(|instance| {
instance
.as_ref()
.map(|instance| {
Ok(ArcTlasInstance {
blas: self.resolve_blas_id(instance.blas)?,
transform: instance.transform,
blas: self.resolve_blas_id(instance.blas_id)?,
transform: *instance.transform,
custom_data: instance.custom_data,
mask: instance.mask,
})
@ -239,7 +177,7 @@ impl Global {
})
.collect::<Result<_, BuildAccelerationStructureError>>()?;
Ok(ArcTlasPackage {
tlas: self.resolve_tlas_id(tlas_package.tlas)?,
tlas: self.resolve_tlas_id(tlas_package.tlas_id)?,
instances,
lowest_unmodified: tlas_package.lowest_unmodified,
})

View File

@ -77,6 +77,9 @@ fn store_hal_ops(store: StoreOp) -> hal::AttachmentOps {
}
/// Describes an individual channel within a render pass, such as color, depth, or stencil.
///
/// A channel must either be read-only, or it must specify both load and store
/// operations. See [`ResolvedPassChannel`] for a validated version.
#[repr(C)]
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -120,7 +123,12 @@ impl<V: Copy + Default> PassChannel<Option<V>> {
}
}
/// Describes an individual channel within a render pass, such as color, depth, or stencil.
///
/// Unlike [`PassChannel`], this version uses the Rust type system to guarantee
/// a valid specification.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ResolvedPassChannel<V> {
ReadOnly,
Operational(wgt::Operations<V>),
@ -185,8 +193,8 @@ pub type ArcRenderPassColorAttachment = RenderPassColorAttachment<Arc<TextureVie
// Avoid allocation in the common case that there is only one color attachment,
// but don't bloat `ArcCommand::RunRenderPass` excessively.
pub type ArcRenderPassColorAttachmentArray =
SmallVec<[Option<RenderPassColorAttachment<Arc<TextureView>>>; 1]>;
pub type ColorAttachments<TV = Arc<TextureView>> =
SmallVec<[Option<RenderPassColorAttachment<TV>>; 1]>;
impl ArcRenderPassColorAttachment {
fn hal_ops(&self) -> hal::AttachmentOps {
@ -202,12 +210,14 @@ impl ArcRenderPassColorAttachment {
}
/// Describes a depth/stencil attachment to a render pass.
///
/// This version uses the unvalidated [`PassChannel`].
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RenderPassDepthStencilAttachment {
pub struct RenderPassDepthStencilAttachment<TV> {
/// The view to use as an attachment.
pub view: id::TextureViewId,
pub view: TV,
/// What operations will be performed on the depth part of the attachment.
pub depth: PassChannel<Option<f32>>,
/// What operations will be performed on the stencil part of the attachment.
@ -215,10 +225,13 @@ pub struct RenderPassDepthStencilAttachment {
}
/// Describes a depth/stencil attachment to a render pass.
///
/// This version uses the validated [`ResolvedPassChannel`].
#[derive(Clone, Debug)]
pub struct ArcRenderPassDepthStencilAttachment {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ResolvedRenderPassDepthStencilAttachment<TV> {
/// The view to use as an attachment.
pub view: Arc<TextureView>,
pub view: TV,
/// What operations will be performed on the depth part of the attachment.
pub depth: ResolvedPassChannel<f32>,
/// What operations will be performed on the stencil part of the attachment.
@ -232,7 +245,7 @@ pub struct RenderPassDescriptor<'a> {
/// The color attachments of the render pass.
pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>,
/// The depth and stencil attachment of the render pass, if any.
pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment>,
pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment<id::TextureViewId>>,
/// Defines where and when timestamp values will be written for this pass.
pub timestamp_writes: Option<&'a PassTimestampWrites>,
/// Defines where the occlusion query results will be stored for this pass.
@ -246,7 +259,8 @@ struct ArcRenderPassDescriptor<'a> {
pub color_attachments:
ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
/// The depth and stencil attachment of the render pass, if any.
pub depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
pub depth_stencil_attachment:
Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
/// Defines where and when timestamp values will be written for this pass.
pub timestamp_writes: Option<ArcPassTimestampWrites>,
/// Defines where the occlusion query results will be stored for this pass.
@ -275,7 +289,7 @@ pub struct RenderPass {
color_attachments:
ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
depth_stencil_attachment: Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
timestamp_writes: Option<ArcPassTimestampWrites>,
occlusion_query_set: Option<Arc<QuerySet>>,
@ -971,7 +985,9 @@ impl RenderPassInfo {
device: &Arc<Device>,
hal_label: Option<&str>,
color_attachments: &[Option<ArcRenderPassColorAttachment>],
mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
mut depth_stencil_attachment: Option<
ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
>,
mut timestamp_writes: Option<ArcPassTimestampWrites>,
mut occlusion_query_set: Option<Arc<QuerySet>>,
encoder: &mut dyn hal::DynCommandEncoder,
@ -1650,7 +1666,7 @@ impl Global {
)));
}
Some(ArcRenderPassDepthStencilAttachment {
Some(ResolvedRenderPassDepthStencilAttachment {
view,
depth: if format.has_depth_aspect() {
depth_stencil_attachment.depth.resolve(|clear| if let Some(clear) = clear {
@ -1762,79 +1778,6 @@ impl Global {
}
}
/// Note that this differs from [`Self::render_pass_end`], it will
/// create a new pass, replay the commands and end the pass.
#[doc(hidden)]
#[cfg(any(feature = "serde", feature = "replay"))]
pub fn render_pass_end_with_unresolved_commands(
&self,
encoder_id: id::CommandEncoderId,
base: BasePass<super::RenderCommand, Infallible>,
color_attachments: &[Option<RenderPassColorAttachment>],
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
timestamp_writes: Option<&PassTimestampWrites>,
occlusion_query_set: Option<id::QuerySetId>,
) {
#[cfg(feature = "trace")]
{
let cmd_enc = self.hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
let cmd_buf_data = cmd_buf_data.get_inner();
if let Some(ref mut list) = cmd_buf_data.trace_commands {
list.push(crate::command::Command::RunRenderPass {
base: BasePass {
label: base.label.clone(),
error: None,
commands: base.commands.clone(),
dynamic_offsets: base.dynamic_offsets.clone(),
string_data: base.string_data.clone(),
push_constant_data: base.push_constant_data.clone(),
},
target_colors: color_attachments.to_vec(),
target_depth_stencil: depth_stencil_attachment.cloned(),
timestamp_writes: timestamp_writes.cloned(),
occlusion_query_set_id: occlusion_query_set,
});
}
}
let BasePass {
label,
error: _,
commands,
dynamic_offsets,
string_data,
push_constant_data,
} = base;
let (mut render_pass, encoder_error) = self.command_encoder_begin_render_pass(
encoder_id,
&RenderPassDescriptor {
label: label.as_deref().map(Cow::Borrowed),
color_attachments: Cow::Borrowed(color_attachments),
depth_stencil_attachment,
timestamp_writes,
occlusion_query_set,
},
);
if let Some(err) = encoder_error {
panic!("{:?}", err);
};
render_pass.base = BasePass {
label,
error: None,
commands: super::RenderCommand::resolve_render_command_ids(&self.hub, &commands)
.unwrap(),
dynamic_offsets,
string_data,
push_constant_data,
};
self.render_pass_end(&mut render_pass).unwrap();
}
pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
profiling::scope!(
"CommandEncoder::run_render_pass {}",
@ -1881,8 +1824,10 @@ impl Global {
pub(super) fn encode_render_pass(
parent_state: &mut EncodingState<InnerCommandEncoder>,
mut base: BasePass<ArcRenderCommand, Infallible>,
color_attachments: ArcRenderPassColorAttachmentArray,
mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
color_attachments: ColorAttachments<Arc<TextureView>>,
mut depth_stencil_attachment: Option<
ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
>,
mut timestamp_writes: Option<ArcPassTimestampWrites>,
occlusion_query_set: Option<Arc<QuerySet>>,
) -> Result<(), RenderPassError> {
@ -3444,8 +3389,8 @@ impl Global {
count: 1,
family: DrawCommandFamily::Draw,
vertex_or_index_limit: 0,
instance_limit: 0,
vertex_or_index_limit: None,
instance_limit: None,
});
Ok(())
@ -3469,8 +3414,8 @@ impl Global {
count: 1,
family: DrawCommandFamily::DrawIndexed,
vertex_or_index_limit: 0,
instance_limit: 0,
vertex_or_index_limit: None,
instance_limit: None,
});
Ok(())
@ -3494,8 +3439,8 @@ impl Global {
count: 1,
family: DrawCommandFamily::DrawMeshTasks,
vertex_or_index_limit: 0,
instance_limit: 0,
vertex_or_index_limit: None,
instance_limit: None,
});
Ok(())
@ -3520,8 +3465,8 @@ impl Global {
count,
family: DrawCommandFamily::Draw,
vertex_or_index_limit: 0,
instance_limit: 0,
vertex_or_index_limit: None,
instance_limit: None,
});
Ok(())
@ -3546,8 +3491,8 @@ impl Global {
count,
family: DrawCommandFamily::DrawIndexed,
vertex_or_index_limit: 0,
instance_limit: 0,
vertex_or_index_limit: None,
instance_limit: None,
});
Ok(())
@ -3572,8 +3517,8 @@ impl Global {
count,
family: DrawCommandFamily::DrawMeshTasks,
vertex_or_index_limit: 0,
instance_limit: 0,
vertex_or_index_limit: None,
instance_limit: None,
});
Ok(())

View File

@ -1,34 +1,30 @@
use alloc::sync::Arc;
use wgt::{BufferAddress, BufferSize, Color};
use super::{DrawCommandFamily, Rect, RenderBundle};
use crate::{
binding_model::BindGroup,
id,
pipeline::RenderPipeline,
resource::{Buffer, QuerySet},
};
use super::{DrawCommandFamily, Rect};
use crate::command::{serde_object_reference_struct, ArcReferences, ReferenceType};
use macro_rules_attribute::apply;
/// cbindgen:ignore
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RenderCommand {
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
pub enum RenderCommand<R: ReferenceType> {
SetBindGroup {
index: u32,
num_dynamic_offsets: usize,
bind_group_id: Option<id::BindGroupId>,
bind_group: Option<R::BindGroup>,
},
SetPipeline(id::RenderPipelineId),
SetPipeline(R::RenderPipeline),
SetIndexBuffer {
buffer_id: id::BufferId,
buffer: R::Buffer,
index_format: wgt::IndexFormat,
offset: BufferAddress,
size: Option<BufferSize>,
},
SetVertexBuffer {
slot: u32,
buffer_id: id::BufferId,
buffer: R::Buffer,
offset: BufferAddress,
size: Option<BufferSize>,
},
@ -88,30 +84,36 @@ pub enum RenderCommand {
group_count_z: u32,
},
DrawIndirect {
buffer_id: id::BufferId,
buffer: R::Buffer,
offset: BufferAddress,
count: u32,
family: DrawCommandFamily,
/// This limit is only populated for commands in a finished [`RenderBundle`].
vertex_or_index_limit: Option<u64>,
/// This limit is only populated for commands in a finished [`RenderBundle`].
instance_limit: Option<u64>,
},
MultiDrawIndirectCount {
buffer_id: id::BufferId,
buffer: R::Buffer,
offset: BufferAddress,
count_buffer_id: id::BufferId,
count_buffer: R::Buffer,
count_buffer_offset: BufferAddress,
max_count: u32,
family: DrawCommandFamily,
},
PushDebugGroup {
#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
color: u32,
len: usize,
},
PopDebugGroup,
InsertDebugMarker {
#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
color: u32,
len: usize,
},
WriteTimestamp {
query_set_id: id::QuerySetId,
query_set: R::QuerySet,
query_index: u32,
},
BeginOcclusionQuery {
@ -119,290 +121,11 @@ pub enum RenderCommand {
},
EndOcclusionQuery,
BeginPipelineStatisticsQuery {
query_set_id: id::QuerySetId,
query_set: R::QuerySet,
query_index: u32,
},
EndPipelineStatisticsQuery,
ExecuteBundle(id::RenderBundleId),
}
impl RenderCommand {
/// Resolves all ids in a list of commands into the corresponding resource Arc.
#[cfg(any(feature = "serde", feature = "replay"))]
pub fn resolve_render_command_ids(
hub: &crate::hub::Hub,
commands: &[RenderCommand],
) -> Result<alloc::vec::Vec<ArcRenderCommand>, super::RenderPassError> {
use super::{DrawKind, PassErrorScope, RenderPassError};
use alloc::vec::Vec;
let buffers_guard = hub.buffers.read();
let bind_group_guard = hub.bind_groups.read();
let query_set_guard = hub.query_sets.read();
let pipelines_guard = hub.render_pipelines.read();
let render_bundles_guard = hub.render_bundles.read();
let resolved_commands: Vec<ArcRenderCommand> =
commands
.iter()
.map(|c| -> Result<ArcRenderCommand, RenderPassError> {
Ok(match *c {
RenderCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group_id,
} => {
if bind_group_id.is_none() {
return Ok(ArcRenderCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group: None,
});
}
let bind_group_id = bind_group_id.unwrap();
let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::SetBindGroup,
inner: e.into(),
}
})?;
ArcRenderCommand::SetBindGroup {
index,
num_dynamic_offsets,
bind_group: Some(bg),
}
}
RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline(
pipelines_guard.get(pipeline_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::SetPipelineRender,
inner: e.into(),
}
})?,
),
RenderCommand::SetPushConstant {
offset,
size_bytes,
values_offset,
stages,
} => ArcRenderCommand::SetPushConstant {
offset,
size_bytes,
values_offset,
stages,
},
RenderCommand::PushDebugGroup { color, len } => {
ArcRenderCommand::PushDebugGroup { color, len }
}
RenderCommand::PopDebugGroup => ArcRenderCommand::PopDebugGroup,
RenderCommand::InsertDebugMarker { color, len } => {
ArcRenderCommand::InsertDebugMarker { color, len }
}
RenderCommand::WriteTimestamp {
query_set_id,
query_index,
} => ArcRenderCommand::WriteTimestamp {
query_set: query_set_guard.get(query_set_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::WriteTimestamp,
inner: e.into(),
}
})?,
query_index,
},
RenderCommand::BeginPipelineStatisticsQuery {
query_set_id,
query_index,
} => ArcRenderCommand::BeginPipelineStatisticsQuery {
query_set: query_set_guard.get(query_set_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::BeginPipelineStatisticsQuery,
inner: e.into(),
}
})?,
query_index,
},
RenderCommand::EndPipelineStatisticsQuery => {
ArcRenderCommand::EndPipelineStatisticsQuery
}
RenderCommand::SetIndexBuffer {
buffer_id,
index_format,
offset,
size,
} => ArcRenderCommand::SetIndexBuffer {
buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::SetIndexBuffer,
inner: e.into(),
}
})?,
index_format,
offset,
size,
},
RenderCommand::SetVertexBuffer {
slot,
buffer_id,
offset,
size,
} => ArcRenderCommand::SetVertexBuffer {
slot,
buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::SetVertexBuffer,
inner: e.into(),
}
})?,
offset,
size,
},
RenderCommand::SetBlendConstant(color) => {
ArcRenderCommand::SetBlendConstant(color)
}
RenderCommand::SetStencilReference(reference) => {
ArcRenderCommand::SetStencilReference(reference)
}
RenderCommand::SetViewport {
rect,
depth_min,
depth_max,
} => ArcRenderCommand::SetViewport {
rect,
depth_min,
depth_max,
},
RenderCommand::SetScissor(scissor) => ArcRenderCommand::SetScissor(scissor),
RenderCommand::Draw {
vertex_count,
instance_count,
first_vertex,
first_instance,
} => ArcRenderCommand::Draw {
vertex_count,
instance_count,
first_vertex,
first_instance,
},
RenderCommand::DrawIndexed {
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
} => ArcRenderCommand::DrawIndexed {
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
},
RenderCommand::DrawMeshTasks {
group_count_x,
group_count_y,
group_count_z,
} => ArcRenderCommand::DrawMeshTasks {
group_count_x,
group_count_y,
group_count_z,
},
RenderCommand::DrawIndirect {
buffer_id,
offset,
count,
family,
} => ArcRenderCommand::DrawIndirect {
buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::Draw {
kind: if count != 1 {
DrawKind::MultiDrawIndirect
} else {
DrawKind::DrawIndirect
},
family,
},
inner: e.into(),
}
})?,
offset,
count,
family,
vertex_or_index_limit: 0,
instance_limit: 0,
},
RenderCommand::MultiDrawIndirectCount {
buffer_id,
offset,
count_buffer_id,
count_buffer_offset,
max_count,
family,
} => {
let scope = PassErrorScope::Draw {
kind: DrawKind::MultiDrawIndirectCount,
family,
};
ArcRenderCommand::MultiDrawIndirectCount {
buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
RenderPassError {
scope,
inner: e.into(),
}
})?,
offset,
count_buffer: buffers_guard.get(count_buffer_id).get().map_err(
|e| RenderPassError {
scope,
inner: e.into(),
},
)?,
count_buffer_offset,
max_count,
family,
}
}
RenderCommand::BeginOcclusionQuery { query_index } => {
ArcRenderCommand::BeginOcclusionQuery { query_index }
}
RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery,
RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle(
render_bundles_guard.get(bundle).get().map_err(|e| {
RenderPassError {
scope: PassErrorScope::ExecuteBundle,
inner: e.into(),
}
})?,
),
})
})
.collect::<Result<Vec<_>, RenderPassError>>()?;
Ok(resolved_commands)
}
ExecuteBundle(R::RenderBundle),
}
/// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs.
@ -417,123 +140,6 @@ impl RenderCommand {
/// is `finish()`ed and when the bundle is executed. Validation occurs when the
/// bundle is finished, which means that parameters stored in an `ArcRenderCommand`
/// for a render bundle operation must have been validated.
#[doc(hidden)]
#[derive(Clone, Debug)]
pub enum ArcRenderCommand {
SetBindGroup {
index: u32,
num_dynamic_offsets: usize,
bind_group: Option<Arc<BindGroup>>,
},
SetPipeline(Arc<RenderPipeline>),
SetIndexBuffer {
buffer: Arc<Buffer>,
index_format: wgt::IndexFormat,
offset: BufferAddress,
size: Option<BufferSize>,
},
SetVertexBuffer {
slot: u32,
buffer: Arc<Buffer>,
offset: BufferAddress,
size: Option<BufferSize>,
},
SetBlendConstant(Color),
SetStencilReference(u32),
SetViewport {
rect: Rect<f32>,
depth_min: f32,
depth_max: f32,
},
SetScissor(Rect<u32>),
/// Set a range of push constants to values stored in [`BasePass::push_constant_data`].
///
/// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation
/// of the restrictions these commands must satisfy.
SetPushConstant {
/// Which stages we are setting push constant values for.
stages: wgt::ShaderStages,
/// The byte offset within the push constant storage to write to. This
/// must be a multiple of four.
offset: u32,
/// The number of bytes to write. This must be a multiple of four.
size_bytes: u32,
/// Index in [`BasePass::push_constant_data`] of the start of the data
/// to be written.
///
/// Note: this is not a byte offset like `offset`. Rather, it is the
/// index of the first `u32` element in `push_constant_data` to read.
///
/// `None` means zeros should be written to the destination range, and
/// there is no corresponding data in `push_constant_data`. This is used
/// by render bundles, which explicitly clear out any state that
/// post-bundle code might see.
values_offset: Option<u32>,
},
Draw {
vertex_count: u32,
instance_count: u32,
first_vertex: u32,
first_instance: u32,
},
DrawIndexed {
index_count: u32,
instance_count: u32,
first_index: u32,
base_vertex: i32,
first_instance: u32,
},
DrawMeshTasks {
group_count_x: u32,
group_count_y: u32,
group_count_z: u32,
},
DrawIndirect {
buffer: Arc<Buffer>,
offset: BufferAddress,
count: u32,
family: DrawCommandFamily,
/// This limit is only populated for commands in a [`RenderBundle`].
vertex_or_index_limit: u64,
/// This limit is only populated for commands in a [`RenderBundle`].
instance_limit: u64,
},
MultiDrawIndirectCount {
buffer: Arc<Buffer>,
offset: BufferAddress,
count_buffer: Arc<Buffer>,
count_buffer_offset: BufferAddress,
max_count: u32,
family: DrawCommandFamily,
},
PushDebugGroup {
#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
color: u32,
len: usize,
},
PopDebugGroup,
InsertDebugMarker {
#[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
color: u32,
len: usize,
},
WriteTimestamp {
query_set: Arc<QuerySet>,
query_index: u32,
},
BeginOcclusionQuery {
query_index: u32,
},
EndOcclusionQuery,
BeginPipelineStatisticsQuery {
query_set: Arc<QuerySet>,
query_index: u32,
},
EndPipelineStatisticsQuery,
ExecuteBundle(Arc<RenderBundle>),
}
///
/// cbindgen:ignore
pub type ArcRenderCommand = RenderCommand<ArcReferences>;

View File

@ -8,8 +8,6 @@ use wgt::{
TextureUsages,
};
#[cfg(feature = "trace")]
use crate::command::Command as TraceCommand;
use crate::{
api_log,
command::{
@ -825,17 +823,6 @@ impl Global {
let cmd_enc = hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::CopyBufferToBuffer {
src: source,
src_offset: source_offset,
dst: destination,
dst_offset: destination_offset,
size,
});
}
cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
Ok(ArcCommand::CopyBufferToBuffer {
src: self.resolve_buffer_id(source)?,
@ -864,15 +851,6 @@ impl Global {
let cmd_enc = self.hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::CopyBufferToTexture {
src: *source,
dst: *destination,
size: *copy_size,
});
}
cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
Ok(ArcCommand::CopyBufferToTexture {
src: wgt::TexelCopyBufferInfo::<Arc<Buffer>> {
@ -907,15 +885,6 @@ impl Global {
let cmd_enc = self.hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(list) = cmd_buf_data.trace() {
list.push(TraceCommand::CopyTextureToBuffer {
src: *source,
dst: *destination,
size: *copy_size,
});
}
cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
Ok(ArcCommand::CopyTextureToBuffer {
src: wgt::TexelCopyTextureInfo::<Arc<Texture>> {
@ -950,15 +919,6 @@ impl Global {
let cmd_enc = self.hub.command_encoders.get(command_encoder_id);
let mut cmd_buf_data = cmd_enc.data.lock();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf_data.trace() {
list.push(TraceCommand::CopyTextureToTexture {
src: *source,
dst: *destination,
size: *copy_size,
});
}
cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
Ok(ArcCommand::CopyTextureToTexture {
src: wgt::TexelCopyTextureInfo {

View File

@ -2,7 +2,7 @@ use alloc::{borrow::Cow, boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{ptr::NonNull, sync::atomic::Ordering};
#[cfg(feature = "trace")]
use crate::device::trace;
use crate::device::trace::{self, IntoTrace};
use crate::{
api_log,
binding_model::{
@ -106,6 +106,13 @@ impl Global {
let error = 'error: {
let device = self.hub.devices.get(device_id);
let buffer = match device.create_buffer(desc) {
Ok(buffer) => buffer,
Err(e) => {
break 'error e;
}
};
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
let mut desc = desc.clone();
@ -113,16 +120,9 @@ impl Global {
if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
desc.usage |= wgt::BufferUsages::COPY_DST;
}
trace.add(trace::Action::CreateBuffer(fid.id(), desc));
trace.add(trace::Action::CreateBuffer(buffer.to_trace(), desc));
}
let buffer = match device.create_buffer(desc) {
Ok(buffer) => buffer,
Err(e) => {
break 'error e;
}
};
let id = fid.assign(Fallible::Valid(buffer));
api_log!(
@ -240,13 +240,10 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(trace) = buffer.device.trace.lock().as_mut() {
trace.add(trace::Action::FreeBuffer(buffer_id));
trace.add(trace::Action::FreeBuffer(buffer.to_trace()));
}
let _ = buffer.unmap(
#[cfg(feature = "trace")]
buffer_id,
);
let _ = buffer.unmap();
buffer.destroy();
}
@ -266,13 +263,10 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(t) = buffer.device.trace.lock().as_mut() {
t.add(trace::Action::DestroyBuffer(buffer_id));
t.add(trace::Action::DestroyBuffer(buffer.to_trace()));
}
let _ = buffer.unmap(
#[cfg(feature = "trace")]
buffer_id,
);
let _ = buffer.unmap();
}
pub fn device_create_texture(
@ -290,16 +284,19 @@ impl Global {
let error = 'error: {
let device = self.hub.devices.get(device_id);
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
}
let texture = match device.create_texture(desc) {
Ok(texture) => texture,
Err(error) => break 'error error,
};
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTexture(
texture.to_trace(),
desc.clone(),
));
}
let id = fid.assign(Fallible::Valid(texture));
api_log!("Device::create_texture({desc:?}) -> {id:?}");
@ -331,18 +328,21 @@ impl Global {
let error = 'error: {
let device = self.hub.devices.get(device_id);
// NB: Any change done through the raw texture handle will not be
// recorded in the replay
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
}
let texture = match device.create_texture_from_hal(hal_texture, desc) {
Ok(texture) => texture,
Err(error) => break 'error error,
};
// NB: Any change done through the raw texture handle will not be
// recorded in the replay
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTexture(
texture.to_trace(),
desc.clone(),
));
}
let id = fid.assign(Fallible::Valid(texture));
api_log!("Device::create_texture({desc:?}) -> {id:?}");
@ -373,15 +373,20 @@ impl Global {
let device = self.hub.devices.get(device_id);
let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) };
// NB: Any change done through the raw buffer handle will not be
// recorded in the replay
#[cfg(feature = "trace")]
if let Some(trace) = device.trace.lock().as_mut() {
trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone()));
match &buffer {
Fallible::Valid(arc) => {
trace.add(trace::Action::CreateBuffer(arc.to_trace(), desc.clone()))
}
Fallible::Invalid(_) => {}
}
}
let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) };
let id = fid.assign(buffer);
api_log!("Device::create_buffer -> {id:?}");
@ -401,7 +406,7 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(trace) = texture.device.trace.lock().as_mut() {
trace.add(trace::Action::FreeTexture(texture_id));
trace.add(trace::Action::FreeTexture(texture.to_trace()));
}
texture.destroy();
@ -417,7 +422,7 @@ impl Global {
#[cfg(feature = "trace")]
if let Ok(texture) = _texture.get() {
if let Some(t) = texture.device.trace.lock().as_mut() {
t.add(trace::Action::DestroyTexture(texture_id));
t.add(trace::Action::DestroyTexture(texture.to_trace()));
}
}
}
@ -441,20 +446,20 @@ impl Global {
};
let device = &texture.device;
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTextureView {
id: fid.id(),
parent_id: texture_id,
desc: desc.clone(),
});
}
let view = match device.create_texture_view(&texture, desc) {
Ok(view) => view,
Err(e) => break 'error e,
};
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTextureView {
id: view.to_trace(),
parent: texture.to_trace(),
desc: desc.clone(),
});
}
let id = fid.assign(Fallible::Valid(view));
api_log!("Texture::create_view({texture_id:?}) -> {id:?}");
@ -480,7 +485,7 @@ impl Global {
#[cfg(feature = "trace")]
if let Ok(view) = _view.get() {
if let Some(t) = view.device.trace.lock().as_mut() {
t.add(trace::Action::DestroyTextureView(texture_view_id));
t.add(trace::Action::DestroyTextureView(view.to_trace()));
}
}
Ok(())
@ -1170,24 +1175,27 @@ impl Global {
let device = self.hub.devices.get(bundle_encoder.parent());
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateRenderBundle {
id: fid.id(),
desc: trace::new_render_bundle_encoder_descriptor(
desc.label.clone(),
&bundle_encoder.context,
bundle_encoder.is_depth_read_only,
bundle_encoder.is_stencil_read_only,
),
base: bundle_encoder.to_base_pass(),
});
}
let trace_desc = trace::new_render_bundle_encoder_descriptor(
desc.label.clone(),
&bundle_encoder.context,
bundle_encoder.is_depth_read_only,
bundle_encoder.is_stencil_read_only,
);
let render_bundle = match bundle_encoder.finish(desc, &device, hub) {
Ok(bundle) => bundle,
Err(e) => break 'error e,
};
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateRenderBundle {
id: render_bundle.to_trace(),
desc: trace_desc,
base: render_bundle.to_base_pass().to_trace(),
});
}
let id = fid.assign(Fallible::Valid(render_bundle));
api_log!("RenderBundleEncoder::finish -> {id:?}");
@ -1742,7 +1750,10 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::ConfigureSurface(surface_id, config.clone()));
trace.add(trace::Action::ConfigureSurface(
surface.to_trace(),
config.clone(),
));
}
device.configure_surface(&surface, config)
@ -2082,9 +2093,6 @@ impl Global {
drop(snatch_guard);
buffer.device.check_is_valid()?;
buffer.unmap(
#[cfg(feature = "trace")]
buffer_id,
)
buffer.unmap()
}
}

View File

@ -15,7 +15,7 @@ use wgt::{
use super::{life::LifetimeTracker, Device};
#[cfg(feature = "trace")]
use crate::device::trace::Action;
use crate::device::trace::{Action, IntoTrace};
use crate::{
api_log,
command::{
@ -521,7 +521,7 @@ impl WebGpuError for QueueSubmitError {
impl Queue {
pub fn write_buffer(
&self,
buffer: Fallible<Buffer>,
buffer: Arc<Buffer>,
buffer_offset: wgt::BufferAddress,
data: &[u8],
) -> Result<(), QueueWriteError> {
@ -530,8 +530,6 @@ impl Queue {
self.device.check_is_valid()?;
let buffer = buffer.get()?;
let data_size = data.len() as wgt::BufferAddress;
self.same_device_as(buffer.as_ref())?;
@ -728,7 +726,7 @@ impl Queue {
pub fn write_texture(
&self,
destination: wgt::TexelCopyTextureInfo<Fallible<Texture>>,
destination: wgt::TexelCopyTextureInfo<Arc<Texture>>,
data: &[u8],
data_layout: &wgt::TexelCopyBufferLayout,
size: &wgt::Extent3d,
@ -738,7 +736,7 @@ impl Queue {
self.device.check_is_valid()?;
let dst = destination.texture.get()?;
let dst = destination.texture;
let destination = wgt::TexelCopyTextureInfo {
texture: (),
mip_level: destination.mip_level,
@ -1559,19 +1557,19 @@ impl Global {
data: &[u8],
) -> Result<(), QueueWriteError> {
let queue = self.hub.queues.get(queue_id);
let buffer = self.hub.buffers.get(buffer_id).get()?;
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *queue.device.trace.lock() {
let data_path = trace.make_binary("bin", data);
trace.add(Action::WriteBuffer {
id: buffer_id,
id: buffer.to_trace(),
data: data_path,
range: buffer_offset..buffer_offset + data.len() as u64,
queued: true,
});
}
let buffer = self.hub.buffers.get(buffer_id);
queue.write_buffer(buffer, buffer_offset, data)
}
@ -1624,24 +1622,25 @@ impl Global {
size: &wgt::Extent3d,
) -> Result<(), QueueWriteError> {
let queue = self.hub.queues.get(queue_id);
let texture = self.hub.textures.get(destination.texture).get()?;
let destination = wgt::TexelCopyTextureInfo {
texture,
mip_level: destination.mip_level,
origin: destination.origin,
aspect: destination.aspect,
};
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *queue.device.trace.lock() {
let data_path = trace.make_binary("bin", data);
trace.add(Action::WriteTexture {
to: *destination,
to: destination.to_trace(),
data: data_path,
layout: *data_layout,
size: *size,
});
}
let destination = wgt::TexelCopyTextureInfo {
texture: self.hub.textures.get(destination.texture),
mip_level: destination.mip_level,
origin: destination.origin,
aspect: destination.aspect,
};
queue.write_texture(destination, data, data_layout, size)
}

View File

@ -1993,7 +1993,7 @@ impl Device {
};
let params = self.create_buffer(&params_desc)?;
self.get_queue().unwrap().write_buffer(
Fallible::Valid(params.clone()),
params.clone(),
0,
bytemuck::bytes_of(&params_data),
)?;

View File

@ -27,7 +27,7 @@ pub enum Action<'a, R: ReferenceType> {
backend: wgt::Backend,
},
ConfigureSurface(
id::SurfaceId,
R::Surface,
wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
),
CreateBuffer(R::Buffer, crate::resource::BufferDescriptor<'a>),
@ -38,7 +38,7 @@ pub enum Action<'a, R: ReferenceType> {
DestroyTexture(R::Texture),
CreateTextureView {
id: R::TextureView,
parent_id: R::Texture,
parent: R::Texture,
desc: crate::resource::TextureViewDescriptor<'a>,
},
DestroyTextureView(R::TextureView),
@ -53,10 +53,10 @@ pub enum Action<'a, R: ReferenceType> {
DestroySampler(id::SamplerId),
GetSurfaceTexture {
id: R::Texture,
parent_id: id::SurfaceId,
parent: R::Surface,
},
Present(id::SurfaceId),
DiscardSurfaceTexture(id::SurfaceId),
Present(R::Surface),
DiscardSurfaceTexture(R::Surface),
CreateBindGroupLayout(
id::BindGroupLayoutId,
crate::binding_model::BindGroupLayoutDescriptor<'a>,
@ -107,9 +107,9 @@ pub enum Action<'a, R: ReferenceType> {
},
DestroyPipelineCache(id::PipelineCacheId),
CreateRenderBundle {
id: id::RenderBundleId,
id: R::RenderBundle,
desc: crate::command::RenderBundleEncoderDescriptor<'a>,
base: BasePass<RenderCommand, Infallible>,
base: BasePass<RenderCommand<R>, Infallible>,
},
DestroyRenderBundle(id::RenderBundleId),
CreateQuerySet {
@ -129,7 +129,7 @@ pub enum Action<'a, R: ReferenceType> {
layout: wgt::TexelCopyBufferLayout,
size: wgt::Extent3d,
},
Submit(crate::SubmissionIndex, Vec<Command>),
Submit(crate::SubmissionIndex, Vec<Command<R>>),
CreateBlas {
id: id::BlasId,
desc: crate::resource::BlasDescriptor<'a>,

View File

@ -1,19 +1,32 @@
use alloc::{borrow::Cow, string::String};
use alloc::{
borrow::Cow,
string::{String, ToString},
sync::Arc,
};
use core::convert::Infallible;
use std::io::Write as _;
use crate::command::IdReferences;
use crate::{
command::{
ArcCommand, ArcComputeCommand, ArcPassTimestampWrites, ArcReferences, ArcRenderCommand,
BasePass, ColorAttachments, Command, ComputeCommand, PointerReferences, RenderCommand,
RenderPassColorAttachment, ResolvedRenderPassDepthStencilAttachment,
},
id,
storage::StorageItem,
};
use super::{Action, FILE_NAME};
pub(crate) fn new_render_bundle_encoder_descriptor<'a>(
label: crate::Label<'a>,
context: &'a crate::device::RenderPassContext,
pub(crate) fn new_render_bundle_encoder_descriptor(
label: crate::Label<'_>,
context: &crate::device::RenderPassContext,
depth_read_only: bool,
stencil_read_only: bool,
) -> crate::command::RenderBundleEncoderDescriptor<'a> {
) -> crate::command::RenderBundleEncoderDescriptor<'static> {
crate::command::RenderBundleEncoderDescriptor {
label,
color_formats: Cow::Borrowed(&context.attachments.colors),
label: label.map(|l| Cow::from(l.to_string())),
color_formats: Cow::from(context.attachments.colors.to_vec()),
depth_stencil: context.attachments.depth_stencil.map(|format| {
wgt::RenderBundleDepthStencil {
format,
@ -54,9 +67,9 @@ impl Trace {
name
}
pub(crate) fn add(&mut self, action: Action<'_, IdReferences>)
pub(crate) fn add(&mut self, action: Action<'_, PointerReferences>)
where
for<'a> Action<'a, IdReferences>: serde::Serialize,
for<'a> Action<'a, PointerReferences>: serde::Serialize,
{
match ron::ser::to_string_pretty(&action, self.config.clone()) {
Ok(string) => {
@ -74,3 +87,476 @@ impl Drop for Trace {
let _ = self.file.write_all(b"]");
}
}
pub(crate) trait IntoTrace {
type Output;
fn into_trace(self) -> Self::Output;
fn to_trace(&self) -> Self::Output
where
Self: Sized + Clone,
{
self.clone().into_trace()
}
}
impl<T: StorageItem> IntoTrace for Arc<T> {
type Output = id::PointerId<T::Marker>;
fn into_trace(self) -> Self::Output {
self.to_trace()
}
fn to_trace(&self) -> Self::Output {
id::PointerId::from(self)
}
}
impl IntoTrace for ArcCommand {
type Output = Command<PointerReferences>;
fn into_trace(self) -> Self::Output {
match self {
ArcCommand::CopyBufferToBuffer {
src,
src_offset,
dst,
dst_offset,
size,
} => Command::CopyBufferToBuffer {
src: src.to_trace(),
src_offset,
dst: dst.to_trace(),
dst_offset,
size,
},
ArcCommand::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture {
src: src.into_trace(),
dst: dst.into_trace(),
size,
},
ArcCommand::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer {
src: src.into_trace(),
dst: dst.into_trace(),
size,
},
ArcCommand::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture {
src: src.into_trace(),
dst: dst.into_trace(),
size,
},
ArcCommand::ClearBuffer { dst, offset, size } => Command::ClearBuffer {
dst: dst.to_trace(),
offset,
size,
},
ArcCommand::ClearTexture {
dst,
subresource_range,
} => Command::ClearTexture {
dst: dst.to_trace(),
subresource_range,
},
ArcCommand::WriteTimestamp {
query_set,
query_index,
} => Command::WriteTimestamp {
query_set: query_set.to_trace(),
query_index,
},
ArcCommand::ResolveQuerySet {
query_set,
start_query,
query_count,
destination,
destination_offset,
} => Command::ResolveQuerySet {
query_set: query_set.to_trace(),
start_query,
query_count,
destination: destination.to_trace(),
destination_offset,
},
ArcCommand::PushDebugGroup(label) => Command::PushDebugGroup(label),
ArcCommand::PopDebugGroup => Command::PopDebugGroup,
ArcCommand::InsertDebugMarker(label) => Command::InsertDebugMarker(label),
ArcCommand::RunComputePass {
pass,
timestamp_writes,
} => Command::RunComputePass {
pass: pass.into_trace(),
timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
},
ArcCommand::RunRenderPass {
pass,
color_attachments,
depth_stencil_attachment,
timestamp_writes,
occlusion_query_set,
} => Command::RunRenderPass {
pass: pass.into_trace(),
color_attachments: color_attachments.into_trace(),
depth_stencil_attachment: depth_stencil_attachment.map(|d| d.into_trace()),
timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
occlusion_query_set: occlusion_query_set.map(|q| q.to_trace()),
},
ArcCommand::BuildAccelerationStructures { blas, tlas } => {
Command::BuildAccelerationStructures {
blas: blas.into_iter().map(|b| b.into_trace()).collect(),
tlas: tlas.into_iter().map(|b| b.into_trace()).collect(),
}
}
ArcCommand::TransitionResources {
buffer_transitions: _,
texture_transitions: _,
} => {
// TransitionResources does not exist in Command, so skip or handle as needed.
// If you want to ignore, you could panic or return a default.
panic!("TransitionResources cannot be converted to Command");
}
}
}
}
impl<T: IntoTrace> IntoTrace for wgt::TexelCopyBufferInfo<T> {
type Output = wgt::TexelCopyBufferInfo<T::Output>;
fn into_trace(self) -> Self::Output {
wgt::TexelCopyBufferInfo {
buffer: self.buffer.into_trace(),
layout: self.layout,
}
}
}
impl<T: IntoTrace> IntoTrace for wgt::TexelCopyTextureInfo<T> {
type Output = wgt::TexelCopyTextureInfo<T::Output>;
fn into_trace(self) -> Self::Output {
wgt::TexelCopyTextureInfo {
texture: self.texture.into_trace(),
mip_level: self.mip_level,
origin: self.origin,
aspect: self.aspect,
}
}
}
impl IntoTrace for ArcPassTimestampWrites {
type Output = crate::command::PassTimestampWrites<id::PointerId<id::markers::QuerySet>>;
fn into_trace(self) -> Self::Output {
crate::command::PassTimestampWrites {
query_set: self.query_set.into_trace(),
beginning_of_pass_write_index: self.beginning_of_pass_write_index,
end_of_pass_write_index: self.end_of_pass_write_index,
}
}
}
impl IntoTrace for ColorAttachments {
type Output = ColorAttachments<id::PointerId<id::markers::TextureView>>;
fn into_trace(self) -> Self::Output {
self.into_iter()
.map(|opt| {
opt.map(|att| RenderPassColorAttachment {
view: att.view.into_trace(),
depth_slice: att.depth_slice,
resolve_target: att.resolve_target.map(|r| r.into_trace()),
load_op: att.load_op,
store_op: att.store_op,
})
})
.collect()
}
}
impl<TV: IntoTrace> IntoTrace for ResolvedRenderPassDepthStencilAttachment<TV> {
type Output = ResolvedRenderPassDepthStencilAttachment<TV::Output>;
fn into_trace(self) -> Self::Output {
ResolvedRenderPassDepthStencilAttachment {
view: self.view.into_trace(),
depth: self.depth,
stencil: self.stencil,
}
}
}
impl IntoTrace for crate::ray_tracing::OwnedBlasBuildEntry<ArcReferences> {
type Output = crate::ray_tracing::OwnedBlasBuildEntry<PointerReferences>;
fn into_trace(self) -> Self::Output {
crate::ray_tracing::OwnedBlasBuildEntry {
blas: self.blas.into_trace(),
geometries: self.geometries.into_trace(),
}
}
}
impl IntoTrace for crate::ray_tracing::OwnedBlasGeometries<ArcReferences> {
type Output = crate::ray_tracing::OwnedBlasGeometries<PointerReferences>;
fn into_trace(self) -> Self::Output {
match self {
crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => {
crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(
geos.into_iter().map(|g| g.into_trace()).collect(),
)
}
}
}
}
impl IntoTrace for crate::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> {
type Output = crate::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>;
fn into_trace(self) -> Self::Output {
crate::ray_tracing::OwnedBlasTriangleGeometry {
size: self.size,
vertex_buffer: self.vertex_buffer.into_trace(),
index_buffer: self.index_buffer.map(|b| b.into_trace()),
transform_buffer: self.transform_buffer.map(|b| b.into_trace()),
first_vertex: self.first_vertex,
vertex_stride: self.vertex_stride,
first_index: self.first_index,
transform_buffer_offset: self.transform_buffer_offset,
}
}
}
impl IntoTrace for crate::ray_tracing::OwnedTlasPackage<ArcReferences> {
type Output = crate::ray_tracing::OwnedTlasPackage<PointerReferences>;
fn into_trace(self) -> Self::Output {
crate::ray_tracing::OwnedTlasPackage {
tlas: self.tlas.into_trace(),
instances: self
.instances
.into_iter()
.map(|opt| opt.map(|inst| inst.into_trace()))
.collect(),
lowest_unmodified: self.lowest_unmodified,
}
}
}
impl IntoTrace for crate::ray_tracing::OwnedTlasInstance<ArcReferences> {
type Output = crate::ray_tracing::OwnedTlasInstance<PointerReferences>;
fn into_trace(self) -> Self::Output {
crate::ray_tracing::OwnedTlasInstance {
blas: self.blas.into_trace(),
transform: self.transform,
custom_data: self.custom_data,
mask: self.mask,
}
}
}
impl<C: IntoTrace> IntoTrace for BasePass<C, Infallible> {
type Output = BasePass<C::Output, Infallible>;
fn into_trace(self) -> Self::Output {
BasePass {
label: self.label,
error: self.error,
commands: self
.commands
.into_iter()
.map(|cmd| cmd.into_trace())
.collect(),
dynamic_offsets: self.dynamic_offsets,
string_data: self.string_data,
push_constant_data: self.push_constant_data,
}
}
}
impl IntoTrace for ArcComputeCommand {
type Output = ComputeCommand<PointerReferences>;
fn into_trace(self) -> Self::Output {
use ComputeCommand as C;
match self {
C::SetBindGroup {
index,
num_dynamic_offsets,
bind_group,
} => C::SetBindGroup {
index,
num_dynamic_offsets,
bind_group: bind_group.map(|bg| bg.into_trace()),
},
C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
C::SetPushConstant {
offset,
size_bytes,
values_offset,
} => C::SetPushConstant {
offset,
size_bytes,
values_offset,
},
C::Dispatch(groups) => C::Dispatch(groups),
C::DispatchIndirect { buffer, offset } => C::DispatchIndirect {
buffer: buffer.into_trace(),
offset,
},
C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
C::PopDebugGroup => C::PopDebugGroup,
C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
C::WriteTimestamp {
query_set,
query_index,
} => C::WriteTimestamp {
query_set: query_set.into_trace(),
query_index,
},
C::BeginPipelineStatisticsQuery {
query_set,
query_index,
} => C::BeginPipelineStatisticsQuery {
query_set: query_set.into_trace(),
query_index,
},
C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
}
}
}
impl IntoTrace for ArcRenderCommand {
type Output = RenderCommand<PointerReferences>;
fn into_trace(self) -> Self::Output {
use RenderCommand as C;
match self {
C::SetBindGroup {
index,
num_dynamic_offsets,
bind_group,
} => C::SetBindGroup {
index,
num_dynamic_offsets,
bind_group: bind_group.map(|bg| bg.into_trace()),
},
C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
C::SetIndexBuffer {
buffer,
index_format,
offset,
size,
} => C::SetIndexBuffer {
buffer: buffer.into_trace(),
index_format,
offset,
size,
},
C::SetVertexBuffer {
slot,
buffer,
offset,
size,
} => C::SetVertexBuffer {
slot,
buffer: buffer.into_trace(),
offset,
size,
},
C::SetBlendConstant(color) => C::SetBlendConstant(color),
C::SetStencilReference(val) => C::SetStencilReference(val),
C::SetViewport {
rect,
depth_min,
depth_max,
} => C::SetViewport {
rect,
depth_min,
depth_max,
},
C::SetScissor(rect) => C::SetScissor(rect),
C::SetPushConstant {
stages,
offset,
size_bytes,
values_offset,
} => C::SetPushConstant {
stages,
offset,
size_bytes,
values_offset,
},
C::Draw {
vertex_count,
instance_count,
first_vertex,
first_instance,
} => C::Draw {
vertex_count,
instance_count,
first_vertex,
first_instance,
},
C::DrawIndexed {
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
} => C::DrawIndexed {
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
},
C::DrawMeshTasks {
group_count_x,
group_count_y,
group_count_z,
} => C::DrawMeshTasks {
group_count_x,
group_count_y,
group_count_z,
},
C::DrawIndirect {
buffer,
offset,
count,
family,
vertex_or_index_limit,
instance_limit,
} => C::DrawIndirect {
buffer: buffer.into_trace(),
offset,
count,
family,
vertex_or_index_limit,
instance_limit,
},
C::MultiDrawIndirectCount {
buffer,
offset,
count_buffer,
count_buffer_offset,
max_count,
family,
} => C::MultiDrawIndirectCount {
buffer: buffer.into_trace(),
offset,
count_buffer: count_buffer.into_trace(),
count_buffer_offset,
max_count,
family,
},
C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
C::PopDebugGroup => C::PopDebugGroup,
C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
C::WriteTimestamp {
query_set,
query_index,
} => C::WriteTimestamp {
query_set: query_set.into_trace(),
query_index,
},
C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index },
C::EndOcclusionQuery => C::EndOcclusionQuery,
C::BeginPipelineStatisticsQuery {
query_set,
query_index,
} => C::BeginPipelineStatisticsQuery {
query_set: query_set.into_trace(),
query_index,
},
C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
C::ExecuteBundle(bundle) => C::ExecuteBundle(bundle.into_trace()),
}
}
}

View File

@ -1,4 +1,5 @@
use crate::{Epoch, Index};
use crate::{storage::StorageItem, Epoch, Index};
use alloc::sync::Arc;
use core::{
cmp::Ordering,
fmt::{self, Debug},
@ -82,18 +83,15 @@ impl RawId {
/// [`Registry`]: crate::registry::Registry
/// [`Noop`]: hal::api::Noop
#[repr(transparent)]
#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))]
#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))]
#[cfg_attr(
any(feature = "serde", feature = "trace", feature = "replay"),
serde(transparent)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct Id<T: Marker>(RawId, PhantomData<T>);
// This type represents Id in a more readable (and editable) way.
#[allow(dead_code)]
#[cfg(feature = "serde")]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
enum SerialId {
#[derive(Clone, Debug)]
pub enum SerialId {
// The only variant forces RON to not ignore "Id"
Id(Index, Epoch),
}
@ -125,6 +123,48 @@ impl TryFrom<SerialId> for RawId {
}
}
/// Identify an object by the pointer returned by `Arc::as_ptr`.
///
/// This is used for tracing.
#[allow(dead_code)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug)]
pub struct PointerId<T: Marker>(usize, #[serde(skip)] PhantomData<T>);
impl<T: Marker> Copy for PointerId<T> {}
impl<T: Marker> Clone for PointerId<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Marker> PartialEq for PointerId<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: Marker> Eq for PointerId<T> {}
impl<T: Marker> Hash for PointerId<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: StorageItem> From<&Arc<T>> for PointerId<T::Marker> {
fn from(arc: &Arc<T>) -> Self {
// Since the memory representation of `Arc<T>` is just a pointer, it
// would be nice to use that pointer as the trace ID, since many
// `into_trace` implementations would then be no-ops at runtime.
// Unfortunately, because `Arc::as_ptr` returns a pointer to the
// contained data, and `Arc` stores reference counts before the data,
// we are adding an offset to the pointer here.
Self(Arc::as_ptr(arc) as usize, PhantomData)
}
}
impl<T> Id<T>
where
T: Marker,

View File

@ -13,7 +13,7 @@ use alloc::{sync::Arc, vec::Vec};
use core::mem::ManuallyDrop;
#[cfg(feature = "trace")]
use crate::device::trace::Action;
use crate::device::trace::{Action, IntoTrace};
use crate::{
conv,
device::{Device, DeviceError, MissingDownlevelFlags, WaitIdleError},
@ -363,10 +363,12 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(present) = surface.presentation.lock().as_ref() {
if let Some(ref mut trace) = *present.device.trace.lock() {
trace.add(Action::GetSurfaceTexture {
id: fid.id(),
parent_id: surface_id,
});
if let Some(texture) = present.acquired_texture.as_ref() {
trace.add(Action::GetSurfaceTexture {
id: texture.to_trace(),
parent: surface.to_trace(),
});
}
}
}
@ -389,7 +391,7 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(present) = surface.presentation.lock().as_ref() {
if let Some(ref mut trace) = *present.device.trace.lock() {
trace.add(Action::Present(surface_id));
trace.add(Action::Present(surface.to_trace()));
}
}
@ -402,7 +404,7 @@ impl Global {
#[cfg(feature = "trace")]
if let Some(present) = surface.presentation.lock().as_ref() {
if let Some(ref mut trace) = *present.device.trace.lock() {
trace.add(Action::DiscardSurfaceTexture(surface_id));
trace.add(Action::DiscardSurfaceTexture(surface.to_trace()));
}
}

View File

@ -337,7 +337,7 @@ pub type TraceBlasGeometries = OwnedBlasGeometries<IdReferences>;
#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))]
pub struct OwnedBlasBuildEntry<R: ReferenceType> {
pub blas: R::Blas,
pub geometries: OwnedBlasGeometries<R>, // TODO
pub geometries: OwnedBlasGeometries<R>,
}
pub type ArcBlasBuildEntry = OwnedBlasBuildEntry<ArcReferences>;

View File

@ -797,14 +797,8 @@ impl Buffer {
}
// Note: This must not be called while holding a lock.
pub(crate) fn unmap(
self: &Arc<Self>,
#[cfg(feature = "trace")] buffer_id: crate::id::BufferId,
) -> Result<(), BufferAccessError> {
if let Some((mut operation, status)) = self.unmap_inner(
#[cfg(feature = "trace")]
buffer_id,
)? {
pub(crate) fn unmap(self: &Arc<Self>) -> Result<(), BufferAccessError> {
if let Some((mut operation, status)) = self.unmap_inner()? {
if let Some(callback) = operation.callback.take() {
callback(status);
}
@ -813,10 +807,7 @@ impl Buffer {
Ok(())
}
fn unmap_inner(
self: &Arc<Self>,
#[cfg(feature = "trace")] buffer_id: crate::id::BufferId,
) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> {
fn unmap_inner(self: &Arc<Self>) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> {
let device = &self.device;
let snatch_guard = device.snatchable_lock.read();
let raw_buf = self.try_raw(&snatch_guard)?;
@ -824,9 +815,11 @@ impl Buffer {
BufferMapState::Init { staging_buffer } => {
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
use crate::device::trace::IntoTrace;
let data = trace.make_binary("bin", staging_buffer.get_data());
trace.add(trace::Action::WriteBuffer {
id: buffer_id,
id: self.to_trace(),
data,
range: 0..self.size,
queued: true,
@ -886,12 +879,14 @@ impl Buffer {
if host == HostMap::Write {
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
use crate::device::trace::IntoTrace;
let size = range.end - range.start;
let data = trace.make_binary("bin", unsafe {
core::slice::from_raw_parts(mapping.ptr.as_ptr(), size as usize)
});
trace.add(trace::Action::WriteBuffer {
id: buffer_id,
id: self.to_trace(),
data,
range: range.clone(),
queued: false,

View File

@ -19,7 +19,9 @@ where
Occupied(T, Epoch),
}
pub(crate) trait StorageItem: ResourceType {
/// Not a public API. For use only by `player`.
#[doc(hidden)]
pub trait StorageItem: ResourceType {
type Marker: Marker;
}