mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
trace: player skeleton
This commit is contained in:
parent
622d9ecc74
commit
47f37ad78e
@ -1,5 +1,6 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"player",
|
||||
"wgpu-core",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
32
player/Cargo.toml
Normal file
32
player/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "player"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Dzmitry Malyshau <kvark@mozilla.com>",
|
||||
]
|
||||
edition = "2018"
|
||||
description = "WebGPU trace player"
|
||||
homepage = "https://github.com/gfx-rs/wgpu"
|
||||
repository = "https://github.com/gfx-rs/wgpu"
|
||||
keywords = ["graphics"]
|
||||
license = "MPL-2.0"
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.7"
|
||||
ron = { version = "0.5" }
|
||||
winit = { version = "0.22" }
|
||||
|
||||
[dependencies.wgt]
|
||||
path = "../wgpu-types"
|
||||
package = "wgpu-types"
|
||||
version = "0.5"
|
||||
features = ["replay"]
|
||||
|
||||
[dependencies.wgc]
|
||||
path = "../wgpu-core"
|
||||
package = "wgpu-core"
|
||||
version = "0.5"
|
||||
features = ["replay", "raw-window-handle"]
|
121
player/src/main.rs
Normal file
121
player/src/main.rs
Normal file
@ -0,0 +1,121 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use wgc::device::trace;
|
||||
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
fs::File,
|
||||
marker::PhantomData,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use winit::{event_loop::EventLoop, window::WindowBuilder};
|
||||
|
||||
macro_rules! gfx_select {
|
||||
($id:expr => $global:ident.$method:ident( $($param:expr),+ )) => {
|
||||
match $id.backend() {
|
||||
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
|
||||
wgt::Backend::Vulkan => $global.$method::<wgc::backend::Vulkan>( $($param),+ ),
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
wgt::Backend::Metal => $global.$method::<wgc::backend::Metal>( $($param),+ ),
|
||||
#[cfg(windows)]
|
||||
wgt::Backend::Dx12 => $global.$method::<wgc::backend::Dx12>( $($param),+ ),
|
||||
#[cfg(windows)]
|
||||
wgt::Backend::Dx11 => $global.$method::<wgc::backend::Dx11>( $($param),+ ),
|
||||
_ => unreachable!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IdentityPassThrough<I>(PhantomData<I>);
|
||||
|
||||
impl<I: Clone + Debug + wgc::id::TypedId> wgc::hub::IdentityHandler<I> for IdentityPassThrough<I> {
|
||||
type Input = I;
|
||||
fn process(&self, id: I, backend: wgt::Backend) -> I {
|
||||
let (index, epoch, _backend) = id.unzip();
|
||||
I::zip(index, epoch, backend)
|
||||
}
|
||||
fn free(&self, _id: I) {}
|
||||
}
|
||||
|
||||
struct IdentityPassThroughFactory;
|
||||
|
||||
impl<I: Clone + Debug + wgc::id::TypedId> wgc::hub::IdentityHandlerFactory<I>
|
||||
for IdentityPassThroughFactory
|
||||
{
|
||||
type Filter = IdentityPassThrough<I>;
|
||||
fn spawn(&self, _min_index: u32) -> Self::Filter {
|
||||
IdentityPassThrough(PhantomData)
|
||||
}
|
||||
}
|
||||
impl wgc::hub::GlobalIdentityHandlerFactory for IdentityPassThroughFactory {}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let folder = match std::env::args().nth(1) {
|
||||
Some(arg) if Path::new(&arg).is_dir() => PathBuf::from(arg),
|
||||
_ => panic!("Provide the folder path as the parameter"),
|
||||
};
|
||||
|
||||
let file = File::open(folder.join(trace::FILE_NAME)).unwrap();
|
||||
let actions: Vec<trace::Action> = ron::de::from_reader(file).unwrap();
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let mut builder = WindowBuilder::new();
|
||||
builder = builder.with_title("wgpu player");
|
||||
let window = builder.build(&event_loop).unwrap();
|
||||
|
||||
let global = wgc::hub::Global::new("player", IdentityPassThroughFactory);
|
||||
let mut surface_id_manager = wgc::hub::IdentityManager::from_index(1);
|
||||
let mut adapter_id_manager = wgc::hub::IdentityManager::default();
|
||||
let mut device_id_manager = wgc::hub::IdentityManager::default();
|
||||
|
||||
let (_size, surface) = {
|
||||
let size = window.inner_size();
|
||||
let id = surface_id_manager.alloc(wgt::Backend::Empty);
|
||||
let surface = global.instance_create_surface(&window, id);
|
||||
(size, surface)
|
||||
};
|
||||
|
||||
let adapter = global
|
||||
.pick_adapter(
|
||||
&wgc::instance::RequestAdapterOptions {
|
||||
power_preference: wgt::PowerPreference::Default,
|
||||
compatible_surface: Some(surface),
|
||||
},
|
||||
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| wgc::id::TypedId::unzip(*id).2,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let limits = match actions.first() {
|
||||
Some(&trace::Action::Init { ref limits }) => limits.clone(),
|
||||
other => panic!("Unsupported first action: {:?}", other),
|
||||
};
|
||||
|
||||
let device = gfx_select!(adapter => global.adapter_request_device(
|
||||
adapter,
|
||||
&wgt::DeviceDescriptor {
|
||||
extensions: wgt::Extensions {
|
||||
anisotropic_filtering: false,
|
||||
},
|
||||
limits,
|
||||
},
|
||||
device_id_manager.alloc(wgt::Backend::Vulkan)
|
||||
));
|
||||
|
||||
for action in actions.into_iter().skip(1) {
|
||||
match action {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ gfx-descriptor = "0.1"
|
||||
gfx-memory = "0.1"
|
||||
parking_lot = "0.10"
|
||||
peek-poke = "0.2"
|
||||
raw-window-handle = { version = "0.3", optional = true }
|
||||
ron = { version = "0.5", optional = true }
|
||||
serde = { version = "1.0", features = ["serde_derive"], optional = true }
|
||||
smallvec = "1"
|
||||
|
@ -28,7 +28,7 @@ enum PipelineState {
|
||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub(crate) enum ComputeCommand {
|
||||
pub enum ComputeCommand {
|
||||
SetBindGroup {
|
||||
index: u8,
|
||||
num_dynamic_offsets: u8,
|
||||
|
@ -27,7 +27,7 @@ use peek_poke::PeekPoke;
|
||||
use std::{marker::PhantomData, mem, ptr, slice, thread::ThreadId};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||
pub(crate) struct PhantomSlice<T>(PhantomData<T>);
|
||||
pub struct PhantomSlice<T>(PhantomData<T>);
|
||||
|
||||
impl<T> Default for PhantomSlice<T> {
|
||||
fn default() -> Self {
|
||||
|
@ -58,7 +58,7 @@ pub struct Rect<T> {
|
||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub(crate) enum RenderCommand {
|
||||
pub enum RenderCommand {
|
||||
SetBindGroup {
|
||||
index: u8,
|
||||
num_dynamic_offsets: u8,
|
||||
|
@ -31,8 +31,8 @@ use std::{
|
||||
};
|
||||
|
||||
mod life;
|
||||
#[cfg(feature = "trace")]
|
||||
pub(crate) mod trace;
|
||||
#[cfg(any(feature = "trace", feature = "replay"))]
|
||||
pub mod trace;
|
||||
#[cfg(feature = "trace")]
|
||||
use trace::{Action, Trace};
|
||||
|
||||
|
@ -6,12 +6,19 @@ use crate::{
|
||||
command::{BufferCopyView, TextureCopyView},
|
||||
id,
|
||||
};
|
||||
use std::{io::Write as _, ops::Range};
|
||||
use std::ops::Range;
|
||||
#[cfg(feature = "trace")]
|
||||
use std::io::Write as _;
|
||||
|
||||
//TODO: consider a readable Id that doesn't include the backend
|
||||
|
||||
type FileName = String;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub const FILE_NAME: &str = "trace.ron";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub enum BindingResource {
|
||||
Buffer {
|
||||
id: id::BufferId,
|
||||
@ -22,8 +29,10 @@ pub enum BindingResource {
|
||||
TextureView(id::TextureViewId),
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub(crate) enum Action {
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub enum Action {
|
||||
Init {
|
||||
limits: wgt::Limits,
|
||||
},
|
||||
@ -88,8 +97,10 @@ pub(crate) enum Action {
|
||||
Submit(Vec<Command>),
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub(crate) enum Command {
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub enum Command {
|
||||
CopyBufferToBuffer {
|
||||
src: id::BufferId,
|
||||
src_offset: wgt::BufferAddress,
|
||||
@ -124,6 +135,7 @@ pub(crate) enum Command {
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[derive(Debug)]
|
||||
pub struct Trace {
|
||||
path: std::path::PathBuf,
|
||||
@ -132,10 +144,11 @@ pub struct Trace {
|
||||
binary_id: usize,
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
impl Trace {
|
||||
pub fn new(path: &std::path::Path) -> Result<Self, std::io::Error> {
|
||||
log::info!("Tracing into '{:?}'", path);
|
||||
let mut file = std::fs::File::create(path.join("trace.ron"))?;
|
||||
let mut file = std::fs::File::create(path.join(FILE_NAME))?;
|
||||
file.write(b"[\n")?;
|
||||
Ok(Trace {
|
||||
path: path.to_path_buf(),
|
||||
@ -164,6 +177,7 @@ impl Trace {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
impl Drop for Trace {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.file.write(b"]");
|
||||
|
@ -25,7 +25,7 @@ use wgt::Backend;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use std::cell::Cell;
|
||||
use std::{fmt::Debug, iter, marker::PhantomData, ops};
|
||||
use std::{fmt::Debug, marker::PhantomData, ops};
|
||||
|
||||
/// A simple structure to manage identities of objects.
|
||||
#[derive(Debug)]
|
||||
@ -44,6 +44,13 @@ impl Default for IdentityManager {
|
||||
}
|
||||
|
||||
impl IdentityManager {
|
||||
pub fn from_index(min_index: u32) -> Self {
|
||||
IdentityManager {
|
||||
free: (0 .. min_index).collect(),
|
||||
epochs: vec![1; min_index as usize],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc<I: TypedId>(&mut self, backend: Backend) -> I {
|
||||
match self.free.pop() {
|
||||
Some(index) => I::zip(index, self.epochs[index as usize], backend),
|
||||
@ -262,10 +269,7 @@ pub struct IdentityManagerFactory;
|
||||
impl<I: TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
|
||||
type Filter = Mutex<IdentityManager>;
|
||||
fn spawn(&self, min_index: Index) -> Self::Filter {
|
||||
let mut man = IdentityManager::default();
|
||||
man.free.extend(0..min_index);
|
||||
man.epochs.extend(iter::repeat(1).take(min_index as usize));
|
||||
Mutex::new(man)
|
||||
Mutex::new(IdentityManager::from_index(min_index))
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,6 +553,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
|
||||
fn drop(&mut self) {
|
||||
log::info!("Dropping Global");
|
||||
// destroy surfaces
|
||||
for (_, (surface, _)) in self.surfaces.data.write().map.drain() {
|
||||
self.instance.destroy_surface(surface);
|
||||
|
@ -188,7 +188,7 @@ impl From<HalDeviceType> for DeviceType {
|
||||
|
||||
pub enum AdapterInputs<'a, I> {
|
||||
IdSet(&'a [I], fn(&I) -> Backend),
|
||||
Mask(BackendBit, fn() -> I),
|
||||
Mask(BackendBit, fn(Backend) -> I),
|
||||
}
|
||||
|
||||
impl<I: Clone> AdapterInputs<'_, I> {
|
||||
@ -197,7 +197,7 @@ impl<I: Clone> AdapterInputs<'_, I> {
|
||||
AdapterInputs::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).cloned(),
|
||||
AdapterInputs::Mask(bits, ref fun) => {
|
||||
if bits.contains(b.into()) {
|
||||
Some(fun())
|
||||
Some(fun(b))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -207,6 +207,85 @@ impl<I: Clone> AdapterInputs<'_, I> {
|
||||
}
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
#[cfg(feature = "raw-window-handle")]
|
||||
pub fn instance_create_surface<W: raw_window_handle::HasRawWindowHandle>(
|
||||
&self,
|
||||
window: &W,
|
||||
id_in: Input<G, SurfaceId>,
|
||||
) -> SurfaceId {
|
||||
use raw_window_handle::RawWindowHandle as Rwh;
|
||||
|
||||
let surface = match window.raw_window_handle() {
|
||||
#[cfg(target_os = "ios")]
|
||||
Rwh::IOS(h) => Surface {
|
||||
#[cfg(feature = "gfx-backend-vulkan")]
|
||||
vulkan: None,
|
||||
metal: self
|
||||
.instance
|
||||
.metal
|
||||
.create_surface_from_uiview(h.ui_view, cfg!(debug_assertions)),
|
||||
},
|
||||
#[cfg(target_os = "macos")]
|
||||
Rwh::MacOS(h) => {
|
||||
//TODO: figure out when this is needed, and how to get that without `objc`
|
||||
//use objc::{msg_send, runtime::Object, sel, sel_impl};
|
||||
//let ns_view = if h.ns_view.is_null() {
|
||||
// let ns_window = h.ns_window as *mut Object;
|
||||
// unsafe { msg_send![ns_window, contentView] }
|
||||
//} else {
|
||||
// h.ns_view
|
||||
//};
|
||||
Surface {
|
||||
#[cfg(feature = "gfx-backend-vulkan")]
|
||||
vulkan: self
|
||||
.instance
|
||||
.vulkan
|
||||
.as_ref()
|
||||
.map(|inst| inst.create_surface_from_ns_view(h.ns_view)),
|
||||
metal: self
|
||||
.instance
|
||||
.metal
|
||||
.create_surface_from_nsview(h.ns_view, cfg!(debug_assertions)),
|
||||
}
|
||||
}
|
||||
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
|
||||
Rwh::Xlib(h) => Surface {
|
||||
vulkan: self
|
||||
.instance
|
||||
.vulkan
|
||||
.as_ref()
|
||||
.map(|inst| inst.create_surface_from_xlib(h.display as _, h.window as _)),
|
||||
},
|
||||
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
|
||||
Rwh::Wayland(h) => Surface {
|
||||
vulkan: self
|
||||
.instance
|
||||
.vulkan
|
||||
.as_ref()
|
||||
.map(|inst| inst.create_surface_from_wayland(h.display, h.surface)),
|
||||
},
|
||||
#[cfg(windows)]
|
||||
Rwh::Windows(h) => Surface {
|
||||
vulkan: self
|
||||
.instance
|
||||
.vulkan
|
||||
.as_ref()
|
||||
.map(|inst| inst.create_surface_from_hwnd(std::ptr::null_mut(), h.hwnd)),
|
||||
dx12: self
|
||||
.instance
|
||||
.dx12
|
||||
.as_ref()
|
||||
.map(|inst| inst.create_surface_from_hwnd(h.hwnd)),
|
||||
dx11: self.instance.dx11.create_surface_from_hwnd(h.hwnd),
|
||||
},
|
||||
_ => panic!("Unsupported window handle"),
|
||||
};
|
||||
|
||||
let mut token = Token::root();
|
||||
self.surfaces
|
||||
.register_identity(id_in, surface, &mut token)
|
||||
}
|
||||
|
||||
pub fn enumerate_adapters(&self, inputs: AdapterInputs<Input<G, AdapterId>>) -> Vec<AdapterId> {
|
||||
let instance = &self.instance;
|
||||
let mut token = Token::root();
|
||||
|
Loading…
Reference in New Issue
Block a user