diff --git a/Cargo.lock b/Cargo.lock index 5ac6df3d5d5..2c7ac6701bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2370,6 +2370,22 @@ version = "0.1.4+2024.11.22-df583a3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e3cd67e8ea2ba061339150970542cf1c60ba44c6d17e31279cbc133a4b018f8" +[[package]] +name = "macro_rules_attribute" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" + [[package]] name = "malloc_buf" version = "0.0.6" @@ -3176,6 +3192,7 @@ version = "27.0.0" dependencies = [ "bytemuck", "env_logger", + "hashbrown 0.16.0", "log", "raw-window-handle 0.6.2", "ron", @@ -3790,6 +3807,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" @@ -4841,6 +4861,7 @@ dependencies = [ "hashbrown 0.16.0", "indexmap", "log", + "macro_rules_attribute", "naga", "once_cell", "parking_lot", diff --git a/Cargo.toml b/Cargo.toml index d78e742c29e..1629af3c22b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,6 +142,7 @@ libloading = "0.8" libm = { version = "0.2.6", default-features = false } libtest-mimic = "0.8" log = "0.4.21" +macro_rules_attribute = "0.2" nanoserde = "0.2" nanorand = { version = "0.8", default-features = false, features = ["wyrand"] } noise = "0.9" diff --git a/deno_webgpu/device.rs b/deno_webgpu/device.rs index b59fc633cd4..f6c3110d48c 100644 --- a/deno_webgpu/device.rs +++ b/deno_webgpu/device.rs @@ -577,11 +577,8 @@ impl GPUDevice { multiview: None, }; - let res = wgpu_core::command::RenderBundleEncoder::new( - &wgpu_descriptor, - self.id, - None, - ); + let res = + wgpu_core::command::RenderBundleEncoder::new(&wgpu_descriptor, self.id); let (encoder, err) = match res { Ok(encoder) => (encoder, None), Err(e) => ( diff --git a/player/Cargo.toml b/player/Cargo.toml index f29aacf0e94..f09231830c8 100644 --- a/player/Cargo.toml +++ b/player/Cargo.toml @@ -22,6 +22,7 @@ test = false wgpu-types = { workspace = true, features = ["serde", "std"] } env_logger.workspace = true +hashbrown.workspace = true log.workspace = true raw-window-handle.workspace = true ron.workspace = true diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index dfce80b8ad4..cc251e881f6 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -5,14 +5,15 @@ fn main() { extern crate wgpu_core as wgc; extern crate wgpu_types as wgt; - use player::GlobalPlay as _; + use player::Player; use wgc::device::trace; - use wgpu_core::identity::IdentityManager; + use wgpu_core::command::PointerReferences; use std::{ fs, path::{Path, PathBuf}, process::exit, + sync::Arc, }; #[cfg(feature = "winit")] @@ -52,7 +53,7 @@ fn main() { log::info!("Loading trace '{trace:?}'"); let file = fs::File::open(trace).unwrap(); - let mut actions: Vec = ron::de::from_reader(file).unwrap(); + let mut actions: Vec> = ron::de::from_reader(file).unwrap(); actions.reverse(); // allows us to pop from the top log::info!("Found {} actions", actions.len()); @@ -68,17 +69,14 @@ fn main() { .build(&event_loop) .unwrap(); - let global = - wgc::global::Global::new("player", &wgt::InstanceDescriptor::from_env_or_default()); - let mut command_encoder_id_manager = IdentityManager::new(); - let mut command_buffer_id_manager = IdentityManager::new(); + let instance_desc = wgt::InstanceDescriptor::from_env_or_default(); + let instance = wgc::instance::Instance::new("player", &instance_desc); #[cfg(feature = "winit")] let surface = unsafe { - global.instance_create_surface( + instance.create_surface( window.display_handle().unwrap().into(), window.window_handle().unwrap().into(), - Some(wgc::id::Id::zip(0, 1)), ) } .unwrap(); @@ -93,29 +91,29 @@ fn main() { None => (wgt::Backends::all(), wgt::DeviceDescriptor::default()), }; - let adapter = global - .request_adapter( - &wgc::instance::RequestAdapterOptions { - #[cfg(feature = "winit")] - compatible_surface: Some(surface), - #[cfg(not(feature = "winit"))] - compatible_surface: None, - ..Default::default() - }, - backends, - Some(wgc::id::AdapterId::zip(0, 1)), - ) - .expect("Unable to obtain an adapter"); - - let info = global.adapter_get_info(adapter); + let adapter = Arc::new( + instance + .request_adapter( + &wgt::RequestAdapterOptions { + #[cfg(feature = "winit")] + compatible_surface: Some(&surface), + #[cfg(not(feature = "winit"))] + compatible_surface: None, + ..Default::default() + }, + backends, + ) + .expect("Unable to obtain an adapter"), + ); + + let info = adapter.get_info(); log::info!("Using '{}'", info.name); - let device = wgc::id::Id::zip(0, 1); - let queue = wgc::id::Id::zip(0, 1); - let res = global.adapter_request_device(adapter, &device_desc, Some(device), Some(queue)); - if let Err(e) = res { - panic!("{e:?}"); - } + let (device, queue) = adapter + .create_device_and_queue(&device_desc, instance_desc.flags) + .unwrap(); + + let mut player = Player::default(); log::info!("Executing actions"); #[cfg(not(feature = "winit"))] @@ -123,20 +121,13 @@ fn main() { unsafe { global.device_start_graphics_debugger_capture(device) }; while let Some(action) = actions.pop() { - global.process( - device, - queue, - action, - &dir, - &mut command_encoder_id_manager, - &mut command_buffer_id_manager, - ); + player.process(&device, &queue, action, &dir); } unsafe { global.device_stop_graphics_debugger_capture(device) }; - global - .device_poll(device, wgt::PollType::wait_indefinitely()) - .unwrap(); + let (user_closures, result) = device.poll(wgt::PollType::wait_indefinitely()); + user_closures.fire(); + result.unwrap(); } #[cfg(feature = "winit")] { @@ -170,33 +161,25 @@ fn main() { resize_config = Some(config); target.exit(); } else { - let error = - global.surface_configure(surface, device, &config); + let error = device.configure_surface(&surface, &config); if let Some(e) = error { panic!("{e:?}"); } } } - Some(trace::Action::Present(id)) => { + Some(trace::Action::Present(_id)) => { frame_count += 1; log::debug!("Presenting frame {frame_count}"); - global.surface_present(id).unwrap(); + surface.present().unwrap(); target.exit(); } - Some(trace::Action::DiscardSurfaceTexture(id)) => { + Some(trace::Action::DiscardSurfaceTexture(_id)) => { log::debug!("Discarding frame {frame_count}"); - global.surface_texture_discard(id).unwrap(); + surface.discard().unwrap(); target.exit(); } Some(action) => { - global.process( - device, - queue, - action, - &dir, - &mut command_encoder_id_manager, - &mut command_buffer_id_manager, - ); + player.process(&device, &queue, action, &dir); } None => { if !done { @@ -209,7 +192,7 @@ fn main() { } WindowEvent::Resized(_) => { if let Some(config) = resize_config.take() { - let error = global.surface_configure(surface, device, &config); + let error = device.configure_surface(&surface, &config); if let Some(e) = error { panic!("{e:?}"); } @@ -229,9 +212,10 @@ fn main() { }, Event::LoopExiting => { log::info!("Closing"); - global - .device_poll(device, wgt::PollType::wait_indefinitely()) - .unwrap(); + let (user_closures, result) = + device.poll(wgt::PollType::wait_indefinitely()); + user_closures.fire(); + result.unwrap(); } _ => {} } diff --git a/player/src/lib.rs b/player/src/lib.rs index 437f51b14bb..7508bf3d388 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -6,196 +6,98 @@ extern crate wgpu_core as wgc; extern crate wgpu_types as wgt; -use wgc::{command::Command, device::trace, identity::IdentityManager}; +use std::{borrow::Cow, convert::Infallible, fs, path::Path, sync::Arc}; -use std::{borrow::Cow, fs, path::Path}; +use hashbrown::HashMap; -pub trait GlobalPlay { - fn encode_commands( - &self, - encoder: wgc::id::CommandEncoderId, - commands: Vec, - command_buffer_id_manager: &mut IdentityManager, - ) -> wgc::id::CommandBufferId; - fn process( - &self, - device: wgc::id::DeviceId, - queue: wgc::id::QueueId, - action: trace::Action, - dir: &Path, - command_encoder_id_manager: &mut IdentityManager, - command_buffer_id_manager: &mut IdentityManager, - ); +use wgc::{ + binding_model::BindingResource, + command::{ArcCommand, ArcReferences, BasePass, Command, PointerReferences}, + device::trace, + id::PointerId, +}; + +pub struct Player { + pipeline_layouts: HashMap< + wgc::id::PointerId, + Arc, + >, + shader_modules: HashMap< + wgc::id::PointerId, + Arc, + >, + bind_group_layouts: HashMap< + wgc::id::PointerId, + Arc, + >, + bind_groups: HashMap< + wgc::id::PointerId, + Arc, + >, + render_bundles: HashMap< + wgc::id::PointerId, + Arc, + >, + render_pipelines: HashMap< + wgc::id::PointerId, + Arc, + >, + compute_pipelines: HashMap< + wgc::id::PointerId, + Arc, + >, + pipeline_caches: HashMap< + wgc::id::PointerId, + Arc, + >, + query_sets: + HashMap, Arc>, + buffers: HashMap, Arc>, + textures: HashMap, Arc>, + texture_views: + HashMap, Arc>, + external_textures: HashMap< + wgc::id::PointerId, + Arc, + >, + samplers: HashMap, Arc>, + blas_s: HashMap, Arc>, + tlas_s: HashMap, Arc>, } -impl GlobalPlay for wgc::global::Global { - fn encode_commands( - &self, - encoder: wgc::id::CommandEncoderId, - commands: Vec, - command_buffer_id_manager: &mut IdentityManager, - ) -> wgc::id::CommandBufferId { - for command in commands { - match command { - Command::CopyBufferToBuffer { - src, - src_offset, - dst, - dst_offset, - size, - } => self - .command_encoder_copy_buffer_to_buffer( - encoder, src, src_offset, dst, dst_offset, size, - ) - .unwrap(), - Command::CopyBufferToTexture { src, dst, size } => self - .command_encoder_copy_buffer_to_texture(encoder, &src, &dst, &size) - .unwrap(), - Command::CopyTextureToBuffer { src, dst, size } => self - .command_encoder_copy_texture_to_buffer(encoder, &src, &dst, &size) - .unwrap(), - Command::CopyTextureToTexture { src, dst, size } => self - .command_encoder_copy_texture_to_texture(encoder, &src, &dst, &size) - .unwrap(), - Command::ClearBuffer { dst, offset, size } => self - .command_encoder_clear_buffer(encoder, dst, offset, size) - .unwrap(), - Command::ClearTexture { - dst, - subresource_range, - } => self - .command_encoder_clear_texture(encoder, dst, &subresource_range) - .unwrap(), - Command::WriteTimestamp { - query_set_id, - query_index, - } => self - .command_encoder_write_timestamp(encoder, query_set_id, query_index) - .unwrap(), - Command::ResolveQuerySet { - query_set_id, - start_query, - query_count, - destination, - destination_offset, - } => self - .command_encoder_resolve_query_set( - encoder, - query_set_id, - start_query, - query_count, - destination, - destination_offset, - ) - .unwrap(), - Command::PushDebugGroup(marker) => self - .command_encoder_push_debug_group(encoder, &marker) - .unwrap(), - Command::PopDebugGroup => self.command_encoder_pop_debug_group(encoder).unwrap(), - Command::InsertDebugMarker(marker) => self - .command_encoder_insert_debug_marker(encoder, &marker) - .unwrap(), - Command::RunComputePass { - base, - timestamp_writes, - } => { - self.compute_pass_end_with_unresolved_commands( - encoder, - base, - timestamp_writes.as_ref(), - ); - } - Command::RunRenderPass { - base, - target_colors, - target_depth_stencil, - timestamp_writes, - occlusion_query_set_id, - } => { - self.render_pass_end_with_unresolved_commands( - encoder, - base, - &target_colors, - target_depth_stencil.as_ref(), - timestamp_writes.as_ref(), - occlusion_query_set_id, - ); - } - Command::BuildAccelerationStructures { blas, tlas } => { - let blas_iter = blas.iter().map(|x| { - let geometries = match &x.geometries { - wgc::ray_tracing::TraceBlasGeometries::TriangleGeometries( - triangle_geometries, - ) => { - let iter = triangle_geometries.iter().map(|tg| { - wgc::ray_tracing::BlasTriangleGeometry { - size: &tg.size, - 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, - } - }); - wgc::ray_tracing::BlasGeometries::TriangleGeometries(Box::new(iter)) - } - }; - wgc::ray_tracing::BlasBuildEntry { - blas_id: x.blas_id, - geometries, - } - }); - - let tlas_iter = tlas.iter().map(|x| { - let instances = x.instances.iter().map(|instance| { - instance - .as_ref() - .map(|instance| wgc::ray_tracing::TlasInstance { - blas_id: instance.blas_id, - transform: &instance.transform, - custom_data: instance.custom_data, - mask: instance.mask, - }) - }); - wgc::ray_tracing::TlasPackage { - tlas_id: x.tlas_id, - instances: Box::new(instances), - lowest_unmodified: x.lowest_unmodified, - } - }); - - self.command_encoder_build_acceleration_structures( - encoder, blas_iter, tlas_iter, - ) - .unwrap(); - } - } - } - let (cmd_buf, error) = self.command_encoder_finish( - encoder, - &wgt::CommandBufferDescriptor { label: None }, - Some(command_buffer_id_manager.process()), - ); - if let Some(e) = error { - panic!("{e}"); +impl Default for Player { + fn default() -> Self { + Self { + pipeline_layouts: HashMap::new(), + shader_modules: HashMap::new(), + bind_group_layouts: HashMap::new(), + bind_groups: HashMap::new(), + render_bundles: HashMap::new(), + render_pipelines: HashMap::new(), + compute_pipelines: HashMap::new(), + pipeline_caches: HashMap::new(), + query_sets: HashMap::new(), + buffers: HashMap::new(), + textures: HashMap::new(), + texture_views: HashMap::new(), + external_textures: HashMap::new(), + samplers: HashMap::new(), + blas_s: HashMap::new(), + tlas_s: HashMap::new(), } - cmd_buf } +} - fn process( - &self, - device: wgc::id::DeviceId, - queue: wgc::id::QueueId, - action: trace::Action, +impl Player { + pub fn process( + &mut self, + device: &Arc, + queue: &Arc, + action: trace::Action, dir: &Path, - command_encoder_id_manager: &mut IdentityManager, - command_buffer_id_manager: &mut IdentityManager, ) { use wgc::device::trace::Action; log::debug!("action {action:?}"); - //TODO: find a way to force ID perishing without excessive `maintain()` calls. match action { Action::Init { .. } => { panic!("Unexpected Action::Init: has to be the first action only") @@ -206,96 +108,117 @@ impl GlobalPlay for wgc::global::Global { panic!("Unexpected Surface action: winit feature is not enabled") } Action::CreateBuffer(id, desc) => { - let (_, error) = self.device_create_buffer(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let buffer = device.create_buffer(&desc).expect("create_buffer error"); + self.buffers.insert(id, buffer); } Action::FreeBuffer(id) => { - self.buffer_destroy(id); + let buffer = self.buffers.remove(&id).expect("invalid buffer"); + let _ = buffer.unmap(); + buffer.destroy(); } Action::DestroyBuffer(id) => { - self.buffer_drop(id); + let buffer = self.buffers.remove(&id).expect("invalid buffer"); + let _ = buffer.unmap(); } Action::CreateTexture(id, desc) => { - let (_, error) = self.device_create_texture(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let texture = device.create_texture(&desc).expect("create_texture error"); + self.textures.insert(id, texture); } Action::FreeTexture(id) => { - self.texture_destroy(id); + let texture = self.textures.remove(&id).expect("invalid texture"); + texture.destroy(); } Action::DestroyTexture(id) => { - self.texture_drop(id); + self.textures.remove(&id).expect("invalid texture"); } - Action::CreateTextureView { - id, - parent_id, - desc, - } => { - let (_, error) = self.texture_create_view(parent_id, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + Action::CreateTextureView { id, parent, desc } => { + let parent_texture = self.resolve_texture_id(parent); + let texture_view = device + .create_texture_view(&parent_texture, &desc) + .expect("create_texture_view error"); + self.texture_views.insert(id, texture_view); } Action::DestroyTextureView(id) => { - self.texture_view_drop(id).unwrap(); + self.texture_views + .remove(&id) + .expect("invalid texture view"); } Action::CreateExternalTexture { id, desc, planes } => { - let (_, error) = - self.device_create_external_texture(device, &desc, &planes, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let planes = planes + .iter() + .map(|&id| self.resolve_texture_view_id(id)) + .collect::>(); + let external_texture = device + .create_external_texture(&desc, &planes) + .expect("create_external_texture error"); + self.external_textures.insert(id, external_texture); } Action::FreeExternalTexture(id) => { - self.external_texture_destroy(id); + let external_texture = self + .external_textures + .remove(&id) + .expect("invalid external texture"); + external_texture.destroy(); } Action::DestroyExternalTexture(id) => { - self.external_texture_drop(id); + self.external_textures + .remove(&id) + .expect("invalid external texture"); } Action::CreateSampler(id, desc) => { - let (_, error) = self.device_create_sampler(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let sampler = device.create_sampler(&desc).expect("create_sampler error"); + self.samplers.insert(id, sampler); } Action::DestroySampler(id) => { - self.sampler_drop(id); + self.samplers.remove(&id).expect("invalid sampler"); } - Action::GetSurfaceTexture { id, parent_id } => { - self.surface_get_current_texture(parent_id, Some(id)) - .unwrap() - .texture - .unwrap(); + Action::GetSurfaceTexture { .. } => { + unimplemented!() } Action::CreateBindGroupLayout(id, desc) => { - let (_, error) = self.device_create_bind_group_layout(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let bind_group_layout = device + .create_bind_group_layout(&desc) + .expect("create_bind_group_layout error"); + self.bind_group_layouts.insert(id, bind_group_layout); } Action::DestroyBindGroupLayout(id) => { - self.bind_group_layout_drop(id); + self.bind_group_layouts + .remove(&id) + .expect("invalid bind group layout"); } Action::CreatePipelineLayout(id, desc) => { - let (_, error) = self.device_create_pipeline_layout(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let bind_group_layouts: Vec> = desc + .bind_group_layouts + .to_vec() + .into_iter() + .map(|bgl_id| self.resolve_bind_group_layout_id(bgl_id)) + .collect(); + + let resolved_desc = wgc::binding_model::ResolvedPipelineLayoutDescriptor { + label: desc.label.clone(), + bind_group_layouts: Cow::from(&bind_group_layouts), + push_constant_ranges: Cow::Borrowed(&*desc.push_constant_ranges), + }; + + let pipeline_layout = device + .create_pipeline_layout(&resolved_desc) + .expect("create_pipeline_layout error"); + self.pipeline_layouts.insert(id, pipeline_layout); } Action::DestroyPipelineLayout(id) => { - self.pipeline_layout_drop(id); + self.pipeline_layouts + .remove(&id) + .expect("invalid pipeline layout"); } Action::CreateBindGroup(id, desc) => { - let (_, error) = self.device_create_bind_group(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let resolved_desc = self.resolve_bind_group_descriptor(desc); + let bind_group = device + .create_bind_group(resolved_desc) + .expect("create_bind_group error"); + self.bind_groups.insert(id, bind_group); } Action::DestroyBindGroup(id) => { - self.bind_group_drop(id); + let _bind_group = self.bind_groups.remove(&id).expect("invalid bind group"); } Action::CreateShaderModule { id, desc, data } => { log::debug!("Creating shader from {data}"); @@ -308,10 +231,10 @@ impl GlobalPlay for wgc::global::Global { } else { panic!("Unknown shader {data}"); }; - let (_, error) = self.device_create_shader_module(device, &desc, source, Some(id)); - if let Some(e) = error { - println!("shader compilation error:\n---{code}\n---\n{e}"); - } + match device.create_shader_module(&desc, source) { + Ok(module) => self.shader_modules.insert(id, module), + Err(e) => panic!("shader compilation error:\n---{code}\n---\n{e}"), + }; } Action::CreateShaderModulePassthrough { id, @@ -384,69 +307,68 @@ impl GlobalPlay for wgc::global::Global { glsl, wgsl, }; - let (_, error) = unsafe { - self.device_create_shader_module_passthrough(device, &desc, Some(id)) + match unsafe { device.create_shader_module_passthrough(&desc) } { + Ok(module) => self.shader_modules.insert(id, module), + Err(e) => panic!("shader compilation error:\n{e}"), }; - if let Some(e) = error { - println!("shader compilation error: {e}"); - } } Action::DestroyShaderModule(id) => { - self.shader_module_drop(id); + self.shader_modules + .remove(&id) + .expect("invalid shader module"); } Action::CreateComputePipeline { id, desc } => { - let (_, error) = self.device_create_compute_pipeline(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let resolved_desc = self.resolve_compute_pipeline_descriptor(desc); + let pipeline = device + .create_compute_pipeline(resolved_desc) + .expect("create_compute_pipeline error"); + self.compute_pipelines.insert(id, pipeline); } Action::DestroyComputePipeline(id) => { - self.compute_pipeline_drop(id); + self.compute_pipelines + .remove(&id) + .expect("invalid compute pipeline"); } - Action::CreateRenderPipeline { id, desc } => { - let (_, error) = self.device_create_render_pipeline(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } - } - Action::CreateMeshPipeline { id, desc } => { - let (_, error) = self.device_create_mesh_pipeline(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + Action::CreateGeneralRenderPipeline { id, desc } => { + // Note that this is the `General` version of the render + // pipeline descriptor that can represent either a conventional + // pipeline or a mesh shading pipeline. + let resolved_desc = self.resolve_render_pipeline_descriptor(desc); + let pipeline = device + .create_render_pipeline(resolved_desc) + .expect("create_render_pipeline error"); + self.render_pipelines.insert(id, pipeline); } Action::DestroyRenderPipeline(id) => { - self.render_pipeline_drop(id); + self.render_pipelines + .remove(&id) + .expect("invalid render pipeline"); } Action::CreatePipelineCache { id, desc } => { - let _ = unsafe { self.device_create_pipeline_cache(device, &desc, Some(id)) }; + let cache = unsafe { device.create_pipeline_cache(&desc) }.unwrap(); + self.pipeline_caches.insert(id, cache); } Action::DestroyPipelineCache(id) => { - self.pipeline_cache_drop(id); - } - Action::CreateRenderBundle { id, desc, base } => { - let bundle = - wgc::command::RenderBundleEncoder::new(&desc, device, Some(base)).unwrap(); - let (_, error) = self.render_bundle_encoder_finish( - bundle, - &wgt::RenderBundleDescriptor { label: desc.label }, - Some(id), - ); - if let Some(e) = error { - panic!("{e}"); - } + self.pipeline_caches + .remove(&id) + .expect("invalid pipeline cache"); + } + Action::CreateRenderBundle { .. } => { + unimplemented!("traced render bundles are not supported"); } Action::DestroyRenderBundle(id) => { - self.render_bundle_drop(id); + self.render_bundles + .remove(&id) + .expect("invalid render bundle"); } Action::CreateQuerySet { id, desc } => { - let (_, error) = self.device_create_query_set(device, &desc, Some(id)); - if let Some(e) = error { - panic!("{e}"); - } + let query_set = device + .create_query_set(&desc) + .expect("create_query_set error"); + self.query_sets.insert(id, query_set); } Action::DestroyQuerySet(id) => { - self.query_set_drop(id); + self.query_sets.remove(&id).expect("invalid query set"); } Action::WriteBuffer { id, @@ -454,14 +376,17 @@ impl GlobalPlay for wgc::global::Global { range, queued, } => { + let buffer = self.resolve_buffer_id(id); let bin = std::fs::read(dir.join(data)).unwrap(); let size = (range.end - range.start) as usize; if queued { - self.queue_write_buffer(queue, id, range.start, &bin) - .unwrap(); + queue + .write_buffer(buffer, range.start, &bin) + .expect("Queue::write_buffer error"); } else { - self.device_set_buffer_data(id, range.start, &bin[..size]) - .unwrap(); + device + .set_buffer_data(&buffer, range.start, &bin[..size]) + .expect("Device::set_buffer_data error"); } } Action::WriteTexture { @@ -470,37 +395,908 @@ impl GlobalPlay for wgc::global::Global { layout, size, } => { + let to = self.resolve_texel_copy_texture_info(to); let bin = std::fs::read(dir.join(data)).unwrap(); - self.queue_write_texture(queue, &to, &bin, &layout, &size) - .unwrap(); + queue + .write_texture(to, &bin, &layout, &size) + .expect("Queue::write_texture error"); } Action::Submit(_index, ref commands) if commands.is_empty() => { - self.queue_submit(queue, &[]).unwrap(); + queue.submit(&[]).unwrap(); } Action::Submit(_index, commands) => { - let (encoder, error) = self.device_create_command_encoder( - device, - &wgt::CommandEncoderDescriptor { label: None }, - Some(command_encoder_id_manager.process()), - ); - if let Some(e) = error { - panic!("{e}"); - } - let cmdbuf = self.encode_commands(encoder, commands, command_buffer_id_manager); - self.queue_submit(queue, &[cmdbuf]).unwrap(); + let resolved_commands: Vec<_> = commands + .into_iter() + .map(|cmd| self.resolve_command(cmd)) + .collect(); + let buffer = wgc::command::CommandBuffer::from_trace(device, resolved_commands); + queue.submit(&[buffer]).unwrap(); } Action::CreateBlas { id, desc, sizes } => { - self.device_create_blas(device, &desc, sizes, Some(id)); + let blas = device.create_blas(&desc, sizes).expect("create_blas error"); + self.blas_s.insert(id, blas); } Action::DestroyBlas(id) => { - self.blas_drop(id); + self.blas_s.remove(&id).expect("invalid blas"); } Action::CreateTlas { id, desc } => { - self.device_create_tlas(device, &desc, Some(id)); + let tlas = device.create_tlas(&desc).expect("create_tlas error"); + self.tlas_s.insert(id, tlas); } Action::DestroyTlas(id) => { - self.tlas_drop(id); + self.tlas_s.remove(&id).expect("invalid tlas"); + } + } + } + + fn resolve_buffer_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.buffers.get(&id).expect("invalid buffer").clone() + } + + pub fn get_buffer( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.resolve_buffer_id(id) + } + + fn resolve_texture_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.textures.get(&id).expect("invalid texture").clone() + } + + fn resolve_texture_view_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.texture_views + .get(&id) + .expect("invalid texture view") + .clone() + } + + fn resolve_external_texture_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.external_textures + .get(&id) + .expect("invalid external texture") + .clone() + } + + fn resolve_sampler_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.samplers.get(&id).expect("invalid sampler").clone() + } + + fn resolve_bind_group_layout_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.bind_group_layouts + .get(&id) + .expect("invalid bind group layout") + .clone() + } + + fn resolve_bind_group_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.bind_groups + .get(&id) + .expect("invalid bind group") + .clone() + } + + fn resolve_pipeline_layout_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.pipeline_layouts + .get(&id) + .expect("invalid pipeline layout") + .clone() + } + + fn resolve_shader_module_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.shader_modules + .get(&id) + .expect("invalid shader module") + .clone() + } + + fn resolve_render_pipeline_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.render_pipelines + .get(&id) + .expect("invalid render pipeline") + .clone() + } + + fn resolve_compute_pipeline_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.compute_pipelines + .get(&id) + .expect("invalid compute pipeline") + .clone() + } + + fn resolve_pipeline_cache_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.pipeline_caches + .get(&id) + .expect("invalid pipeline cache") + .clone() + } + + fn resolve_render_bundle_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.render_bundles + .get(&id) + .expect("invalid render bundle") + .clone() + } + + fn resolve_query_set_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.query_sets.get(&id).expect("invalid query set").clone() + } + + fn resolve_blas_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.blas_s.get(&id).expect("invalid blas").clone() + } + + fn resolve_tlas_id( + &self, + id: wgc::id::PointerId, + ) -> Arc { + self.tlas_s.get(&id).expect("invalid tlas").clone() + } + + fn resolve_texel_copy_texture_info( + &self, + info: wgt::TexelCopyTextureInfo>, + ) -> wgt::TexelCopyTextureInfo> { + wgt::TexelCopyTextureInfo { + texture: self.resolve_texture_id(info.texture), + mip_level: info.mip_level, + origin: info.origin, + aspect: info.aspect, + } + } + + fn resolve_compute_pipeline_descriptor<'a>( + &self, + desc: wgc::device::trace::TraceComputePipelineDescriptor<'a>, + ) -> wgc::pipeline::ResolvedComputePipelineDescriptor<'a> { + wgc::pipeline::ResolvedComputePipelineDescriptor { + label: desc.label, + layout: desc.layout.map(|id| self.resolve_pipeline_layout_id(id)), + stage: wgc::pipeline::ResolvedProgrammableStageDescriptor { + module: self.resolve_shader_module_id(desc.stage.module), + entry_point: desc.stage.entry_point, + constants: desc.stage.constants, + zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory, + }, + cache: desc.cache.map(|id| self.resolve_pipeline_cache_id(id)), + } + } + + fn resolve_render_pipeline_descriptor<'a>( + &self, + desc: wgc::device::trace::TraceGeneralRenderPipelineDescriptor<'a>, + ) -> wgc::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> { + let layout = desc.layout.map(|id| self.resolve_pipeline_layout_id(id)); + + let vertex = match desc.vertex { + wgc::pipeline::RenderPipelineVertexProcessor::Vertex(vertex_state) => { + wgc::pipeline::RenderPipelineVertexProcessor::Vertex( + wgc::pipeline::ResolvedVertexState { + stage: wgc::pipeline::ResolvedProgrammableStageDescriptor { + module: self.resolve_shader_module_id(vertex_state.stage.module), + entry_point: vertex_state.stage.entry_point, + constants: vertex_state.stage.constants, + zero_initialize_workgroup_memory: vertex_state + .stage + .zero_initialize_workgroup_memory, + }, + buffers: vertex_state.buffers, + }, + ) } + wgc::pipeline::RenderPipelineVertexProcessor::Mesh(task_state, mesh_state) => { + let resolved_task = task_state.map(|task| wgc::pipeline::ResolvedTaskState { + stage: wgc::pipeline::ResolvedProgrammableStageDescriptor { + module: self.resolve_shader_module_id(task.stage.module), + entry_point: task.stage.entry_point, + constants: task.stage.constants, + zero_initialize_workgroup_memory: task + .stage + .zero_initialize_workgroup_memory, + }, + }); + let resolved_mesh = wgc::pipeline::ResolvedMeshState { + stage: wgc::pipeline::ResolvedProgrammableStageDescriptor { + module: self.resolve_shader_module_id(mesh_state.stage.module), + entry_point: mesh_state.stage.entry_point, + constants: mesh_state.stage.constants, + zero_initialize_workgroup_memory: mesh_state + .stage + .zero_initialize_workgroup_memory, + }, + }; + wgc::pipeline::RenderPipelineVertexProcessor::Mesh(resolved_task, resolved_mesh) + } + }; + + let fragment = desc + .fragment + .map(|fragment_state| wgc::pipeline::ResolvedFragmentState { + stage: wgc::pipeline::ResolvedProgrammableStageDescriptor { + module: self.resolve_shader_module_id(fragment_state.stage.module), + entry_point: fragment_state.stage.entry_point, + constants: fragment_state.stage.constants, + zero_initialize_workgroup_memory: fragment_state + .stage + .zero_initialize_workgroup_memory, + }, + targets: fragment_state.targets, + }); + + wgc::pipeline::ResolvedGeneralRenderPipelineDescriptor { + label: desc.label, + layout, + vertex, + primitive: desc.primitive, + depth_stencil: desc.depth_stencil, + multisample: desc.multisample, + fragment, + multiview: desc.multiview, + cache: desc.cache.map(|id| self.resolve_pipeline_cache_id(id)), + } + } + + fn resolve_bind_group_descriptor<'a>( + &self, + desc: wgc::device::trace::TraceBindGroupDescriptor<'a>, + ) -> wgc::binding_model::ResolvedBindGroupDescriptor<'a> { + let layout = self.resolve_bind_group_layout_id(desc.layout); + + let entries: Vec = desc + .entries + .to_vec() + .into_iter() + .map(|entry| { + let resource = match entry.resource { + BindingResource::Buffer(buffer_binding) => { + let buffer = self.resolve_buffer_id(buffer_binding.buffer); + wgc::binding_model::ResolvedBindingResource::Buffer( + wgc::binding_model::ResolvedBufferBinding { + buffer, + offset: buffer_binding.offset, + size: buffer_binding.size, + }, + ) + } + BindingResource::BufferArray(buffer_bindings) => { + let resolved_buffers: Vec<_> = buffer_bindings + .to_vec() + .into_iter() + .map(|bb| { + let buffer = self.resolve_buffer_id(bb.buffer); + wgc::binding_model::ResolvedBufferBinding { + buffer, + offset: bb.offset, + size: bb.size, + } + }) + .collect(); + wgc::binding_model::ResolvedBindingResource::BufferArray(Cow::Owned( + resolved_buffers, + )) + } + BindingResource::Sampler(sampler_id) => { + let sampler = self.resolve_sampler_id(sampler_id); + wgc::binding_model::ResolvedBindingResource::Sampler(sampler) + } + BindingResource::SamplerArray(sampler_ids) => { + let resolved_samplers: Vec<_> = sampler_ids + .to_vec() + .into_iter() + .map(|id| self.resolve_sampler_id(id)) + .collect(); + wgc::binding_model::ResolvedBindingResource::SamplerArray(Cow::Owned( + resolved_samplers, + )) + } + BindingResource::TextureView(texture_view_id) => { + let texture_view = self.resolve_texture_view_id(texture_view_id); + wgc::binding_model::ResolvedBindingResource::TextureView(texture_view) + } + BindingResource::TextureViewArray(texture_view_ids) => { + let resolved_views: Vec<_> = texture_view_ids + .to_vec() + .into_iter() + .map(|id| self.resolve_texture_view_id(id)) + .collect(); + wgc::binding_model::ResolvedBindingResource::TextureViewArray(Cow::Owned( + resolved_views, + )) + } + BindingResource::AccelerationStructure(tlas_id) => { + let tlas = self.resolve_tlas_id(tlas_id); + wgc::binding_model::ResolvedBindingResource::AccelerationStructure(tlas) + } + BindingResource::ExternalTexture(external_texture_id) => { + let external_texture = + self.resolve_external_texture_id(external_texture_id); + wgc::binding_model::ResolvedBindingResource::ExternalTexture( + external_texture, + ) + } + }; + + wgc::binding_model::ResolvedBindGroupEntry { + binding: entry.binding, + resource, + } + }) + .collect(); + + wgc::binding_model::ResolvedBindGroupDescriptor { + label: desc.label.clone(), + layout, + entries: entries.into(), + } + } + + fn resolve_command(&self, command: Command) -> ArcCommand { + match command { + Command::CopyBufferToBuffer { + src, + src_offset, + dst, + dst_offset, + size, + } => Command::CopyBufferToBuffer { + src: self.resolve_buffer_id(src), + src_offset, + dst: self.resolve_buffer_id(dst), + dst_offset, + size, + }, + Command::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture { + src: self.resolve_texel_copy_buffer_info(src), + dst: self.resolve_texel_copy_texture_info(dst), + size, + }, + Command::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer { + src: self.resolve_texel_copy_texture_info(src), + dst: self.resolve_texel_copy_buffer_info(dst), + size, + }, + Command::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture { + src: self.resolve_texel_copy_texture_info(src), + dst: self.resolve_texel_copy_texture_info(dst), + size, + }, + Command::ClearBuffer { dst, offset, size } => Command::ClearBuffer { + dst: self.resolve_buffer_id(dst), + offset, + size, + }, + Command::ClearTexture { + dst, + subresource_range, + } => Command::ClearTexture { + dst: self.resolve_texture_id(dst), + subresource_range, + }, + Command::WriteTimestamp { + query_set, + query_index, + } => Command::WriteTimestamp { + query_set: self.resolve_query_set_id(query_set), + query_index, + }, + Command::ResolveQuerySet { + query_set, + start_query, + query_count, + destination, + destination_offset, + } => Command::ResolveQuerySet { + query_set: self.resolve_query_set_id(query_set), + start_query, + query_count, + destination: self.resolve_buffer_id(destination), + destination_offset, + }, + Command::PushDebugGroup(label) => Command::PushDebugGroup(label.clone()), + Command::PopDebugGroup => Command::PopDebugGroup, + Command::InsertDebugMarker(label) => Command::InsertDebugMarker(label.clone()), + Command::RunComputePass { + pass, + timestamp_writes, + } => Command::RunComputePass { + pass: self.resolve_compute_pass(pass), + timestamp_writes: timestamp_writes.map(|tw| self.resolve_pass_timestamp_writes(tw)), + }, + Command::RunRenderPass { + pass, + color_attachments, + depth_stencil_attachment, + timestamp_writes, + occlusion_query_set, + } => Command::RunRenderPass { + pass: self.resolve_render_pass(pass), + color_attachments: self.resolve_color_attachments(color_attachments), + depth_stencil_attachment: depth_stencil_attachment + .map(|att| self.resolve_depth_stencil_attachment(att)), + timestamp_writes: timestamp_writes.map(|tw| self.resolve_pass_timestamp_writes(tw)), + occlusion_query_set: occlusion_query_set.map(|qs| self.resolve_query_set_id(qs)), + }, + Command::BuildAccelerationStructures { blas, tlas } => { + Command::BuildAccelerationStructures { + blas: blas + .into_iter() + .map(|entry| self.resolve_blas_build_entry(entry)) + .collect(), + tlas: tlas + .into_iter() + .map(|package| self.resolve_tlas_package(package)) + .collect(), + } + } + Command::TransitionResources { + buffer_transitions, + texture_transitions, + } => Command::TransitionResources { + buffer_transitions: buffer_transitions + .into_iter() + .map(|trans| self.resolve_buffer_transition(trans)) + .collect(), + texture_transitions: texture_transitions + .into_iter() + .map(|trans| self.resolve_texture_transition(trans)) + .collect(), + }, + } + } + + // Helper methods for command resolution + fn resolve_texel_copy_buffer_info( + &self, + info: wgt::TexelCopyBufferInfo>, + ) -> wgt::TexelCopyBufferInfo> { + wgt::TexelCopyBufferInfo { + buffer: self + .buffers + .get(&info.buffer) + .cloned() + .expect("invalid buffer"), + layout: info.layout, + } + } + + fn resolve_compute_pass( + &self, + pass: BasePass, Infallible>, + ) -> BasePass, Infallible> { + let BasePass { + label, + error, + commands, + dynamic_offsets, + push_constant_data, + string_data, + } = pass; + + BasePass { + label, + error, + commands: commands + .into_iter() + .map(|cmd| self.resolve_compute_command(cmd)) + .collect(), + dynamic_offsets, + push_constant_data, + string_data, + } + } + + fn resolve_render_pass( + &self, + pass: BasePass, Infallible>, + ) -> BasePass, Infallible> { + let BasePass { + label, + error, + commands, + dynamic_offsets, + push_constant_data, + string_data, + } = pass; + + BasePass { + label, + error, + commands: commands + .into_iter() + .map(|cmd| self.resolve_render_command(cmd)) + .collect(), + dynamic_offsets, + push_constant_data, + string_data, + } + } + + fn resolve_compute_command( + &self, + command: wgc::command::ComputeCommand, + ) -> wgc::command::ComputeCommand { + use wgc::command::ComputeCommand as C; + match command { + C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group, + } => C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: bind_group.map(|bg| self.resolve_bind_group_id(bg)), + }, + C::SetPipeline(id) => C::SetPipeline(self.resolve_compute_pipeline_id(id)), + 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: self.resolve_buffer_id(buffer), + 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: self.resolve_query_set_id(query_set), + query_index, + }, + C::BeginPipelineStatisticsQuery { + query_set, + query_index, + } => C::BeginPipelineStatisticsQuery { + query_set: self.resolve_query_set_id(query_set), + query_index, + }, + C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery, + } + } + + fn resolve_render_command( + &self, + command: wgc::command::RenderCommand, + ) -> wgc::command::RenderCommand { + use wgc::command::RenderCommand as C; + match command { + C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group, + } => C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: bind_group.map(|bg| self.resolve_bind_group_id(bg)), + }, + C::SetPipeline(id) => C::SetPipeline(self.resolve_render_pipeline_id(id)), + C::SetIndexBuffer { + buffer, + index_format, + offset, + size, + } => C::SetIndexBuffer { + buffer: self.resolve_buffer_id(buffer), + index_format, + offset, + size, + }, + C::SetVertexBuffer { + slot, + buffer, + offset, + size, + } => C::SetVertexBuffer { + slot, + buffer: self.resolve_buffer_id(buffer), + 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: self.resolve_buffer_id(buffer), + offset, + count, + family, + vertex_or_index_limit, + instance_limit, + }, + C::MultiDrawIndirectCount { + buffer, + offset, + count_buffer, + count_buffer_offset, + max_count, + family, + } => C::MultiDrawIndirectCount { + buffer: self.resolve_buffer_id(buffer), + offset, + count_buffer: self.resolve_buffer_id(count_buffer), + 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: self.resolve_query_set_id(query_set), + query_index, + }, + C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index }, + C::EndOcclusionQuery => C::EndOcclusionQuery, + C::BeginPipelineStatisticsQuery { + query_set, + query_index, + } => C::BeginPipelineStatisticsQuery { + query_set: self.resolve_query_set_id(query_set), + query_index, + }, + C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery, + C::ExecuteBundle(bundle) => C::ExecuteBundle(self.resolve_render_bundle_id(bundle)), + } + } + + fn resolve_pass_timestamp_writes( + &self, + writes: wgc::command::PassTimestampWrites>, + ) -> wgc::command::PassTimestampWrites> { + wgc::command::PassTimestampWrites { + query_set: self.resolve_query_set_id(writes.query_set), + beginning_of_pass_write_index: writes.beginning_of_pass_write_index, + end_of_pass_write_index: writes.end_of_pass_write_index, + } + } + + fn resolve_color_attachments( + &self, + attachments: wgc::command::ColorAttachments>, + ) -> wgc::command::ColorAttachments> { + attachments + .into_iter() + .map(|opt| { + opt.map(|att| wgc::command::RenderPassColorAttachment { + view: self.resolve_texture_view_id(att.view), + depth_slice: att.depth_slice, + resolve_target: att + .resolve_target + .map(|rt| self.resolve_texture_view_id(rt)), + load_op: att.load_op, + store_op: att.store_op, + }) + }) + .collect() + } + + fn resolve_depth_stencil_attachment( + &self, + attachment: wgc::command::ResolvedRenderPassDepthStencilAttachment< + PointerId, + >, + ) -> wgc::command::ResolvedRenderPassDepthStencilAttachment> + { + wgc::command::ResolvedRenderPassDepthStencilAttachment { + view: self.resolve_texture_view_id(attachment.view), + depth: attachment.depth, + stencil: attachment.stencil, + } + } + + fn resolve_blas_build_entry( + &self, + entry: wgc::ray_tracing::OwnedBlasBuildEntry, + ) -> wgc::ray_tracing::OwnedBlasBuildEntry { + wgc::ray_tracing::OwnedBlasBuildEntry { + blas: self.resolve_blas_id(entry.blas), + geometries: self.resolve_blas_geometries(entry.geometries), + } + } + + fn resolve_tlas_package( + &self, + package: wgc::ray_tracing::OwnedTlasPackage, + ) -> wgc::ray_tracing::OwnedTlasPackage { + wgc::ray_tracing::OwnedTlasPackage { + tlas: self.resolve_tlas_id(package.tlas), + instances: package + .instances + .into_iter() + .map(|opt| opt.map(|inst| self.resolve_tlas_instance(inst))) + .collect(), + lowest_unmodified: package.lowest_unmodified, + } + } + + // Helper functions for ray tracing structures + fn resolve_blas_geometries( + &self, + geometries: wgc::ray_tracing::OwnedBlasGeometries, + ) -> wgc::ray_tracing::OwnedBlasGeometries { + match geometries { + wgc::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => { + wgc::ray_tracing::OwnedBlasGeometries::TriangleGeometries( + geos.into_iter() + .map(|geo| self.resolve_blas_triangle_geometry(geo)) + .collect(), + ) + } + } + } + + fn resolve_blas_triangle_geometry( + &self, + geometry: wgc::ray_tracing::OwnedBlasTriangleGeometry, + ) -> wgc::ray_tracing::OwnedBlasTriangleGeometry { + wgc::ray_tracing::OwnedBlasTriangleGeometry { + size: geometry.size, + vertex_buffer: self.resolve_buffer_id(geometry.vertex_buffer), + index_buffer: geometry.index_buffer.map(|buf| self.resolve_buffer_id(buf)), + transform_buffer: geometry + .transform_buffer + .map(|buf| self.resolve_buffer_id(buf)), + first_vertex: geometry.first_vertex, + vertex_stride: geometry.vertex_stride, + first_index: geometry.first_index, + transform_buffer_offset: geometry.transform_buffer_offset, + } + } + + fn resolve_tlas_instance( + &self, + instance: wgc::ray_tracing::OwnedTlasInstance, + ) -> wgc::ray_tracing::OwnedTlasInstance { + wgc::ray_tracing::OwnedTlasInstance { + blas: self.resolve_blas_id(instance.blas), + transform: instance.transform, + custom_data: instance.custom_data, + mask: instance.mask, + } + } + + fn resolve_buffer_transition( + &self, + trans: wgt::BufferTransition>, + ) -> wgt::BufferTransition> { + wgt::BufferTransition { + buffer: self + .buffers + .get(&trans.buffer) + .cloned() + .expect("invalid buffer"), + state: trans.state, + } + } + + fn resolve_texture_transition( + &self, + trans: wgt::TextureTransition>, + ) -> wgt::TextureTransition> { + wgt::TextureTransition { + texture: self + .textures + .get(&trans.texture) + .cloned() + .expect("invalid texture"), + selector: trans.selector.clone(), + state: trans.state, } } } diff --git a/player/tests/player/data/bind-group.ron b/player/tests/player/data/bind-group.ron index 5b3a256d37a..5a20aabfce8 100644 --- a/player/tests/player/data/bind-group.ron +++ b/player/tests/player/data/bind-group.ron @@ -2,13 +2,13 @@ features: "", expectations: [], //not crash! actions: [ - CreateBuffer(Id(0, 1), ( + CreateBuffer(PointerId(0x10), ( label: None, size: 16, usage: "UNIFORM", mapped_at_creation: false, )), - CreateBindGroupLayout(Id(0, 1), ( + CreateBindGroupLayout(PointerId(0x10), ( label: None, entries: [ ( @@ -20,29 +20,29 @@ ), ], )), - CreateBindGroup(Id(0, 1), ( + CreateBindGroup(PointerId(0x10), ( label: None, - layout: Id(0, 1), + layout: PointerId(0x10), entries: [ ( binding: 0, resource: Buffer(( - buffer: Id(0, 1), + buffer: PointerId(0x10), offset: 0, size: None, )), ) ], )), - CreatePipelineLayout(Id(0, 1), ( + CreatePipelineLayout(PointerId(0x10), ( label: Some("empty"), bind_group_layouts: [ - Id(0, 1), + PointerId(0x10), ], push_constant_ranges: [], )), CreateShaderModule( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, flags: (bits: 3), @@ -50,12 +50,12 @@ data: "empty.wgsl", ), CreateComputePipeline( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, - layout: Some(Id(0, 1)), + layout: Some(PointerId(0x10)), stage: ( - module: Id(0, 1), + module: PointerId(0x10), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -65,14 +65,14 @@ ), Submit(1, [ RunComputePass( - base: ( + pass: ( commands: [ SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Some(Id(0, 1)), + bind_group: Some(PointerId(0x10)), ), - SetPipeline(Id(0, 1)), + SetPipeline(PointerId(0x10)), ], dynamic_offsets: [], string_data: [], diff --git a/player/tests/player/data/buffer-copy.ron b/player/tests/player/data/buffer-copy.ron index 10a1822bd7a..93b868c90e8 100644 --- a/player/tests/player/data/buffer-copy.ron +++ b/player/tests/player/data/buffer-copy.ron @@ -3,14 +3,14 @@ expectations: [ ( name: "basic", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: Raw([0x00, 0x00, 0x80, 0xBF]), ) ], actions: [ CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("dummy"), size: 16, @@ -19,7 +19,7 @@ ), ), WriteBuffer( - id: Id(0, 1), + id: PointerId(0x10), data: "data1.bin", range: ( start: 0, diff --git a/player/tests/player/data/clear-buffer-texture.ron b/player/tests/player/data/clear-buffer-texture.ron index f6c929252c9..489e1d6639e 100644 --- a/player/tests/player/data/clear-buffer-texture.ron +++ b/player/tests/player/data/clear-buffer-texture.ron @@ -3,13 +3,13 @@ expectations: [ ( name: "Quad", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: File("clear-texture.bin", 16384), ), ( name: "buffer clear", - buffer: (index: 1, epoch: 1), + buffer: PointerId(0x110), offset: 0, data: Raw([ 0x00, 0x00, 0x80, 0xBF, @@ -20,7 +20,7 @@ ) ], actions: [ - CreateTexture(Id(0, 1), ( + CreateTexture(PointerId(0x10), ( label: Some("Output Texture"), size: ( width: 64, @@ -36,7 +36,7 @@ // First fill the texture to ensure it wasn't just zero initialized or "happened" to be zero. WriteTexture( to: ( - texture: Id(0, 1), + texture: PointerId(0x10), mip_level: 0, array_layer: 0, ), @@ -52,7 +52,7 @@ ), ), CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("Output Buffer"), size: 16384, @@ -62,7 +62,7 @@ ), CreateBuffer( - Id(1, 1), + PointerId(0x110), ( label: Some("Buffer to be cleared"), size: 16, @@ -72,7 +72,7 @@ ), // Make sure there is something in the buffer, otherwise it might be just zero init! WriteBuffer( - id: Id(1, 1), + id: PointerId(0x110), data: "data1.bin", range: ( start: 0, @@ -82,7 +82,7 @@ ), Submit(1, [ ClearTexture( - dst: Id(0, 1), + dst: PointerId(0x10), subresource_range: ImageSubresourceRange( aspect: all, baseMipLevel: 0, @@ -93,12 +93,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(0, 1), + texture: PointerId(0x10), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1), + buffer: PointerId(0x10), layout: ( offset: 0, bytes_per_row: Some(256), @@ -112,7 +112,7 @@ ), // Partial clear to prove ClearBuffer( - dst: Id(1, 1), + dst: PointerId(0x110), offset: 4, size: Some(8), ) diff --git a/player/tests/player/data/pipeline-statistics-query.ron b/player/tests/player/data/pipeline-statistics-query.ron index 95acc414c87..2d1c208845e 100644 --- a/player/tests/player/data/pipeline-statistics-query.ron +++ b/player/tests/player/data/pipeline-statistics-query.ron @@ -3,19 +3,19 @@ expectations: [ ( name: "Queried number of compute invocations is correct", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: U64([0x0, 0x2A]), ), ], actions: [ - CreatePipelineLayout(Id(0, 1), ( + CreatePipelineLayout(PointerId(0x10), ( label: Some("empty"), bind_group_layouts: [], push_constant_ranges: [], )), CreateShaderModule( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, flags: (bits: 3), @@ -23,12 +23,12 @@ data: "empty.wgsl", ), CreateComputePipeline( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, - layout: Some(Id(0, 1)), + layout: Some(PointerId(0x10)), stage: ( - module: Id(0, 1), + module: PointerId(0x10), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -37,7 +37,7 @@ ), ), CreateQuerySet( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: Some("Compute Invocation QuerySet"), count: 2, @@ -45,7 +45,7 @@ ), ), CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("Compute Invocation Result Buffer"), size: 16, @@ -55,11 +55,11 @@ ), Submit(1, [ RunComputePass( - base: ( + pass: ( commands: [ - SetPipeline(Id(0, 1)), + SetPipeline(PointerId(0x10)), BeginPipelineStatisticsQuery( - query_set_id: Id(0, 1), + query_set: PointerId(0x10), query_index: 0, ), Dispatch((2, 3, 7,)), @@ -71,10 +71,10 @@ ), ), ResolveQuerySet( - query_set_id: Id(0, 1), + query_set: PointerId(0x10), start_query: 0, query_count: 1, - destination: Id(0, 1), + destination: PointerId(0x10), destination_offset: 0, ) ]), diff --git a/player/tests/player/data/quad.ron b/player/tests/player/data/quad.ron index 7bb56a6be0f..7ef16eead4f 100644 --- a/player/tests/player/data/quad.ron +++ b/player/tests/player/data/quad.ron @@ -3,21 +3,21 @@ expectations: [ ( name: "Quad", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: File("quad.bin", 16384), ) ], actions: [ CreateShaderModule( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, flags: (bits: 3), ), data: "quad.wgsl", ), - CreateTexture(Id(0, 1), ( + CreateTexture(PointerId(0x10), ( label: Some("Output Texture"), size: ( width: 64, @@ -31,12 +31,12 @@ view_formats: [], )), CreateTextureView( - id: Id(0, 1), - parent_id: Id(0, 1), + id: PointerId(0x10), + parent: PointerId(0x10), desc: (), ), CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("Output Buffer"), size: 16384, @@ -44,29 +44,31 @@ mapped_at_creation: false, ), ), - CreatePipelineLayout(Id(0, 1), ( + CreatePipelineLayout(PointerId(0x10), ( label: None, bind_group_layouts: [], push_constant_ranges: [], )), - CreateRenderPipeline( - id: Id(0, 1), + CreateGeneralRenderPipeline( + id: PointerId(0x10), desc: ( label: None, - layout: Some(Id(0, 1)), - vertex: ( - stage: ( - module: Id(0, 1), - entry_point: None, - constants: {}, - zero_initialize_workgroup_memory: true, - vertex_pulling_transform: false, + layout: Some(PointerId(0x10)), + vertex: Vertex( + VertexState( + stage: ( + module: PointerId(0x10), + entry_point: None, + constants: {}, + zero_initialize_workgroup_memory: true, + vertex_pulling_transform: false, + ), + buffers: [], ), - buffers: [], ), fragment: Some(( stage: ( - module: Id(0, 1), + module: PointerId(0x10), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -82,9 +84,9 @@ ), Submit(1, [ RunRenderPass( - base: ( + pass: ( commands: [ - SetPipeline(Id(0, 1)), + SetPipeline(PointerId(0x10)), Draw( vertex_count: 3, instance_count: 1, @@ -96,9 +98,9 @@ string_data: [], push_constant_data: [], ), - target_colors: [ + color_attachments: [ Some(( - view: Id(0, 1), + view: PointerId(0x10), resolve_target: None, load_op: clear(Color( r: 0, @@ -109,16 +111,16 @@ store_op: store, )), ], - target_depth_stencil: None, + depth_stencil_attachment: None, ), CopyTextureToBuffer( src: ( - texture: Id(0, 1), + texture: PointerId(0x10), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1), + buffer: PointerId(0x10), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/player/data/zero-init-buffer.ron b/player/tests/player/data/zero-init-buffer.ron index 143f91f51f8..6e153aa616b 100644 --- a/player/tests/player/data/zero-init-buffer.ron +++ b/player/tests/player/data/zero-init-buffer.ron @@ -4,19 +4,19 @@ // Ensuring that mapping zero-inits buffers. ( name: "mapped_at_creation: false, with MAP_WRITE", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: Raw([0x00, 0x00, 0x00, 0x00]), ), ( name: "mapped_at_creation: false, without MAP_WRITE", - buffer: (index: 1, epoch: 1), + buffer: PointerId(0x110), offset: 0, data: Raw([0x00, 0x00, 0x00, 0x00]), ), ( name: "partially written buffer", - buffer: (index: 2, epoch: 1), + buffer: PointerId(0x120), offset: 0, data: Raw([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBF, @@ -29,7 +29,7 @@ // (by observing correct side effects of compute shader reading & writing values) ( name: "buffer has correct values", - buffer: (index: 3, epoch: 1), + buffer: PointerId(0x130), offset: 0, data: Raw([0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -39,7 +39,7 @@ ], actions: [ CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("mapped_at_creation: false, with MAP_WRITE"), size: 16, @@ -48,7 +48,7 @@ ), ), CreateBuffer( - Id(1, 1), + PointerId(0x110), ( label: Some("mapped_at_creation: false, without MAP_WRITE"), size: 16, @@ -57,7 +57,7 @@ ), ), CreateBuffer( - Id(2, 1), + PointerId(0x120), ( label: Some("partially written"), size: 24, @@ -66,7 +66,7 @@ ), ), WriteBuffer( - id: Id(2, 1), + id: PointerId(0x120), data: "data1.bin", range: ( start: 4, @@ -75,20 +75,20 @@ queued: true, ), CreateShaderModule( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, flags: (bits: 3), ), data: "zero-init-buffer-for-binding.wgsl", ), - CreateBuffer(Id(3, 1), ( + CreateBuffer(PointerId(0x130), ( label: Some("used in binding"), size: 16, usage: "STORAGE | MAP_READ", mapped_at_creation: false, )), - CreateBindGroupLayout(Id(0, 1), ( + CreateBindGroupLayout(PointerId(0x10), ( label: None, entries: [ ( @@ -105,34 +105,34 @@ ), ], )), - CreateBindGroup(Id(0, 1), ( + CreateBindGroup(PointerId(0x10), ( label: None, - layout: Id(0, 1), + layout: PointerId(0x10), entries: [ ( binding: 0, resource: Buffer(( - buffer: Id(3, 1), + buffer: PointerId(0x130), offset: 0, size: Some(16), )), ), ], )), - CreatePipelineLayout(Id(0, 1), ( + CreatePipelineLayout(PointerId(0x10), ( label: None, bind_group_layouts: [ - Id(0, 1), + PointerId(0x10), ], push_constant_ranges: [], )), CreateComputePipeline( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, - layout: Some(Id(0, 1)), + layout: Some(PointerId(0x10)), stage: ( - module: Id(0, 1), + module: PointerId(0x10), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -142,14 +142,14 @@ ), Submit(1, [ RunComputePass( - base: ( + pass: ( label: None, commands: [ - SetPipeline(Id(0, 1)), + SetPipeline(PointerId(0x10)), SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Some(Id(0, 1)), + bind_group: Some(PointerId(0x10)), ), Dispatch((4, 1, 1)), ], diff --git a/player/tests/player/data/zero-init-texture-binding.ron b/player/tests/player/data/zero-init-texture-binding.ron index 8920c41b7a5..a8d5bbc18fe 100644 --- a/player/tests/player/data/zero-init-texture-binding.ron +++ b/player/tests/player/data/zero-init-texture-binding.ron @@ -3,13 +3,13 @@ expectations: [ ( name: "Sampled Texture", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: File("zero-16k.bin", 16384), ), ( name: "Storage Texture", - buffer: (index: 1, epoch: 1), + buffer: PointerId(0x110), offset: 0, data: File("zero-16k.bin", 16384), ), @@ -17,7 +17,7 @@ // MISSING: Partial views ], actions: [ - CreateTexture(Id(0, 1), ( + CreateTexture(PointerId(0x10), ( label: Some("Sampled Texture"), size: ( width: 64, @@ -31,12 +31,12 @@ view_formats: [], )), CreateTextureView( - id: Id(0, 1), - parent_id: Id(0, 1), + id: PointerId(0x10), + parent: PointerId(0x10), desc: (), ), CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("Sampled Texture Buffer"), size: 16384, @@ -44,7 +44,7 @@ mapped_at_creation: false, ), ), - CreateTexture(Id(1, 1), ( + CreateTexture(PointerId(0x110), ( label: Some("Storage Texture"), size: ( width: 64, @@ -58,12 +58,12 @@ view_formats: [], )), CreateTextureView( - id: Id(1, 1), - parent_id: Id(1, 1), + id: PointerId(0x110), + parent: PointerId(0x110), desc: (), ), CreateBuffer( - Id(1, 1), + PointerId(0x110), ( label: Some("Storage Texture Buffer"), size: 16384, @@ -73,7 +73,7 @@ ), - CreateBindGroupLayout(Id(0, 1), ( + CreateBindGroupLayout(PointerId(0x10), ( label: None, entries: [ ( @@ -98,29 +98,29 @@ ), ], )), - CreateBindGroup(Id(0, 1), ( + CreateBindGroup(PointerId(0x10), ( label: None, - layout: Id(0, 1), + layout: PointerId(0x10), entries: [ ( binding: 0, - resource: TextureView(Id(0, 1)), + resource: TextureView(PointerId(0x10)), ), ( binding: 1, - resource: TextureView(Id(1, 1)), + resource: TextureView(PointerId(0x110)), ), ], )), - CreatePipelineLayout(Id(0, 1), ( + CreatePipelineLayout(PointerId(0x10), ( label: None, bind_group_layouts: [ - Id(0, 1), + PointerId(0x10), ], push_constant_ranges: [], )), CreateShaderModule( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, flags: (bits: 3), @@ -128,12 +128,12 @@ data: "zero-init-texture-binding.wgsl", ), CreateComputePipeline( - id: Id(0, 1), + id: PointerId(0x10), desc: ( label: None, - layout: Some(Id(0, 1)), + layout: Some(PointerId(0x10)), stage: ( - module: Id(0, 1), + module: PointerId(0x10), entry_point: None, constants: {}, zero_initialize_workgroup_memory: true, @@ -144,13 +144,13 @@ Submit(1, [ RunComputePass( - base: ( + pass: ( commands: [ - SetPipeline(Id(0, 1)), + SetPipeline(PointerId(0x10)), SetBindGroup( index: 0, num_dynamic_offsets: 0, - bind_group_id: Some(Id(0, 1)), + bind_group: Some(PointerId(0x10)), ), Dispatch((4, 1, 1)), ], @@ -161,12 +161,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(0, 1), + texture: PointerId(0x10), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1), + buffer: PointerId(0x10), layout: ( offset: 0, bytes_per_row: Some(256), @@ -180,12 +180,12 @@ ), CopyTextureToBuffer( src: ( - texture: Id(1, 1), + texture: PointerId(0x110), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(1, 1), + buffer: PointerId(0x110), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/player/data/zero-init-texture-copytobuffer.ron b/player/tests/player/data/zero-init-texture-copytobuffer.ron index 2346e8b4099..c547af92f65 100644 --- a/player/tests/player/data/zero-init-texture-copytobuffer.ron +++ b/player/tests/player/data/zero-init-texture-copytobuffer.ron @@ -3,14 +3,14 @@ expectations: [ ( name: "Copy to Buffer", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: File("zero-16k.bin", 16384), ), // MISSING: Partial copies ], actions: [ - CreateTexture(Id(0, 1), ( + CreateTexture(PointerId(0x10), ( label: Some("Copy To Buffer Texture"), size: ( width: 64, @@ -24,7 +24,7 @@ view_formats: [], )), CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("Copy to Buffer Buffer"), size: 16384, @@ -35,12 +35,12 @@ Submit(1, [ CopyTextureToBuffer( src: ( - texture: Id(0, 1), + texture: PointerId(0x10), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1), + buffer: PointerId(0x10), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/player/data/zero-init-texture-rendertarget.ron b/player/tests/player/data/zero-init-texture-rendertarget.ron index 7f06de9b4e8..49923f64ac5 100644 --- a/player/tests/player/data/zero-init-texture-rendertarget.ron +++ b/player/tests/player/data/zero-init-texture-rendertarget.ron @@ -3,14 +3,14 @@ expectations: [ ( name: "Render Target", - buffer: (index: 0, epoch: 1), + buffer: PointerId(0x10), offset: 0, data: File("zero-16k.bin", 16384), ), // MISSING: Partial view. ], actions: [ - CreateTexture(Id(0, 1), ( + CreateTexture(PointerId(0x10), ( label: Some("Render Target Texture"), size: ( width: 64, @@ -24,12 +24,12 @@ view_formats: [], )), CreateTextureView( - id: Id(0, 1), - parent_id: Id(0, 1), + id: PointerId(0x10), + parent: PointerId(0x10), desc: (), ), CreateBuffer( - Id(0, 1), + PointerId(0x10), ( label: Some("Render Target Buffer"), size: 16384, @@ -40,15 +40,15 @@ Submit(1, [ RunRenderPass( - base: ( + pass: ( commands: [], dynamic_offsets: [], string_data: [], push_constant_data: [], ), - target_colors: [ + color_attachments: [ Some(( - view: Id(0, 1), + view: PointerId(0x10), resolve_target: None, load_op: load, store_op: store, @@ -57,16 +57,16 @@ ), )), ], - target_depth_stencil: None, + depth_stencil_attachment: None, ), CopyTextureToBuffer( src: ( - texture: Id(0, 1), + texture: PointerId(0x10), mip_level: 0, array_layer: 0, ), dst: ( - buffer: Id(0, 1), + buffer: PointerId(0x10), layout: ( offset: 0, bytes_per_row: Some(256), diff --git a/player/tests/player/main.rs b/player/tests/player/main.rs index 700a6739048..e29f01f67bd 100644 --- a/player/tests/player/main.rs +++ b/player/tests/player/main.rs @@ -13,20 +13,15 @@ extern crate wgpu_core as wgc; extern crate wgpu_types as wgt; -use player::GlobalPlay; +use player::Player; use std::{ fs::{read_to_string, File}, io::{Read, Seek, SeekFrom}, path::{Path, PathBuf}, slice, + sync::Arc, }; -use wgc::identity::IdentityManager; - -#[derive(serde::Deserialize)] -struct RawId { - index: u32, - epoch: u32, -} +use wgc::command::PointerReferences; #[derive(serde::Deserialize)] enum ExpectedData { @@ -48,7 +43,7 @@ impl ExpectedData { #[derive(serde::Deserialize)] struct Expectation { name: String, - buffer: RawId, + buffer: wgc::id::PointerId, offset: wgt::BufferAddress, data: ExpectedData, } @@ -57,7 +52,7 @@ struct Expectation { struct Test<'a> { features: wgt::Features, expectations: Vec, - actions: Vec>, + actions: Vec>, } fn map_callback(status: Result<(), wgc::resource::BufferAccessError>) { @@ -82,48 +77,34 @@ impl Test<'_> { fn run( self, dir: &Path, - global: &wgc::global::Global, - adapter: wgc::id::AdapterId, - test_num: u32, + instance_desc: &wgt::InstanceDescriptor, + adapter: Arc, ) { - let device_id = wgc::id::Id::zip(test_num, 1); - let queue_id = wgc::id::Id::zip(test_num, 1); - let res = global.adapter_request_device( - adapter, - &wgt::DeviceDescriptor { - label: None, - required_features: self.features, - required_limits: wgt::Limits::default(), - experimental_features: unsafe { wgt::ExperimentalFeatures::enabled() }, - memory_hints: wgt::MemoryHints::default(), - trace: wgt::Trace::Off, - }, - Some(device_id), - Some(queue_id), - ); - if let Err(e) = res { - panic!("{e:?}"); - } + let (device, queue) = adapter + .create_device_and_queue( + &wgt::DeviceDescriptor { + label: None, + required_features: self.features, + required_limits: wgt::Limits::default(), + experimental_features: unsafe { wgt::ExperimentalFeatures::enabled() }, + memory_hints: wgt::MemoryHints::default(), + trace: wgt::Trace::Off, + }, + instance_desc.flags, + ) + .unwrap(); + + let mut player = Player::default(); - let mut command_encoder_id_manager = IdentityManager::new(); - let mut command_buffer_id_manager = IdentityManager::new(); println!("\t\t\tRunning..."); for action in self.actions { - global.process( - device_id, - queue_id, - action, - dir, - &mut command_encoder_id_manager, - &mut command_buffer_id_manager, - ); + player.process(&device, &queue, action, dir); } println!("\t\t\tMapping..."); for expect in &self.expectations { - let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch); - global - .buffer_map_async( - buffer, + player + .get_buffer(expect.buffer) + .map_async( expect.offset, Some(expect.data.len() as u64), wgc::resource::BufferMapOperation { @@ -135,25 +116,18 @@ impl Test<'_> { } println!("\t\t\tWaiting..."); - global - .device_poll( - device_id, - wgt::PollType::Wait { - submission_index: None, - timeout: Some(std::time::Duration::from_secs(1)), // Tests really shouldn't need longer than that! - }, - ) - .unwrap(); + let (user_closures, result) = device.poll(wgt::PollType::Wait { + submission_index: None, + timeout: Some(std::time::Duration::from_secs(1)), // Tests really shouldn't need longer than that! + }); + user_closures.fire(); + result.unwrap(); for expect in self.expectations { println!("\t\t\tChecking {}", expect.name); - let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch); - let (ptr, size) = global - .buffer_get_mapped_range( - buffer, - expect.offset, - Some(expect.data.len() as wgt::BufferAddress), - ) + let (ptr, size) = player + .get_buffer(expect.buffer) + .get_mapped_range(expect.offset, Some(expect.data.len() as wgt::BufferAddress)) .unwrap(); let contents = unsafe { slice::from_raw_parts(ptr.as_ptr(), size as usize) }; let expected_data = match expect.data { @@ -204,30 +178,26 @@ impl Corpus { if !corpus.backends.contains(backend.into()) { continue; } - let mut test_num = 0; for test_path in &corpus.tests { println!("\t\tTest '{test_path:?}'"); - let global = wgc::global::Global::new( - "test", - &wgt::InstanceDescriptor::from_env_or_default(), - ); - let adapter = match global.request_adapter( - &wgc::instance::RequestAdapterOptions { + let instance_desc = wgt::InstanceDescriptor::from_env_or_default(); + let instance = wgc::instance::Instance::new("test", &instance_desc); + let adapter = match instance.request_adapter( + &wgt::RequestAdapterOptions { power_preference: wgt::PowerPreference::None, force_fallback_adapter: false, compatible_surface: None, }, wgt::Backends::from(backend), - Some(wgc::id::Id::zip(0, 1)), ) { - Ok(adapter) => adapter, + Ok(adapter) => Arc::new(adapter), Err(_) => continue, }; println!("\tBackend {backend:?}"); - let supported_features = global.adapter_features(adapter); - let downlevel_caps = global.adapter_downlevel_capabilities(adapter); + let supported_features = adapter.features(); + let downlevel_caps = adapter.downlevel_capabilities(); let test = Test::load(dir.join(test_path), backend); if !supported_features.contains(test.features) { @@ -244,8 +214,7 @@ impl Corpus { println!("\t\tSkipped due to missing compute shader capability"); continue; } - test.run(dir, &global, adapter, test_num); - test_num += 1; + test.run(dir, &instance_desc, adapter); } } } diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 170d0f74928..b1f03e06948 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -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"] @@ -178,6 +178,7 @@ document-features.workspace = true hashbrown.workspace = true indexmap.workspace = true log.workspace = true +macro_rules_attribute.workspace = true once_cell = { workspace = true, features = ["std"] } parking_lot.workspace = true profiling = { workspace = true, default-features = false } diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 2cbac7bfa6b..3869d23776c 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -889,7 +889,8 @@ where } /// cbindgen:ignore -pub type ResolvedPipelineLayoutDescriptor<'a> = PipelineLayoutDescriptor<'a, Arc>; +pub type ResolvedPipelineLayoutDescriptor<'a, BGL = Arc> = + PipelineLayoutDescriptor<'a, BGL>; #[derive(Debug)] pub struct PipelineLayout { diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 8e8bf90b146..37e63e23cef 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -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, + base: BasePass, Infallible>, parent_id: id::DeviceId, pub(crate) context: RenderPassContext, pub(crate) is_depth_read_only: bool, @@ -175,7 +173,6 @@ impl RenderBundleEncoder { pub fn new( desc: &RenderBundleEncoderDescriptor, parent_id: id::DeviceId, - base: Option>, ) -> Result { let (is_depth_read_only, is_stencil_read_only) = match desc.depth_stencil { Some(ds) => { @@ -197,7 +194,7 @@ impl RenderBundleEncoder { //TODO: validate that attachment formats are renderable, // have expected aspects, support multisampling. Ok(Self { - base: base.unwrap_or_else(|| BasePass::new(&desc.label)), + base: BasePass::new(&desc.label), parent_id, context: RenderPassContext { attachments: AttachmentData { @@ -252,11 +249,6 @@ impl RenderBundleEncoder { } } - #[cfg(feature = "trace")] - pub(crate) fn to_base_pass(&self) -> BasePass { - self.base.clone() - } - pub fn parent(&self) -> id::DeviceId { self.parent_id } @@ -305,12 +297,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 +311,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 +323,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 +337,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 +364,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 +384,7 @@ impl RenderBundleEncoder { ) .map_pass_err(scope)?; } - RenderCommand::DrawIndexed { + &RenderCommand::DrawIndexed { index_count, instance_count, first_index, @@ -414,7 +406,7 @@ impl RenderBundleEncoder { ) .map_pass_err(scope)?; } - RenderCommand::DrawMeshTasks { + &RenderCommand::DrawMeshTasks { group_count_x, group_count_y, group_count_z, @@ -432,11 +424,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 +440,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 +519,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, ) { self.base.commands.push(RenderCommand::SetIndexBuffer { - buffer_id, + buffer, index_format, offset, size, @@ -899,8 +900,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 +942,7 @@ pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor>; //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 +973,11 @@ unsafe impl Send for RenderBundle {} unsafe impl Sync for RenderBundle {} impl RenderBundle { + #[cfg(feature = "trace")] + pub(crate) fn to_base_pass(&self) -> BasePass, 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 +1149,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 +1598,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 +1700,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 +1727,7 @@ pub mod bundle_ffi { ) { bundle.base.commands.push(RenderCommand::SetVertexBuffer { slot, - buffer_id, + buffer: buffer_id, offset, size, }); @@ -1813,10 +1821,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 +1836,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, }); } diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 5c8838f69e5..82bf960e78a 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -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)?, diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 515ca76e8f6..34607571be3 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -419,73 +419,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, - 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 {}", diff --git a/wgpu-core/src/command/compute_command.rs b/wgpu-core/src/command/compute_command.rs index 249713db6d4..7418ca51a34 100644 --- a/wgpu-core/src/command/compute_command.rs +++ b/wgpu-core/src/command/compute_command.rs @@ -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, - }, - - 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, 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 = commands - .iter() - .map(|c| -> Result { - 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::, 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 { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group: Option>, + bind_group: Option, }, - SetPipeline(Arc), + 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: 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, + query_set: R::QuerySet, query_index: u32, }, BeginPipelineStatisticsQuery { - query_set: Arc, + query_set: R::QuerySet, query_index: u32, }, EndPipelineStatisticsQuery, } + +/// cbindgen:ignore +pub type ArcComputeCommand = ComputeCommand; diff --git a/wgpu-core/src/command/encoder_command.rs b/wgpu-core/src/command/encoder_command.rs index 092228099bc..dc1642b502d 100644 --- a/wgpu-core/src/command/encoder_command.rs +++ b/wgpu-core/src/command/encoder_command.rs @@ -1,141 +1,183 @@ use core::convert::Infallible; use alloc::{string::String, sync::Arc, vec::Vec}; +#[cfg(feature = "serde")] +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 ExternalTexture: Clone + core::fmt::Debug; + type QuerySet: Clone + core::fmt::Debug; + type BindGroup: Clone + core::fmt::Debug; + type RenderPipeline: Clone + core::fmt::Debug; + type RenderBundle: Clone + core::fmt::Debug; + type ComputePipeline: Clone + core::fmt::Debug; + type Blas: Clone + core::fmt::Debug; + type Tlas: Clone + core::fmt::Debug; +} + +/// Reference wgpu objects via numeric IDs assigned by [`crate::identity::IdentityManager`]. #[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Command { - CopyBufferToBuffer { - src: id::BufferId, - src_offset: wgt::BufferAddress, - dst: id::BufferId, - dst_offset: wgt::BufferAddress, - size: Option, - }, - CopyBufferToTexture { - src: wgt::TexelCopyBufferInfo, - dst: wgt::TexelCopyTextureInfo, - size: wgt::Extent3d, - }, - CopyTextureToBuffer { - src: wgt::TexelCopyTextureInfo, - dst: wgt::TexelCopyBufferInfo, - size: wgt::Extent3d, - }, - CopyTextureToTexture { - src: wgt::TexelCopyTextureInfo, - dst: wgt::TexelCopyTextureInfo, - size: wgt::Extent3d, - }, - ClearBuffer { - dst: id::BufferId, - offset: wgt::BufferAddress, - size: Option, - }, - ClearTexture { - dst: id::TextureId, - subresource_range: wgt::ImageSubresourceRange, - }, - WriteTimestamp { - query_set_id: id::QuerySetId, - query_index: u32, - }, - ResolveQuerySet { - query_set_id: id::QuerySetId, - start_query: u32, - query_count: u32, - destination: id::BufferId, - destination_offset: wgt::BufferAddress, - }, - PushDebugGroup(String), - PopDebugGroup, - InsertDebugMarker(String), - RunComputePass { - base: crate::command::BasePass, - timestamp_writes: Option, - }, - RunRenderPass { - base: crate::command::BasePass, - target_colors: Vec>, - target_depth_stencil: Option, - timestamp_writes: Option, - occlusion_query_set_id: Option, - }, - BuildAccelerationStructures { - blas: Vec, - tlas: Vec, - }, +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 ExternalTexture = id::ExternalTextureId; + type QuerySet = id::QuerySetId; + type BindGroup = id::BindGroupId; + type RenderPipeline = id::RenderPipelineId; + type RenderBundle = id::RenderBundleId; + type ComputePipeline = id::ComputePipelineId; + type Blas = id::BlasId; + type Tlas = id::TlasId; +} + +impl ReferenceType for PointerReferences { + type Buffer = id::PointerId; + type Surface = id::PointerId; + type Texture = id::PointerId; + type TextureView = id::PointerId; + type ExternalTexture = id::PointerId; + type QuerySet = id::PointerId; + type BindGroup = id::PointerId; + type RenderPipeline = id::PointerId; + type RenderBundle = id::PointerId; + type ComputePipeline = id::PointerId; + type Blas = id::PointerId; + type Tlas = id::PointerId; +} + +impl ReferenceType for ArcReferences { + type Buffer = Arc; + type Surface = Arc; + type Texture = Arc; + type TextureView = Arc; + type ExternalTexture = Arc; + type QuerySet = Arc; + type BindGroup = Arc; + type RenderPipeline = Arc; + type RenderBundle = Arc; + type ComputePipeline = Arc; + type Blas = Arc; + type Tlas = Arc; +} + +#[cfg(feature = "serde")] +attribute_alias! { + #[apply(serde_object_reference_struct)] = + #[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::ExternalTexture: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::QuerySet: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::BindGroup: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::RenderPipeline: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + 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>,\ + wgt::BufferTransition: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + wgt::TextureTransition: serde::Serialize + for<'d> serde::Deserialize<'d>" + )]; } #[derive(Clone, Debug)] -pub enum ArcCommand { +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub enum Command { CopyBufferToBuffer { - src: Arc, + src: R::Buffer, src_offset: wgt::BufferAddress, - dst: Arc, + dst: R::Buffer, dst_offset: wgt::BufferAddress, size: Option, }, CopyBufferToTexture { - src: wgt::TexelCopyBufferInfo>, - dst: wgt::TexelCopyTextureInfo>, + src: wgt::TexelCopyBufferInfo, + dst: wgt::TexelCopyTextureInfo, size: wgt::Extent3d, }, CopyTextureToBuffer { - src: wgt::TexelCopyTextureInfo>, - dst: wgt::TexelCopyBufferInfo>, + src: wgt::TexelCopyTextureInfo, + dst: wgt::TexelCopyBufferInfo, size: wgt::Extent3d, }, CopyTextureToTexture { - src: wgt::TexelCopyTextureInfo>, - dst: wgt::TexelCopyTextureInfo>, + src: wgt::TexelCopyTextureInfo, + dst: wgt::TexelCopyTextureInfo, size: wgt::Extent3d, }, ClearBuffer { - dst: Arc, + dst: R::Buffer, offset: wgt::BufferAddress, size: Option, }, ClearTexture { - dst: Arc, + dst: R::Texture, subresource_range: wgt::ImageSubresourceRange, }, WriteTimestamp { - query_set: Arc, + query_set: R::QuerySet, query_index: u32, }, ResolveQuerySet { - query_set: Arc, + query_set: R::QuerySet, start_query: u32, query_count: u32, - destination: Arc, + destination: R::Buffer, destination_offset: wgt::BufferAddress, }, PushDebugGroup(String), PopDebugGroup, InsertDebugMarker(String), RunComputePass { - pass: super::BasePass, - timestamp_writes: Option, + pass: crate::command::BasePass, Infallible>, + timestamp_writes: Option>, }, RunRenderPass { - pass: super::BasePass, - color_attachments: super::ArcRenderPassColorAttachmentArray, - depth_stencil_attachment: Option, - timestamp_writes: Option, - occlusion_query_set: Option>, + pass: crate::command::BasePass, Infallible>, + color_attachments: ColorAttachments, + depth_stencil_attachment: + Option>, + timestamp_writes: Option>, + occlusion_query_set: Option, }, BuildAccelerationStructures { - blas: Vec, - tlas: Vec, + blas: Vec>, + tlas: Vec>, }, TransitionResources { - buffer_transitions: Vec>>, - texture_transitions: Vec>>, + buffer_transitions: Vec>, + texture_transitions: Vec>, }, } + +pub type ArcCommand = Command; diff --git a/wgpu-core/src/command/ffi.rs b/wgpu-core/src/command/ffi.rs index 9f53d7b5634..4b9a5effbc6 100644 --- a/wgpu-core/src/command/ffi.rs +++ b/wgpu-core/src/command/ffi.rs @@ -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; pub type TexelCopyTextureInfo = wgt::TexelCopyTextureInfo; pub type CopyExternalImageDestInfo = wgt::CopyExternalImageDestInfo; + +pub type Command = super::Command; diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 887c19fb357..de43da04ed9 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -31,23 +31,31 @@ mod transition_resources; use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec::Vec}; use core::convert::Infallible; use core::mem::{self, ManuallyDrop}; -use core::ops; +use core::{ops, panic}; pub(crate) use self::clear::clear_texture; +#[cfg(feature = "serde")] +pub(crate) use self::encoder_command::serde_object_reference_struct; +#[cfg(any(feature = "trace", feature = "replay"))] +#[doc(hidden)] +pub use self::encoder_command::PointerReferences; pub use self::{ bundle::*, clear::ClearError, compute::*, - compute_command::{ArcComputeCommand, ComputeCommand}, + compute_command::ArcComputeCommand, draw::*, - encoder_command::{ArcCommand, Command}, + 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; @@ -81,9 +89,6 @@ use wgt::error::{ErrorType, WebGpuError}; use thiserror::Error; -#[cfg(feature = "trace")] -type TraceCommand = Command; - /// cbindgen:ignore pub type TexelCopyBufferInfo = ffi::TexelCopyBufferInfo; /// cbindgen:ignore @@ -148,12 +153,12 @@ pub(crate) enum CommandEncoderStatus { } impl CommandEncoderStatus { - #[cfg(feature = "trace")] - fn trace(&mut self) -> Option<&mut Vec> { - match self { - Self::Recording(cmd_buf_data) => cmd_buf_data.trace_commands.as_mut(), - _ => None, - } + #[doc(hidden)] + fn replay(&mut self, commands: Vec>) { + let Self::Recording(cmd_buf_data) = self else { + panic!("encoder should be in the recording state"); + }; + cmd_buf_data.commands.extend(commands); } /// Push a command provided by a closure onto the encoder. @@ -271,20 +276,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, @@ -734,10 +725,12 @@ pub struct CommandBufferMutable { indirect_draw_validation_resources: crate::indirect_validation::DrawResources, - pub(crate) commands: Vec, + pub(crate) commands: Vec>, + /// 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>, + pub(crate) trace_commands: Option>>, } impl CommandBufferMutable { @@ -898,9 +891,259 @@ impl CommandEncoder { raw.transition_textures(&texture_barriers); } } + + fn finish( + self: &Arc, + desc: &wgt::CommandBufferDescriptor