Skip to content

Commit 789319d

Browse files
committed
Player-based GPU test framework
1 parent 3cdb9f7 commit 789319d

File tree

9 files changed

+396
-169
lines changed

9 files changed

+396
-169
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

player/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ keywords = ["graphics"]
1212
license = "MPL-2.0"
1313
publish = false
1414

15+
[lib]
16+
17+
[[bin]]
18+
name = "play"
19+
1520
[features]
1621

1722
[dependencies]
@@ -36,3 +41,6 @@ features = ["replay", "raw-window-handle"]
3641

3742
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
3843
gfx-backend-vulkan = { version = "0.5", features = ["x11"] }
44+
45+
[dev-dependencies]
46+
serde = "1"

player/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# wgpu player
22

3-
This is application that allows replaying the `wgpu` workloads recorded elsewhere.
3+
This is application that allows replaying the `wgpu` workloads recorded elsewhere. You must use the player built from
4+
the same revision as an application was linking to, or otherwise the data may fail to load.
45

56
Launch as:
67
```rust
7-
player <trace-dir>
8+
play <trace-dir>
89
```
910

1011
When built with "winit" feature, it's able to replay the workloads that operate on a swapchain. It renders each frame sequentially, 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.

player/src/bin/play.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
/*! This is a player for WebGPU traces.
6+
!*/
7+
8+
use player::{gfx_select, GlobalPlay as _, IdentityPassThroughFactory};
9+
use wgc::device::trace;
10+
11+
use std::{
12+
fs,
13+
path::{Path, PathBuf},
14+
};
15+
16+
fn main() {
17+
#[cfg(feature = "winit")]
18+
use winit::{event_loop::EventLoop, window::WindowBuilder};
19+
20+
env_logger::init();
21+
22+
#[cfg(feature = "renderdoc")]
23+
#[cfg_attr(feature = "winit", allow(unused))]
24+
let mut rd = renderdoc::RenderDoc::<renderdoc::V110>::new()
25+
.expect("Failed to connect to RenderDoc: are you running without it?");
26+
27+
//TODO: setting for the backend bits
28+
//TODO: setting for the target frame, or controls
29+
30+
let dir = match std::env::args().nth(1) {
31+
Some(arg) if Path::new(&arg).is_dir() => PathBuf::from(arg),
32+
_ => panic!("Provide the dir path as the parameter"),
33+
};
34+
35+
log::info!("Loading trace '{:?}'", dir);
36+
let file = fs::File::open(dir.join(trace::FILE_NAME)).unwrap();
37+
let mut actions: Vec<trace::Action> = ron::de::from_reader(file).unwrap();
38+
actions.reverse(); // allows us to pop from the top
39+
log::info!("Found {} actions", actions.len());
40+
41+
#[cfg(feature = "winit")]
42+
let event_loop = {
43+
log::info!("Creating a window");
44+
EventLoop::new()
45+
};
46+
#[cfg(feature = "winit")]
47+
let window = WindowBuilder::new()
48+
.with_title("wgpu player")
49+
.with_resizable(false)
50+
.build(&event_loop)
51+
.unwrap();
52+
53+
let global =
54+
wgc::hub::Global::new("player", IdentityPassThroughFactory, wgt::BackendBit::all());
55+
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
56+
57+
#[cfg(feature = "winit")]
58+
let surface =
59+
global.instance_create_surface(&window, wgc::id::TypedId::zip(0, 1, wgt::Backend::Empty));
60+
61+
let device = match actions.pop() {
62+
Some(trace::Action::Init { desc, backend }) => {
63+
log::info!("Initializing the device for backend: {:?}", backend);
64+
let adapter = global
65+
.pick_adapter(
66+
&wgc::instance::RequestAdapterOptions {
67+
power_preference: wgt::PowerPreference::Default,
68+
#[cfg(feature = "winit")]
69+
compatible_surface: Some(surface),
70+
#[cfg(not(feature = "winit"))]
71+
compatible_surface: None,
72+
},
73+
wgc::instance::AdapterInputs::IdSet(
74+
&[wgc::id::TypedId::zip(0, 0, backend)],
75+
|id| id.backend(),
76+
),
77+
)
78+
.expect("Unable to find an adapter for selected backend");
79+
80+
let info = gfx_select!(adapter => global.adapter_get_info(adapter));
81+
log::info!("Picked '{}'", info.name);
82+
gfx_select!(adapter => global.adapter_request_device(
83+
adapter,
84+
&desc,
85+
None,
86+
wgc::id::TypedId::zip(1, 0, wgt::Backend::Empty)
87+
))
88+
.expect("Failed to request device")
89+
}
90+
_ => panic!("Expected Action::Init"),
91+
};
92+
log::info!("Executing actions");
93+
#[cfg(not(feature = "winit"))]
94+
{
95+
#[cfg(feature = "renderdoc")]
96+
rd.start_frame_capture(ptr::null(), ptr::null());
97+
98+
while let Some(action) = actions.pop() {
99+
gfx_select!(device => global.process(device, action, &dir, &mut command_buffer_id_manager));
100+
}
101+
102+
#[cfg(feature = "renderdoc")]
103+
rd.end_frame_capture(ptr::null(), ptr::null());
104+
gfx_select!(device => global.device_poll(device, true));
105+
}
106+
#[cfg(feature = "winit")]
107+
{
108+
use winit::{
109+
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
110+
event_loop::ControlFlow,
111+
};
112+
113+
let mut frame_count = 0;
114+
event_loop.run(move |event, _, control_flow| {
115+
*control_flow = ControlFlow::Poll;
116+
match event {
117+
Event::MainEventsCleared => {
118+
window.request_redraw();
119+
}
120+
Event::RedrawRequested(_) => loop {
121+
match actions.pop() {
122+
Some(trace::Action::CreateSwapChain { id, desc }) => {
123+
log::info!("Initializing the swapchain");
124+
assert_eq!(id.to_surface_id(), surface);
125+
window.set_inner_size(winit::dpi::PhysicalSize::new(
126+
desc.width,
127+
desc.height,
128+
));
129+
gfx_select!(device => global.device_create_swap_chain(device, surface, &desc));
130+
}
131+
Some(trace::Action::PresentSwapChain(id)) => {
132+
frame_count += 1;
133+
log::debug!("Presenting frame {}", frame_count);
134+
gfx_select!(device => global.swap_chain_present(id));
135+
break;
136+
}
137+
Some(action) => {
138+
gfx_select!(device => global.process(device, action, &dir, &mut command_buffer_id_manager));
139+
}
140+
None => break,
141+
}
142+
},
143+
Event::WindowEvent { event, .. } => match event {
144+
WindowEvent::KeyboardInput {
145+
input:
146+
KeyboardInput {
147+
virtual_keycode: Some(VirtualKeyCode::Escape),
148+
state: ElementState::Pressed,
149+
..
150+
},
151+
..
152+
}
153+
| WindowEvent::CloseRequested => {
154+
*control_flow = ControlFlow::Exit;
155+
}
156+
_ => {}
157+
},
158+
Event::LoopDestroyed => {
159+
log::info!("Closing");
160+
gfx_select!(device => global.device_poll(device, true));
161+
}
162+
_ => {}
163+
}
164+
});
165+
}
166+
}

0 commit comments

Comments
 (0)