mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 16:24:24 +00:00
trace: player skeleton
This commit is contained in:
parent
622d9ecc74
commit
47f37ad78e
@ -1,5 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"player",
|
||||||
"wgpu-core",
|
"wgpu-core",
|
||||||
"wgpu-types",
|
"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"
|
gfx-memory = "0.1"
|
||||||
parking_lot = "0.10"
|
parking_lot = "0.10"
|
||||||
peek-poke = "0.2"
|
peek-poke = "0.2"
|
||||||
|
raw-window-handle = { version = "0.3", optional = true }
|
||||||
ron = { version = "0.5", optional = true }
|
ron = { version = "0.5", optional = true }
|
||||||
serde = { version = "1.0", features = ["serde_derive"], optional = true }
|
serde = { version = "1.0", features = ["serde_derive"], optional = true }
|
||||||
smallvec = "1"
|
smallvec = "1"
|
||||||
|
@ -28,7 +28,7 @@ enum PipelineState {
|
|||||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||||
pub(crate) enum ComputeCommand {
|
pub enum ComputeCommand {
|
||||||
SetBindGroup {
|
SetBindGroup {
|
||||||
index: u8,
|
index: u8,
|
||||||
num_dynamic_offsets: u8,
|
num_dynamic_offsets: u8,
|
||||||
|
@ -27,7 +27,7 @@ use peek_poke::PeekPoke;
|
|||||||
use std::{marker::PhantomData, mem, ptr, slice, thread::ThreadId};
|
use std::{marker::PhantomData, mem, ptr, slice, thread::ThreadId};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||||
pub(crate) struct PhantomSlice<T>(PhantomData<T>);
|
pub struct PhantomSlice<T>(PhantomData<T>);
|
||||||
|
|
||||||
impl<T> Default for PhantomSlice<T> {
|
impl<T> Default for PhantomSlice<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -58,7 +58,7 @@ pub struct Rect<T> {
|
|||||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||||
pub(crate) enum RenderCommand {
|
pub enum RenderCommand {
|
||||||
SetBindGroup {
|
SetBindGroup {
|
||||||
index: u8,
|
index: u8,
|
||||||
num_dynamic_offsets: u8,
|
num_dynamic_offsets: u8,
|
||||||
|
@ -31,8 +31,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod life;
|
mod life;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(any(feature = "trace", feature = "replay"))]
|
||||||
pub(crate) mod trace;
|
pub mod trace;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use trace::{Action, Trace};
|
use trace::{Action, Trace};
|
||||||
|
|
||||||
|
@ -6,12 +6,19 @@ use crate::{
|
|||||||
command::{BufferCopyView, TextureCopyView},
|
command::{BufferCopyView, TextureCopyView},
|
||||||
id,
|
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
|
//TODO: consider a readable Id that doesn't include the backend
|
||||||
|
|
||||||
type FileName = String;
|
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 {
|
pub enum BindingResource {
|
||||||
Buffer {
|
Buffer {
|
||||||
id: id::BufferId,
|
id: id::BufferId,
|
||||||
@ -22,8 +29,10 @@ pub enum BindingResource {
|
|||||||
TextureView(id::TextureViewId),
|
TextureView(id::TextureViewId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Action {
|
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||||
|
pub enum Action {
|
||||||
Init {
|
Init {
|
||||||
limits: wgt::Limits,
|
limits: wgt::Limits,
|
||||||
},
|
},
|
||||||
@ -88,8 +97,10 @@ pub(crate) enum Action {
|
|||||||
Submit(Vec<Command>),
|
Submit(Vec<Command>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Command {
|
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||||
|
pub enum Command {
|
||||||
CopyBufferToBuffer {
|
CopyBufferToBuffer {
|
||||||
src: id::BufferId,
|
src: id::BufferId,
|
||||||
src_offset: wgt::BufferAddress,
|
src_offset: wgt::BufferAddress,
|
||||||
@ -124,6 +135,7 @@ pub(crate) enum Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Trace {
|
pub struct Trace {
|
||||||
path: std::path::PathBuf,
|
path: std::path::PathBuf,
|
||||||
@ -132,10 +144,11 @@ pub struct Trace {
|
|||||||
binary_id: usize,
|
binary_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
impl Trace {
|
impl Trace {
|
||||||
pub fn new(path: &std::path::Path) -> Result<Self, std::io::Error> {
|
pub fn new(path: &std::path::Path) -> Result<Self, std::io::Error> {
|
||||||
log::info!("Tracing into '{:?}'", path);
|
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")?;
|
file.write(b"[\n")?;
|
||||||
Ok(Trace {
|
Ok(Trace {
|
||||||
path: path.to_path_buf(),
|
path: path.to_path_buf(),
|
||||||
@ -164,6 +177,7 @@ impl Trace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
impl Drop for Trace {
|
impl Drop for Trace {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.file.write(b"]");
|
let _ = self.file.write(b"]");
|
||||||
|
@ -25,7 +25,7 @@ use wgt::Backend;
|
|||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use std::cell::Cell;
|
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.
|
/// A simple structure to manage identities of objects.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -44,6 +44,13 @@ impl Default for IdentityManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn alloc<I: TypedId>(&mut self, backend: Backend) -> I {
|
||||||
match self.free.pop() {
|
match self.free.pop() {
|
||||||
Some(index) => I::zip(index, self.epochs[index as usize], backend),
|
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 {
|
impl<I: TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
|
||||||
type Filter = Mutex<IdentityManager>;
|
type Filter = Mutex<IdentityManager>;
|
||||||
fn spawn(&self, min_index: Index) -> Self::Filter {
|
fn spawn(&self, min_index: Index) -> Self::Filter {
|
||||||
let mut man = IdentityManager::default();
|
Mutex::new(IdentityManager::from_index(min_index))
|
||||||
man.free.extend(0..min_index);
|
|
||||||
man.epochs.extend(iter::repeat(1).take(min_index as usize));
|
|
||||||
Mutex::new(man)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +553,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
|
|
||||||
impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
|
impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
log::info!("Dropping Global");
|
||||||
// destroy surfaces
|
// destroy surfaces
|
||||||
for (_, (surface, _)) in self.surfaces.data.write().map.drain() {
|
for (_, (surface, _)) in self.surfaces.data.write().map.drain() {
|
||||||
self.instance.destroy_surface(surface);
|
self.instance.destroy_surface(surface);
|
||||||
|
@ -188,7 +188,7 @@ impl From<HalDeviceType> for DeviceType {
|
|||||||
|
|
||||||
pub enum AdapterInputs<'a, I> {
|
pub enum AdapterInputs<'a, I> {
|
||||||
IdSet(&'a [I], fn(&I) -> Backend),
|
IdSet(&'a [I], fn(&I) -> Backend),
|
||||||
Mask(BackendBit, fn() -> I),
|
Mask(BackendBit, fn(Backend) -> I),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Clone> AdapterInputs<'_, 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::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).cloned(),
|
||||||
AdapterInputs::Mask(bits, ref fun) => {
|
AdapterInputs::Mask(bits, ref fun) => {
|
||||||
if bits.contains(b.into()) {
|
if bits.contains(b.into()) {
|
||||||
Some(fun())
|
Some(fun(b))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -207,6 +207,85 @@ impl<I: Clone> AdapterInputs<'_, I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
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> {
|
pub fn enumerate_adapters(&self, inputs: AdapterInputs<Input<G, AdapterId>>) -> Vec<AdapterId> {
|
||||||
let instance = &self.instance;
|
let instance = &self.instance;
|
||||||
let mut token = Token::root();
|
let mut token = Token::root();
|
||||||
|
Loading…
Reference in New Issue
Block a user