hal: renderdoc integration

This commit is contained in:
Dzmitry Malyshau
2021-07-14 12:40:01 -04:00
committed by Dzmitry Malyshau
parent 0a81cb08bf
commit 509b683e6b
16 changed files with 195 additions and 16 deletions

View File

@@ -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"

View File

@@ -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(),
}
}

View File

@@ -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]

View File

@@ -1,3 +1,6 @@
#[cfg(feature = "renderdoc")]
pub(super) mod renderdoc;
pub mod db {
pub mod intel {
pub const VENDOR: u32 = 0x8086;

View 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)
}
};
}
}

View File

@@ -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())
}
}

View File

@@ -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 {}

View File

@@ -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),

View File

@@ -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())
}
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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>;

View File

@@ -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 })

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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 {