mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
hal: renderdoc integration
This commit is contained in:
committed by
Dzmitry Malyshau
parent
0a81cb08bf
commit
509b683e6b
@@ -54,10 +54,10 @@ hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["metal"] }
|
||||
#Note: could also enable "vulkan" for Vulkan Portability
|
||||
|
||||
[target.'cfg(all(not(target_arch = "wasm32"), unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
|
||||
hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan", "gles"] }
|
||||
hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan", "gles", "renderdoc"] }
|
||||
|
||||
[target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies]
|
||||
hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan", "dx12"] }
|
||||
hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan", "dx12", "renderdoc"] }
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases = "0.1"
|
||||
|
||||
@@ -2268,7 +2268,7 @@ impl<A: HalApi> Device<A> {
|
||||
}
|
||||
hal::PipelineError::EntryPoint(stage) => {
|
||||
pipeline::CreateRenderPipelineError::Internal {
|
||||
stage: hal::util::map_naga_stage(stage),
|
||||
stage: hal::auxil::map_naga_stage(stage),
|
||||
error: EP_FAILURE.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ license = "MIT OR Apache-2.0"
|
||||
[features]
|
||||
default = []
|
||||
metal = ["naga/msl-out", "block", "foreign-types"]
|
||||
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it", "renderdoc-sys"]
|
||||
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it"]
|
||||
gles = ["naga/glsl-out", "glow", "egl", "libloading"]
|
||||
dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"]
|
||||
renderdoc = ["libloading", "renderdoc-sys"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
@@ -29,17 +30,21 @@ wgt = { package = "wgpu-types", path = "../wgpu-types" }
|
||||
arrayvec = "0.7"
|
||||
fxhash = "0.2.1"
|
||||
log = "0.4"
|
||||
renderdoc-sys = { version = "0.7.1", optional = true }
|
||||
|
||||
# backend: Metal
|
||||
block = { version = "0.1", optional = true }
|
||||
foreign-types = { version = "0.3", optional = true }
|
||||
|
||||
# backend: Vulkan
|
||||
ash = { version = "0.32", optional = true }
|
||||
gpu-alloc = { version = "0.4", optional = true }
|
||||
gpu-descriptor = { version = "0.1", optional = true }
|
||||
inplace_it = { version ="0.3.3", optional = true }
|
||||
renderdoc-sys = { version = "0.7.1", optional = true }
|
||||
|
||||
# backend: Gles
|
||||
glow = { git = "https://github.com/grovesNL/glow", rev = "0864897a28bbdd43f89f4fd8fdd4ed781b719f8a", optional = true }
|
||||
|
||||
# backend: Dx12
|
||||
bit-set = { version = "0.5", optional = true }
|
||||
native = { package = "d3d12", version = "0.4", features = ["libloading"], optional = true }
|
||||
@@ -47,6 +52,7 @@ range-alloc = { version = "0.1", optional = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true }
|
||||
#Note: it's only unused on Apple platforms
|
||||
libloading = { version = "0.7", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#[cfg(feature = "renderdoc")]
|
||||
pub(super) mod renderdoc;
|
||||
|
||||
pub mod db {
|
||||
pub mod intel {
|
||||
pub const VENDOR: u32 = 0x8086;
|
||||
122
wgpu-hal/src/auxil/renderdoc.rs
Normal file
122
wgpu-hal/src/auxil/renderdoc.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
//! RenderDoc integration - <https://renderdoc.org/>
|
||||
|
||||
use std::{ffi, os, ptr};
|
||||
|
||||
/// The dynamically loaded RenderDoc API function table
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct RenderDocApi {
|
||||
api: renderdoc_sys::RENDERDOC_API_1_4_1,
|
||||
lib: libloading::Library,
|
||||
}
|
||||
|
||||
unsafe impl Send for RenderDocApi {}
|
||||
unsafe impl Sync for RenderDocApi {}
|
||||
|
||||
/// RenderDoc API type
|
||||
#[derive(Debug)]
|
||||
pub enum RenderDoc {
|
||||
/// RenderDoc functionality is available
|
||||
Available {
|
||||
/// RenderDoc API with function pointers
|
||||
api: RenderDocApi,
|
||||
},
|
||||
/// RenderDoc functionality is _not_ available
|
||||
NotAvailable {
|
||||
/// A description why renderdoc functionality is not available
|
||||
reason: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl RenderDoc {
|
||||
pub unsafe fn new() -> Self {
|
||||
type GetApiFn = unsafe extern "C" fn(version: u32, out: *mut *mut ffi::c_void) -> i32;
|
||||
|
||||
#[cfg(windows)]
|
||||
let renderdoc_filename = "renderdoc.dll";
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
let renderdoc_filename = "librenderdoc.so";
|
||||
#[cfg(target_os = "android")]
|
||||
let renderdoc_filename = "libVkLayer_GLES_RenderDoc.so";
|
||||
|
||||
let renderdoc_lib = match libloading::Library::new(renderdoc_filename) {
|
||||
Ok(lib) => lib,
|
||||
Err(e) => {
|
||||
return RenderDoc::NotAvailable {
|
||||
reason: format!(
|
||||
"Unable to load renderdoc library '{}': {:?}",
|
||||
renderdoc_filename, e
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let get_api: libloading::Symbol<GetApiFn> = match renderdoc_lib.get(b"RENDERDOC_GetAPI\0") {
|
||||
Ok(api) => api,
|
||||
Err(e) => {
|
||||
return RenderDoc::NotAvailable {
|
||||
reason: format!(
|
||||
"Unable to get RENDERDOC_GetAPI from renderdoc library '{}': {:?}",
|
||||
renderdoc_filename, e
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut obj = ptr::null_mut();
|
||||
match get_api(10401, &mut obj) {
|
||||
1 => RenderDoc::Available {
|
||||
api: RenderDocApi {
|
||||
api: *(obj as *mut renderdoc_sys::RENDERDOC_API_1_4_1),
|
||||
lib: renderdoc_lib,
|
||||
},
|
||||
},
|
||||
return_value => RenderDoc::NotAvailable {
|
||||
reason: format!(
|
||||
"Unable to get API from renderdoc library '{}': {}",
|
||||
renderdoc_filename, return_value
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RenderDoc {
|
||||
fn default() -> Self {
|
||||
if !cfg!(debug_assertions) {
|
||||
return RenderDoc::NotAvailable {
|
||||
reason: "RenderDoc support is only enabled with 'debug_assertions'".into(),
|
||||
};
|
||||
}
|
||||
unsafe { Self::new() }
|
||||
}
|
||||
}
|
||||
/// A implementation specific handle
|
||||
pub type Handle = *mut os::raw::c_void;
|
||||
|
||||
impl RenderDoc {
|
||||
/// Start a RenderDoc frame capture
|
||||
pub unsafe fn start_frame_capture(&self, device_handle: Handle, window_handle: Handle) -> bool {
|
||||
match *self {
|
||||
Self::Available { api: ref entry } => {
|
||||
entry.api.StartFrameCapture.unwrap()(device_handle, window_handle);
|
||||
true
|
||||
}
|
||||
Self::NotAvailable { ref reason } => {
|
||||
log::warn!("Could not start RenderDoc frame capture: {}", reason);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// End a RenderDoc frame capture
|
||||
pub unsafe fn end_frame_capture(&self, device_handle: Handle, window_handle: Handle) {
|
||||
match *self {
|
||||
Self::Available { api: ref entry } => {
|
||||
entry.api.EndFrameCapture.unwrap()(device_handle, window_handle);
|
||||
}
|
||||
Self::NotAvailable { ref reason } => {
|
||||
log::warn!("Could not end RenderDoc frame capture: {}", reason)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -147,6 +147,8 @@ impl super::Device {
|
||||
native::DescriptorHeapType::Sampler,
|
||||
)),
|
||||
library: Arc::clone(library),
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -522,7 +524,7 @@ impl super::Device {
|
||||
) -> Result<native::Blob, crate::PipelineError> {
|
||||
use naga::back::hlsl;
|
||||
|
||||
let stage_bit = crate::util::map_naga_stage(naga_stage);
|
||||
let stage_bit = crate::auxil::map_naga_stage(naga_stage);
|
||||
let module = &stage.module.naga.module;
|
||||
//TODO: reuse the writer
|
||||
let mut source = String::new();
|
||||
@@ -1664,7 +1666,18 @@ impl crate::Device<super::Api> for super::Device {
|
||||
}
|
||||
|
||||
unsafe fn start_capture(&self) -> bool {
|
||||
#[cfg(feature = "renderdoc")]
|
||||
{
|
||||
self.render_doc
|
||||
.start_frame_capture(self.raw.as_mut_ptr() as *mut _, ptr::null_mut())
|
||||
}
|
||||
#[cfg(not(feature = "renderdoc"))]
|
||||
false
|
||||
}
|
||||
unsafe fn stop_capture(&self) {}
|
||||
|
||||
unsafe fn stop_capture(&self) {
|
||||
#[cfg(feature = "renderdoc")]
|
||||
self.render_doc
|
||||
.end_frame_capture(self.raw.as_mut_ptr() as *mut _, ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,8 @@ pub struct Device {
|
||||
sampler_pool: Mutex<descriptor::CpuPool>,
|
||||
// library
|
||||
library: Arc<native::D3D12Lib>,
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: crate::auxil::renderdoc::RenderDoc,
|
||||
}
|
||||
|
||||
unsafe impl Send for Device {}
|
||||
|
||||
@@ -353,6 +353,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
device: super::Device {
|
||||
shared: Arc::clone(&self.shared),
|
||||
main_vao,
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: Default::default(),
|
||||
},
|
||||
queue: super::Queue {
|
||||
shared: Arc::clone(&self.shared),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::conv;
|
||||
use crate::util::map_naga_stage;
|
||||
use crate::auxil::map_naga_stage;
|
||||
use glow::HasContext;
|
||||
use std::{convert::TryInto, iter, ptr::NonNull, sync::Arc};
|
||||
use std::{convert::TryInto, iter, ptr, sync::Arc};
|
||||
|
||||
type ShaderStage<'a> = (
|
||||
naga::ShaderStage,
|
||||
@@ -378,7 +378,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
gl.bind_buffer(buffer.target, None);
|
||||
|
||||
Ok(crate::BufferMapping {
|
||||
ptr: NonNull::new(ptr).ok_or(crate::DeviceError::Lost)?,
|
||||
ptr: ptr::NonNull::new(ptr).ok_or(crate::DeviceError::Lost)?,
|
||||
is_coherent,
|
||||
})
|
||||
}
|
||||
@@ -1017,7 +1017,18 @@ impl crate::Device<super::Api> for super::Device {
|
||||
}
|
||||
|
||||
unsafe fn start_capture(&self) -> bool {
|
||||
#[cfg(feature = "renderdoc")]
|
||||
{
|
||||
//Note: it doesn't look like the device pointer is used by RD
|
||||
self.render_doc
|
||||
.start_frame_capture(ptr::null_mut(), ptr::null_mut())
|
||||
}
|
||||
#[cfg(not(feature = "renderdoc"))]
|
||||
false
|
||||
}
|
||||
unsafe fn stop_capture(&self) {}
|
||||
unsafe fn stop_capture(&self) {
|
||||
#[cfg(feature = "renderdoc")]
|
||||
self.render_doc
|
||||
.end_frame_capture(ptr::null_mut(), ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,8 @@ pub struct Adapter {
|
||||
pub struct Device {
|
||||
shared: Arc<AdapterShared>,
|
||||
main_vao: glow::VertexArray,
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: crate::auxil::renderdoc::RenderDoc,
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
|
||||
@@ -56,7 +56,7 @@ mod metal;
|
||||
#[cfg(feature = "vulkan")]
|
||||
mod vulkan;
|
||||
|
||||
pub mod util;
|
||||
pub mod auxil;
|
||||
pub mod api {
|
||||
#[cfg(feature = "dx12")]
|
||||
pub use super::dx12::Api as Dx12;
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
use super::conv;
|
||||
use crate::util::map_naga_stage;
|
||||
use crate::auxil::map_naga_stage;
|
||||
|
||||
type DeviceResult<T> = Result<T, crate::DeviceError>;
|
||||
|
||||
|
||||
@@ -618,7 +618,7 @@ impl super::Instance {
|
||||
|
||||
let (available_features, downlevel_flags) = phd_features.to_wgpu(&phd_capabilities);
|
||||
{
|
||||
use crate::util::db;
|
||||
use crate::auxil::db;
|
||||
// see https://github.com/gfx-rs/gfx/issues/1930
|
||||
let _is_windows_intel_dual_src_bug = cfg!(windows)
|
||||
&& phd_capabilities.properties.vendor_id == db::intel::VENDOR
|
||||
@@ -897,6 +897,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
desc_allocator: Mutex::new(desc_allocator),
|
||||
valid_ash_memory_types,
|
||||
naga_options,
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: Default::default(),
|
||||
};
|
||||
|
||||
Ok(crate::OpenDevice { device, queue })
|
||||
|
||||
@@ -1501,9 +1501,23 @@ impl crate::Device<super::Api> for super::Device {
|
||||
}
|
||||
|
||||
unsafe fn start_capture(&self) -> bool {
|
||||
#[cfg(feature = "renderdoc")]
|
||||
{
|
||||
self.render_doc.start_frame_capture(
|
||||
ash::vk::Handle::as_raw(self.shared.raw.handle()) as *mut _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
}
|
||||
#[cfg(not(feature = "renderdoc"))]
|
||||
false
|
||||
}
|
||||
unsafe fn stop_capture(&self) {}
|
||||
unsafe fn stop_capture(&self) {
|
||||
#[cfg(feature = "renderdoc")]
|
||||
self.render_doc.end_frame_capture(
|
||||
ash::vk::Handle::as_raw(self.shared.raw.handle()) as *mut _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<gpu_alloc::AllocationError> for crate::DeviceError {
|
||||
|
||||
@@ -626,7 +626,7 @@ impl crate::Surface<super::Api> for super::Surface {
|
||||
};
|
||||
|
||||
// special case for Intel Vulkan returning bizzare values (ugh)
|
||||
if sc.device.vendor_id == crate::util::db::intel::VENDOR && index > 0x100 {
|
||||
if sc.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
|
||||
return Err(crate::SurfaceError::Outdated);
|
||||
}
|
||||
|
||||
|
||||
@@ -231,6 +231,8 @@ pub struct Device {
|
||||
Mutex<gpu_descriptor::DescriptorAllocator<vk::DescriptorPool, vk::DescriptorSet>>,
|
||||
valid_ash_memory_types: u32,
|
||||
naga_options: naga::back::spv::Options,
|
||||
#[cfg(feature = "renderdoc")]
|
||||
render_doc: crate::auxil::renderdoc::RenderDoc,
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
|
||||
Reference in New Issue
Block a user