mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 16:24:24 +00:00
trace: make Id serialization nicer
This commit is contained in:
parent
3c68fb17e4
commit
f64b2dd3bb
@ -17,6 +17,7 @@ The implementation consists of the following parts:
|
||||
|
||||
- `wgpu-core` - internal Rust API for WebGPU implementations to use
|
||||
- `wgpu-types` - Rust types shared between `wgpu-core`, `wgpu-native`, and `wgpu-rs`
|
||||
- `player` - application for replaying the API traces, uses `winit`
|
||||
|
||||
This repository is not meant for direct use by applications.
|
||||
If you are looking for the user-facing Rust API, you need [wgpu-rs](https://github.com/gfx-rs/wgpu-rs).
|
||||
|
12
player/README.md
Normal file
12
player/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# wgpu player
|
||||
|
||||
This is application that allows replaying the `wgpu` workloads recorded elsewhere.
|
||||
|
||||
Launch as:
|
||||
```rust
|
||||
player <trace-dir>
|
||||
```
|
||||
|
||||
When built with "winit" feature, it's able to replay the workloads that operate on a swapchain. It renders each frame consequently, then waits for the user to close the window. When built without "winit", it launches in console mode and can replay any trace that doesn't use swapchains.
|
||||
|
||||
Note: replaying is currently restricted to the same backend, as one used for recording a trace. It is straightforward, however, to just replace the backend in RON, since it's serialized as plain text. Valid values are: Vulkan, Metal, Dx12, and Dx11.
|
@ -454,7 +454,6 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
let global = wgc::hub::Global::new("player", IdentityPassThroughFactory);
|
||||
let mut adapter_id_manager = wgc::hub::IdentityManager::default();
|
||||
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
@ -463,37 +462,28 @@ fn main() {
|
||||
wgc::id::TypedId::zip(0, 1, wgt::Backend::Empty),
|
||||
);
|
||||
|
||||
let adapter = global
|
||||
.pick_adapter(
|
||||
&wgc::instance::RequestAdapterOptions {
|
||||
power_preference: wgt::PowerPreference::Default,
|
||||
#[cfg(feature = "winit")]
|
||||
compatible_surface: Some(surface),
|
||||
#[cfg(not(feature = "winit"))]
|
||||
compatible_surface: None,
|
||||
},
|
||||
wgc::instance::AdapterInputs::IdSet(
|
||||
&vec![
|
||||
adapter_id_manager.alloc(wgt::Backend::Vulkan),
|
||||
adapter_id_manager.alloc(wgt::Backend::Dx12),
|
||||
adapter_id_manager.alloc(wgt::Backend::Metal),
|
||||
],
|
||||
|id| id.backend(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
log::info!("Initializing the device");
|
||||
let device = match actions.pop() {
|
||||
Some(trace::Action::Init { limits }) => {
|
||||
Some(trace::Action::Init { desc, backend }) => {
|
||||
log::info!("Initializing the device for backend: {:?}", backend);
|
||||
let adapter = global
|
||||
.pick_adapter(
|
||||
&wgc::instance::RequestAdapterOptions {
|
||||
power_preference: wgt::PowerPreference::Default,
|
||||
#[cfg(feature = "winit")]
|
||||
compatible_surface: Some(surface),
|
||||
#[cfg(not(feature = "winit"))]
|
||||
compatible_surface: None,
|
||||
},
|
||||
wgc::instance::AdapterInputs::IdSet(
|
||||
&[wgc::id::TypedId::zip(0, 0, backend)],
|
||||
|id| id.backend(),
|
||||
),
|
||||
)
|
||||
.expect("Unable to find an adapter for selected backend");
|
||||
gfx_select!(adapter => global.adapter_request_device(
|
||||
adapter,
|
||||
&wgt::DeviceDescriptor {
|
||||
extensions: wgt::Extensions {
|
||||
anisotropic_filtering: false,
|
||||
},
|
||||
limits,
|
||||
},
|
||||
&desc,
|
||||
None,
|
||||
wgc::id::TypedId::zip(1, 0, wgt::Backend::Empty)
|
||||
))
|
||||
}
|
||||
@ -501,72 +491,69 @@ fn main() {
|
||||
};
|
||||
|
||||
log::info!("Executing actions");
|
||||
#[cfg(feature = "winit")]
|
||||
{
|
||||
let mut frame_count = 0;
|
||||
winit::platform::desktop::EventLoopExtDesktop::run_return(
|
||||
&mut event_loop,
|
||||
move |event, _, control_flow| {
|
||||
use winit::{
|
||||
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||
event_loop::ControlFlow,
|
||||
};
|
||||
|
||||
*control_flow = ControlFlow::Poll;
|
||||
match event {
|
||||
Event::MainEventsCleared => {
|
||||
window.request_redraw();
|
||||
}
|
||||
Event::RedrawRequested(_) => loop {
|
||||
match actions.pop() {
|
||||
Some(trace::Action::CreateSwapChain { id, desc }) => {
|
||||
log::info!("Initializing the swapchain");
|
||||
assert_eq!(id.to_surface_id(), surface);
|
||||
window.set_inner_size(winit::dpi::PhysicalSize::new(
|
||||
desc.width,
|
||||
desc.height,
|
||||
));
|
||||
gfx_select!(device => global.device_create_swap_chain(device, surface, &desc));
|
||||
}
|
||||
Some(trace::Action::PresentSwapChain(id)) => {
|
||||
frame_count += 1;
|
||||
log::debug!("Presenting frame {}", frame_count);
|
||||
gfx_select!(device => global.swap_chain_present(id));
|
||||
break;
|
||||
}
|
||||
Some(action) => {
|
||||
gfx_select!(device => global.process(device, action, &dir, &mut command_buffer_id_manager));
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
},
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
state: ElementState::Pressed,
|
||||
..
|
||||
},
|
||||
..
|
||||
}
|
||||
| WindowEvent::CloseRequested => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Event::LoopDestroyed => {
|
||||
log::info!("Closing");
|
||||
gfx_select!(device => global.device_poll(device, true));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "winit"))]
|
||||
while let Some(action) = actions.pop() {
|
||||
gfx_select!(device => global.process(device, action, &dir, &mut command_buffer_id_manager));
|
||||
}
|
||||
#[cfg(feature = "winit")]
|
||||
{
|
||||
use winit::{
|
||||
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||
event_loop::ControlFlow,
|
||||
platform::desktop::EventLoopExtDesktop,
|
||||
};
|
||||
|
||||
let mut frame_count = 0;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Poll;
|
||||
match event {
|
||||
Event::MainEventsCleared => {
|
||||
window.request_redraw();
|
||||
}
|
||||
Event::RedrawRequested(_) => loop {
|
||||
match actions.pop() {
|
||||
Some(trace::Action::CreateSwapChain { id, desc }) => {
|
||||
log::info!("Initializing the swapchain");
|
||||
assert_eq!(id.to_surface_id(), surface);
|
||||
window.set_inner_size(winit::dpi::PhysicalSize::new(
|
||||
desc.width,
|
||||
desc.height,
|
||||
));
|
||||
gfx_select!(device => global.device_create_swap_chain(device, surface, &desc));
|
||||
}
|
||||
Some(trace::Action::PresentSwapChain(id)) => {
|
||||
frame_count += 1;
|
||||
log::debug!("Presenting frame {}", frame_count);
|
||||
gfx_select!(device => global.swap_chain_present(id));
|
||||
break;
|
||||
}
|
||||
Some(action) => {
|
||||
gfx_select!(device => global.process(device, action, &dir, &mut command_buffer_id_manager));
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
},
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
state: ElementState::Pressed,
|
||||
..
|
||||
},
|
||||
..
|
||||
}
|
||||
| WindowEvent::CloseRequested => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Event::LoopDestroyed => {
|
||||
log::info!("Closing");
|
||||
gfx_select!(device => global.device_poll(device, true));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ pub enum ComputeCommand {
|
||||
index: u8,
|
||||
num_dynamic_offsets: u8,
|
||||
bind_group_id: id::BindGroupId,
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_offsets: PhantomSlice<DynamicOffset>,
|
||||
},
|
||||
SetPipeline(id::ComputePipelineId),
|
||||
|
@ -63,7 +63,7 @@ pub enum RenderCommand {
|
||||
index: u8,
|
||||
num_dynamic_offsets: u8,
|
||||
bind_group_id: id::BindGroupId,
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_offsets: PhantomSlice<DynamicOffset>,
|
||||
},
|
||||
SetPipeline(id::RenderPipelineId),
|
||||
|
@ -199,6 +199,7 @@ pub struct Device<B: hal::Backend> {
|
||||
temp_suspected: life::SuspectedResources,
|
||||
pub(crate) private_features: PrivateFeatures,
|
||||
limits: wgt::Limits,
|
||||
extensions: wgt::Extensions,
|
||||
#[cfg(feature = "trace")]
|
||||
pub(crate) trace: Option<Mutex<Trace>>,
|
||||
}
|
||||
@ -211,8 +212,8 @@ impl<B: GfxBackend> Device<B> {
|
||||
mem_props: hal::adapter::MemoryProperties,
|
||||
non_coherent_atom_size: u64,
|
||||
supports_texture_d24_s8: bool,
|
||||
limits: wgt::Limits,
|
||||
#[cfg(feature = "trace")] trace_path: Option<&std::path::Path>,
|
||||
desc: &wgt::DeviceDescriptor,
|
||||
trace_path: Option<&std::path::Path>,
|
||||
) -> Self {
|
||||
// don't start submission index at zero
|
||||
let life_guard = LifeGuard::new();
|
||||
@ -232,6 +233,11 @@ impl<B: GfxBackend> Device<B> {
|
||||
non_coherent_atom_size,
|
||||
)
|
||||
};
|
||||
#[cfg(not(feature = "trace"))]
|
||||
match trace_path {
|
||||
Some(_) => log::warn!("Tracing feature is not enabled"),
|
||||
None => (),
|
||||
}
|
||||
|
||||
Device {
|
||||
raw,
|
||||
@ -250,7 +256,8 @@ impl<B: GfxBackend> Device<B> {
|
||||
trace: trace_path.and_then(|path| match Trace::new(path) {
|
||||
Ok(mut trace) => {
|
||||
trace.add(Action::Init {
|
||||
limits: limits.clone(),
|
||||
desc: desc.clone(),
|
||||
backend: B::VARIANT,
|
||||
});
|
||||
Some(Mutex::new(trace))
|
||||
}
|
||||
@ -262,7 +269,8 @@ impl<B: GfxBackend> Device<B> {
|
||||
private_features: PrivateFeatures {
|
||||
supports_texture_d24_s8,
|
||||
},
|
||||
limits,
|
||||
limits: desc.limits.clone(),
|
||||
extensions: desc.extensions.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2336,7 +2344,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
||||
#[cfg(feature = "replay")]
|
||||
/// Only triange suspected resource IDs. This helps us to avoid ID collisions
|
||||
/// upon creating new resources when re-plaing a trace.
|
||||
/// upon creating new resources when re-playing a trace.
|
||||
pub fn device_maintain_ids<B: GfxBackend>(&self, device_id: id::DeviceId) {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
|
@ -96,7 +96,8 @@ pub struct RenderPipelineDescriptor {
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub enum Action {
|
||||
Init {
|
||||
limits: wgt::Limits,
|
||||
desc: wgt::DeviceDescriptor,
|
||||
backend: wgt::Backend,
|
||||
},
|
||||
CreateBuffer {
|
||||
id: id::BufferId,
|
||||
|
@ -11,9 +11,37 @@ const EPOCH_MASK: u32 = (1 << (32 - BACKEND_BITS)) - 1;
|
||||
type Dummy = crate::backend::Empty;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize), serde(into = "SerialId"))]
|
||||
#[cfg_attr(
|
||||
feature = "replay",
|
||||
derive(serde::Deserialize),
|
||||
serde(from = "SerialId")
|
||||
)]
|
||||
pub struct Id<T>(NonZeroU64, PhantomData<T>);
|
||||
|
||||
// This type represents Id in a more readable (and editable) way.
|
||||
#[allow(dead_code)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub struct Id<T>(NonZeroU64, PhantomData<T>);
|
||||
enum SerialId {
|
||||
// The only variant forces RON to not ignore "Id"
|
||||
Id(Index, Epoch, Backend),
|
||||
}
|
||||
#[cfg(feature = "trace")]
|
||||
impl<T> From<Id<T>> for SerialId {
|
||||
fn from(id: Id<T>) -> Self {
|
||||
let (index, epoch, backend) = id.unzip();
|
||||
SerialId::Id(index, epoch, backend)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "replay")]
|
||||
impl<T> From<SerialId> for Id<T> {
|
||||
fn from(id: SerialId) -> Self {
|
||||
match id {
|
||||
SerialId::Id(index, epoch, backend) => TypedId::zip(index, epoch, backend),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// required for PeekPoke
|
||||
impl<T> Default for Id<T> {
|
||||
|
@ -580,7 +580,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
&self,
|
||||
adapter_id: AdapterId,
|
||||
desc: &DeviceDescriptor,
|
||||
#[cfg(feature = "trace")] trace_path: Option<&std::path::Path>,
|
||||
trace_path: Option<&std::path::Path>,
|
||||
id_in: Input<G, DeviceId>,
|
||||
) -> DeviceId {
|
||||
let hub = B::hub(self);
|
||||
@ -646,8 +646,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
mem_props,
|
||||
limits.non_coherent_atom_size as u64,
|
||||
supports_texture_d24_s8,
|
||||
desc.limits.clone(),
|
||||
#[cfg(feature = "trace")]
|
||||
desc,
|
||||
trace_path,
|
||||
)
|
||||
};
|
||||
|
@ -37,7 +37,7 @@ pub enum PowerPreference {
|
||||
bitflags::bitflags! {
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BackendBit: u32 {
|
||||
const VULKAN = 1 << Backend::Vulkan as u32;
|
||||
const GL = 1 << Backend::Gl as u32;
|
||||
|
Loading…
Reference in New Issue
Block a user