Dx11 Backend (#2443)

This commit is contained in:
Connor Fitzgerald 2022-03-12 12:14:18 -05:00 committed by GitHub
parent c314c55788
commit 73f42352f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1754 additions and 476 deletions

3
Cargo.lock generated
View File

@ -436,8 +436,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "d3d12"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c"
source = "git+https://github.com/gfx-rs/d3d12-rs.git?rev=ffe5e261da0a6cb85332b82ab310abd2a7e849f6#ffe5e261da0a6cb85332b82ab310abd2a7e849f6"
dependencies = [
"bitflags",
"libloading",

View File

@ -28,6 +28,7 @@ default-members = ["wgpu", "wgpu-hal", "wgpu-info"]
[patch.crates-io]
#naga = { path = "../naga" }
#glow = { path = "../glow" }
#d3d12 = { path = "../d3d12-rs" }
#metal = { path = "../metal-rs" }
#web-sys = { path = "../wasm-bindgen/crates/web-sys" }
#js-sys = { path = "../wasm-bindgen/crates/js-sys" }

View File

@ -65,7 +65,7 @@ hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.12", features =
hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.12", features = ["vulkan", "gles", "renderdoc"] }
[target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies]
hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.12", features = ["vulkan", "dx12", "renderdoc"] }
hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.12", features = ["vulkan", "dx12", "dx11", "renderdoc"] }
[target.'cfg(target_os = "emscripten")'.dependencies]
hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.12", features = ["emscripten"] }

View File

@ -10,7 +10,7 @@ fn main() {
vulkan: { all(not(wasm), any(windows, unix_wo_apple, feature = "vulkan-portability")) },
metal: { all(not(wasm), apple) },
dx12: { all(not(wasm), windows) },
dx11: { all(false, not(wasm), windows) },
dx11: { all(not(wasm), windows) },
gl: {
any(
unix_wo_apple,

View File

@ -1042,10 +1042,16 @@ impl HalApi for hal::api::Dx12 {
}
}
/*
#[cfg(dx11)]
impl HalApi for hal::api::Dx11 {
const VARIANT: Backend = Backend::Dx11;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
dx11: Some(hal_instance),
..Default::default()
}
}
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.dx11
}
@ -1056,7 +1062,6 @@ impl HalApi for hal::api::Dx11 {
surface.dx11.as_mut().unwrap()
}
}
*/
#[cfg(gl)]
impl HalApi for hal::api::Gles {

View File

@ -508,6 +508,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
dx12: self.instance.dx12.as_ref().map(|inst| HalSurface {
raw: { inst.create_surface_from_visual(visual as _) },
}),
dx11: None,
#[cfg(gl)]
gl: None,
};

View File

@ -211,8 +211,8 @@ macro_rules! gfx_select {
wgt::Backend::Metal => $global.$method::<$crate::api::Metal>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), windows))]
wgt::Backend::Dx12 => $global.$method::<$crate::api::Dx12>( $($param),* ),
//#[cfg(all(not(target_arch = "wasm32"), windows))]
//wgt::Backend::Dx11 => $global.$method::<$crate::api::Dx11>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), windows))]
wgt::Backend::Dx11 => $global.$method::<$crate::api::Dx11>( $($param),* ),
#[cfg(any(
all(unix, not(target_os = "macos"), not(target_os = "ios")),
feature = "angle",

View File

@ -16,6 +16,7 @@ default = []
metal = ["naga/msl-out", "block", "foreign-types"]
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it"]
gles = ["naga/glsl-out", "glow", "egl", "libloading"]
dx11 = ["naga/hlsl-out", "native", "libloading", "winapi/d3d11", "winapi/d3d11_1", "winapi/d3d11_2", "winapi/d3d11sdklayers", "winapi/dxgi1_6"]
dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"]
renderdoc = ["libloading", "renderdoc-sys"]
emscripten = ["gles"]
@ -74,7 +75,8 @@ libloading = { version = "0.7", optional = true }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser", "dcomp"] }
native = { package = "d3d12", version = "0.4.1", features = ["libloading"], optional = true }
# native = { package = "d3d12", version = "0.4.1", features = ["libloading"], optional = true }
native = { package = "d3d12", git = "https://github.com/gfx-rs/d3d12-rs.git", rev = "ffe5e261da0a6cb85332b82ab310abd2a7e849f6", features = ["libloading"], optional = true }
[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
mtl = { package = "metal", git = "https://github.com/gfx-rs/metal-rs", rev = "a357159" }

View File

@ -0,0 +1,175 @@
use winapi::shared::dxgiformat;
pub fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
use wgt::TextureFormat as Tf;
use winapi::shared::dxgiformat::*;
match format {
Tf::R8Unorm => DXGI_FORMAT_R8_UNORM,
Tf::R8Snorm => DXGI_FORMAT_R8_SNORM,
Tf::R8Uint => DXGI_FORMAT_R8_UINT,
Tf::R8Sint => DXGI_FORMAT_R8_SINT,
Tf::R16Uint => DXGI_FORMAT_R16_UINT,
Tf::R16Sint => DXGI_FORMAT_R16_SINT,
Tf::R16Unorm => DXGI_FORMAT_R16_UNORM,
Tf::R16Snorm => DXGI_FORMAT_R16_SNORM,
Tf::R16Float => DXGI_FORMAT_R16_FLOAT,
Tf::Rg8Unorm => DXGI_FORMAT_R8G8_UNORM,
Tf::Rg8Snorm => DXGI_FORMAT_R8G8_SNORM,
Tf::Rg8Uint => DXGI_FORMAT_R8G8_UINT,
Tf::Rg8Sint => DXGI_FORMAT_R8G8_SINT,
Tf::Rg16Unorm => DXGI_FORMAT_R16G16_UNORM,
Tf::Rg16Snorm => DXGI_FORMAT_R16G16_SNORM,
Tf::R32Uint => DXGI_FORMAT_R32_UINT,
Tf::R32Sint => DXGI_FORMAT_R32_SINT,
Tf::R32Float => DXGI_FORMAT_R32_FLOAT,
Tf::Rg16Uint => DXGI_FORMAT_R16G16_UINT,
Tf::Rg16Sint => DXGI_FORMAT_R16G16_SINT,
Tf::Rg16Float => DXGI_FORMAT_R16G16_FLOAT,
Tf::Rgba8Unorm => DXGI_FORMAT_R8G8B8A8_UNORM,
Tf::Rgba8UnormSrgb => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
Tf::Bgra8UnormSrgb => DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
Tf::Rgba8Snorm => DXGI_FORMAT_R8G8B8A8_SNORM,
Tf::Bgra8Unorm => DXGI_FORMAT_B8G8R8A8_UNORM,
Tf::Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT,
Tf::Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT,
Tf::Rgb10a2Unorm => DXGI_FORMAT_R10G10B10A2_UNORM,
Tf::Rg11b10Float => DXGI_FORMAT_R11G11B10_FLOAT,
Tf::Rg32Uint => DXGI_FORMAT_R32G32_UINT,
Tf::Rg32Sint => DXGI_FORMAT_R32G32_SINT,
Tf::Rg32Float => DXGI_FORMAT_R32G32_FLOAT,
Tf::Rgba16Uint => DXGI_FORMAT_R16G16B16A16_UINT,
Tf::Rgba16Sint => DXGI_FORMAT_R16G16B16A16_SINT,
Tf::Rgba16Unorm => DXGI_FORMAT_R16G16B16A16_UNORM,
Tf::Rgba16Snorm => DXGI_FORMAT_R16G16B16A16_SNORM,
Tf::Rgba16Float => DXGI_FORMAT_R16G16B16A16_FLOAT,
Tf::Rgba32Uint => DXGI_FORMAT_R32G32B32A32_UINT,
Tf::Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT,
Tf::Rgba32Float => DXGI_FORMAT_R32G32B32A32_FLOAT,
Tf::Depth32Float => DXGI_FORMAT_D32_FLOAT,
Tf::Depth24Plus => DXGI_FORMAT_D24_UNORM_S8_UINT,
Tf::Depth24PlusStencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT,
Tf::Rgb9e5Ufloat => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
Tf::Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM,
Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_UNORM_SRGB,
Tf::Bc2RgbaUnorm => DXGI_FORMAT_BC2_UNORM,
Tf::Bc2RgbaUnormSrgb => DXGI_FORMAT_BC2_UNORM_SRGB,
Tf::Bc3RgbaUnorm => DXGI_FORMAT_BC3_UNORM,
Tf::Bc3RgbaUnormSrgb => DXGI_FORMAT_BC3_UNORM_SRGB,
Tf::Bc4RUnorm => DXGI_FORMAT_BC4_UNORM,
Tf::Bc4RSnorm => DXGI_FORMAT_BC4_SNORM,
Tf::Bc5RgUnorm => DXGI_FORMAT_BC5_UNORM,
Tf::Bc5RgSnorm => DXGI_FORMAT_BC5_SNORM,
Tf::Bc6hRgbUfloat => DXGI_FORMAT_BC6H_UF16,
Tf::Bc6hRgbSfloat => DXGI_FORMAT_BC6H_SF16,
Tf::Bc7RgbaUnorm => DXGI_FORMAT_BC7_UNORM,
Tf::Bc7RgbaUnormSrgb => DXGI_FORMAT_BC7_UNORM_SRGB,
Tf::Etc2Rgb8Unorm
| Tf::Etc2Rgb8UnormSrgb
| Tf::Etc2Rgb8A1Unorm
| Tf::Etc2Rgb8A1UnormSrgb
| Tf::Etc2Rgba8Unorm
| Tf::Etc2Rgba8UnormSrgb
| Tf::EacR11Unorm
| Tf::EacR11Snorm
| Tf::EacRg11Unorm
| Tf::EacRg11Snorm
| Tf::Astc {
block: _,
channel: _,
} => unreachable!(),
}
}
// Note: DXGI doesn't allow sRGB format on the swapchain,
// but creating RTV of swapchain buffers with sRGB works.
pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::TextureFormat::Bgra8UnormSrgb => dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
wgt::TextureFormat::Rgba8UnormSrgb => dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
_ => map_texture_format(format),
}
}
//Note: SRV and UAV can't use the depth formats directly
//TODO: stencil views?
pub fn map_texture_format_nodepth(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::TextureFormat::Depth32Float => dxgiformat::DXGI_FORMAT_R32_FLOAT,
wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8 => {
dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS
}
_ => {
assert_eq!(
crate::FormatAspects::from(format),
crate::FormatAspects::COLOR
);
map_texture_format(format)
}
}
}
pub fn map_texture_format_depth_typeless(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::TextureFormat::Depth32Float => dxgiformat::DXGI_FORMAT_R32_TYPELESS,
wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8 => {
dxgiformat::DXGI_FORMAT_R24G8_TYPELESS
}
_ => unreachable!(),
}
}
pub fn map_index_format(format: wgt::IndexFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::IndexFormat::Uint16 => dxgiformat::DXGI_FORMAT_R16_UINT,
wgt::IndexFormat::Uint32 => dxgiformat::DXGI_FORMAT_R32_UINT,
}
}
pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT {
use wgt::VertexFormat as Vf;
use winapi::shared::dxgiformat::*;
match format {
Vf::Unorm8x2 => DXGI_FORMAT_R8G8_UNORM,
Vf::Snorm8x2 => DXGI_FORMAT_R8G8_SNORM,
Vf::Uint8x2 => DXGI_FORMAT_R8G8_UINT,
Vf::Sint8x2 => DXGI_FORMAT_R8G8_SINT,
Vf::Unorm8x4 => DXGI_FORMAT_R8G8B8A8_UNORM,
Vf::Snorm8x4 => DXGI_FORMAT_R8G8B8A8_SNORM,
Vf::Uint8x4 => DXGI_FORMAT_R8G8B8A8_UINT,
Vf::Sint8x4 => DXGI_FORMAT_R8G8B8A8_SINT,
Vf::Unorm16x2 => DXGI_FORMAT_R16G16_UNORM,
Vf::Snorm16x2 => DXGI_FORMAT_R16G16_SNORM,
Vf::Uint16x2 => DXGI_FORMAT_R16G16_UINT,
Vf::Sint16x2 => DXGI_FORMAT_R16G16_SINT,
Vf::Float16x2 => DXGI_FORMAT_R16G16_FLOAT,
Vf::Unorm16x4 => DXGI_FORMAT_R16G16B16A16_UNORM,
Vf::Snorm16x4 => DXGI_FORMAT_R16G16B16A16_SNORM,
Vf::Uint16x4 => DXGI_FORMAT_R16G16B16A16_UINT,
Vf::Sint16x4 => DXGI_FORMAT_R16G16B16A16_SINT,
Vf::Float16x4 => DXGI_FORMAT_R16G16B16A16_FLOAT,
Vf::Uint32 => DXGI_FORMAT_R32_UINT,
Vf::Sint32 => DXGI_FORMAT_R32_SINT,
Vf::Float32 => DXGI_FORMAT_R32_FLOAT,
Vf::Uint32x2 => DXGI_FORMAT_R32G32_UINT,
Vf::Sint32x2 => DXGI_FORMAT_R32G32_SINT,
Vf::Float32x2 => DXGI_FORMAT_R32G32_FLOAT,
Vf::Uint32x3 => DXGI_FORMAT_R32G32B32_UINT,
Vf::Sint32x3 => DXGI_FORMAT_R32G32B32_SINT,
Vf::Float32x3 => DXGI_FORMAT_R32G32B32_FLOAT,
Vf::Uint32x4 => DXGI_FORMAT_R32G32B32A32_UINT,
Vf::Sint32x4 => DXGI_FORMAT_R32G32B32A32_SINT,
Vf::Float32x4 => DXGI_FORMAT_R32G32B32A32_FLOAT,
Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(),
}
}
pub fn map_acomposite_alpha_mode(mode: crate::CompositeAlphaMode) -> native::AlphaMode {
use crate::CompositeAlphaMode as Cam;
match mode {
Cam::Opaque => native::AlphaMode::Ignore,
Cam::PreMultiplied => native::AlphaMode::Premultiplied,
Cam::PostMultiplied => native::AlphaMode::Straight,
}
}

View File

@ -0,0 +1,98 @@
use std::{borrow::Cow, slice};
use parking_lot::{lock_api::RawMutex, Mutex};
use winapi::{
um::{errhandlingapi, winnt},
vc::excpt,
};
// This is a mutex as opposed to an atomic as we need to completely
// lock everyone out until we have registered or unregistered the
// exception handler, otherwise really nasty races could happen.
//
// By routing all the registration through these functions we can guarentee
// there is either 1 or 0 exception handlers registered, not multiple.
static EXCEPTION_HANLDER_COUNT: Mutex<usize> = Mutex::const_new(parking_lot::RawMutex::INIT, 0);
pub fn register_exception_handler() {
let mut count_guard = EXCEPTION_HANLDER_COUNT.lock();
if *count_guard == 0 {
unsafe {
errhandlingapi::AddVectoredExceptionHandler(0, Some(output_debug_string_handler))
};
}
*count_guard += 1;
}
pub fn unregister_exception_handler() {
let mut count_guard = EXCEPTION_HANLDER_COUNT.lock();
if *count_guard == 1 {
unsafe {
errhandlingapi::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _)
};
}
*count_guard -= 1;
}
const MESSAGE_PREFIXES: &[(&str, log::Level)] = &[
("CORRUPTION", log::Level::Error),
("ERROR", log::Level::Error),
("WARNING", log::Level::Warn),
("INFO", log::Level::Info),
("MESSAGE", log::Level::Debug),
];
unsafe extern "system" fn output_debug_string_handler(
exception_info: *mut winnt::EXCEPTION_POINTERS,
) -> i32 {
// See https://stackoverflow.com/a/41480827
let record = &*(*exception_info).ExceptionRecord;
if record.NumberParameters != 2 {
return excpt::EXCEPTION_CONTINUE_SEARCH;
}
let message = match record.ExceptionCode {
winnt::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(slice::from_raw_parts(
record.ExceptionInformation[1] as *const u8,
record.ExceptionInformation[0],
)),
winnt::DBG_PRINTEXCEPTION_WIDE_C => {
Cow::Owned(String::from_utf16_lossy(slice::from_raw_parts(
record.ExceptionInformation[1] as *const u16,
record.ExceptionInformation[0],
)))
}
_ => return excpt::EXCEPTION_CONTINUE_SEARCH,
};
let message = match message.strip_prefix("D3D12 ") {
Some(msg) => msg
.trim_end_matches("\n\0")
.trim_end_matches("[ STATE_CREATION WARNING #0: UNKNOWN]"),
None => return excpt::EXCEPTION_CONTINUE_SEARCH,
};
let (message, level) = match MESSAGE_PREFIXES
.iter()
.find(|&&(prefix, _)| message.starts_with(prefix))
{
Some(&(prefix, level)) => (&message[prefix.len() + 2..], level),
None => (message, log::Level::Debug),
};
if level == log::Level::Warn && message.contains("#82") {
// This is are useless spammy warnings (#820, #821):
// "The application did not pass any clear value to resource creation"
return excpt::EXCEPTION_CONTINUE_SEARCH;
}
let _ = std::panic::catch_unwind(|| {
log::log!(level, "{}", message);
});
if cfg!(debug_assertions) && level == log::Level::Error {
// Set canary and continue
crate::VALIDATION_CANARY.set();
}
excpt::EXCEPTION_CONTINUE_EXECUTION
}

View File

@ -0,0 +1,210 @@
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, winerror},
Interface,
};
use super::result::HResult as _;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum DxgiFactoryType {
Factory1,
Factory2,
Factory4,
Factory6,
}
pub fn enumerate_adapters(factory: native::DxgiFactory) -> Vec<native::DxgiAdapter> {
let mut adapters = Vec::with_capacity(8);
for cur_index in 0.. {
if let Some(factory6) = factory.as_factory6() {
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
// We're already at dxgi1.6, we can grab IDXGIAdapater4 directly
let mut adapter4 = native::WeakPtr::<dxgi1_6::IDXGIAdapter4>::null();
let hr = unsafe {
factory6.EnumAdapterByGpuPreference(
cur_index,
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&dxgi1_6::IDXGIAdapter4::uuidof(),
adapter4.mut_void(),
)
};
if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
adapters.push(native::DxgiAdapter::Adapter4(adapter4));
continue;
}
profiling::scope!("IDXGIFactory1::EnumAdapters1");
let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
let hr = unsafe { factory.EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _) };
if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
// Do the most aggressive casts first, skipping Adpater4 as we definitely don't have dxgi1_6.
// Adapter1 -> Adapter3
unsafe {
match adapter1.cast::<dxgi1_4::IDXGIAdapter3>().into_result() {
Ok(adapter3) => {
adapter1.destroy();
adapters.push(native::DxgiAdapter::Adapter3(adapter3));
continue;
}
Err(err) => {
log::info!("Failed casting Adapter1 to Adapter3: {}", err);
}
}
}
// Adapter1 -> Adapter2
unsafe {
match adapter1.cast::<dxgi1_2::IDXGIAdapter2>().into_result() {
Ok(adapter2) => {
adapter1.destroy();
adapters.push(native::DxgiAdapter::Adapter2(adapter2));
continue;
}
Err(err) => {
log::info!("Failed casting Adapter1 to Adapter2: {}", err);
}
}
}
adapters.push(native::DxgiAdapter::Adapter1(adapter1));
}
adapters
}
/// Tries to create a IDXGIFactory6, then a IDXGIFactory4, then a IDXGIFactory2, then a IDXGIFactory1,
/// returning the one that succeeds, or if the required_factory_type fails to be
/// created.
pub fn create_factory(
required_factory_type: DxgiFactoryType,
instance_flags: crate::InstanceFlags,
) -> Result<(native::DxgiLib, native::DxgiFactory), crate::InstanceError> {
let lib_dxgi = native::DxgiLib::new().map_err(|_| crate::InstanceError)?;
let mut factory_flags = native::FactoryCreationFlags::empty();
if instance_flags.contains(crate::InstanceFlags::VALIDATION) {
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
// `CreateDXGIFactory2` if the debug interface is actually available. So
// we check for whether it exists first.
match lib_dxgi.get_debug_interface1() {
Ok(pair) => match pair.into_result() {
Ok(debug_controller) => {
unsafe { debug_controller.destroy() };
factory_flags |= native::FactoryCreationFlags::DEBUG;
}
Err(err) => {
log::warn!("Unable to enable DXGI debug interface: {}", err);
}
},
Err(err) => {
log::warn!("Debug interface function for DXGI not found: {:?}", err);
}
}
// Intercept `OutputDebugString` calls
super::exception::register_exception_handler();
}
// Try to create IDXGIFactory4
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
Ok(pair) => match pair.into_result() {
Ok(factory) => Some(factory),
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
Err(err) => {
log::error!("Failed to create IDXGIFactory4: {}", err);
return Err(crate::InstanceError);
}
},
// If we require factory4, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory4 => {
log::error!("IDXGIFactory1 creation function not found: {:?}", err);
return Err(crate::InstanceError);
}
// If we don't print it to info as all win7 will hit this case.
Err(err) => {
log::info!("IDXGIFactory1 creation function not found: {:?}", err);
None
}
};
if let Some(factory4) = factory4 {
// Try to cast the IDXGIFactory4 into IDXGIFactory6
let factory6 = unsafe { factory4.cast::<dxgi1_6::IDXGIFactory6>().into_result() };
match factory6 {
Ok(factory6) => {
unsafe {
factory4.destroy();
}
return Ok((lib_dxgi, native::DxgiFactory::Factory6(factory6)));
}
// If we require factory6, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory6 => {
log::warn!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err);
return Err(crate::InstanceError);
}
// If we don't print it to info.
Err(err) => {
log::info!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err);
return Ok((lib_dxgi, native::DxgiFactory::Factory4(factory4)));
}
}
}
// Try to create IDXGIFactory1
let factory1 = match lib_dxgi.create_factory1() {
Ok(pair) => match pair.into_result() {
Ok(factory) => factory,
Err(err) => {
log::error!("Failed to create IDXGIFactory1: {}", err);
return Err(crate::InstanceError);
}
},
// We always require at least factory1, so hard error
Err(err) => {
log::error!("IDXGIFactory1 creation function not found: {:?}", err);
return Err(crate::InstanceError);
}
};
// Try to cast the IDXGIFactory1 into IDXGIFactory2
let factory2 = unsafe { factory1.cast::<dxgi1_2::IDXGIFactory2>().into_result() };
match factory2 {
Ok(factory2) => {
unsafe {
factory1.destroy();
}
return Ok((lib_dxgi, native::DxgiFactory::Factory2(factory2)));
}
// If we require factory2, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory2 => {
log::warn!("Failed to cast IDXGIFactory1 to IDXGIFactory2: {:?}", err);
return Err(crate::InstanceError);
}
// If we don't print it to info.
Err(err) => {
log::info!("Failed to cast IDXGIFactory1 to IDXGIFactory2: {:?}", err);
}
}
// We tried to create 4 and 2, but only succeeded with 1.
Ok((lib_dxgi, native::DxgiFactory::Factory1(factory1)))
}

View File

@ -0,0 +1,4 @@
pub mod conv;
pub mod exception;
pub mod factory;
pub mod result;

View File

@ -0,0 +1,42 @@
use std::borrow::Cow;
use winapi::shared::winerror;
pub(crate) trait HResult<O> {
fn into_result(self) -> Result<O, Cow<'static, str>>;
fn into_device_result(self, description: &str) -> Result<O, crate::DeviceError>;
}
impl HResult<()> for i32 {
fn into_result(self) -> Result<(), Cow<'static, str>> {
if self >= 0 {
return Ok(());
}
let description = match self {
winerror::E_UNEXPECTED => "unexpected",
winerror::E_NOTIMPL => "not implemented",
winerror::E_OUTOFMEMORY => "out of memory",
winerror::E_INVALIDARG => "invalid argument",
_ => return Err(Cow::Owned(format!("0x{:X}", self as u32))),
};
Err(Cow::Borrowed(description))
}
fn into_device_result(self, description: &str) -> Result<(), crate::DeviceError> {
self.into_result().map_err(|err| {
log::error!("{} failed: {}", description, err);
if self == winerror::E_OUTOFMEMORY {
crate::DeviceError::OutOfMemory
} else {
crate::DeviceError::Lost
}
})
}
}
impl<T> HResult<T> for (T, i32) {
fn into_result(self) -> Result<T, Cow<'static, str>> {
self.1.into_result().map(|()| self.0)
}
fn into_device_result(self, description: &str) -> Result<T, crate::DeviceError> {
self.1.into_device_result(description).map(|()| self.0)
}
}

View File

@ -1,3 +1,6 @@
#[cfg(any(feature = "dx11", feature = "dx12"))]
pub(super) mod dxgi;
#[cfg(feature = "renderdoc")]
pub(super) mod renderdoc;

View File

@ -0,0 +1,274 @@
use std::num::NonZeroU64;
use winapi::um::{d3d11, d3dcommon};
impl crate::Adapter<super::Api> for super::Adapter {
unsafe fn open(
&self,
features: wgt::Features,
limits: &wgt::Limits,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
todo!()
}
unsafe fn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> crate::TextureFormatCapabilities {
todo!()
}
unsafe fn surface_capabilities(
&self,
surface: &super::Surface,
) -> Option<crate::SurfaceCapabilities> {
todo!()
}
}
impl super::Adapter {
pub(super) fn expose(
instance: &super::library::D3D11Lib,
adapter: native::DxgiAdapter,
) -> Option<crate::ExposedAdapter<super::Api>> {
use d3dcommon::{
D3D_FEATURE_LEVEL_10_0 as FL10_0, D3D_FEATURE_LEVEL_10_1 as FL10_1,
D3D_FEATURE_LEVEL_11_0 as FL11_0, D3D_FEATURE_LEVEL_11_1 as FL11_1,
D3D_FEATURE_LEVEL_9_1 as FL9_1, D3D_FEATURE_LEVEL_9_2 as FL9_2,
D3D_FEATURE_LEVEL_9_3 as FL9_3,
};
let (device, feature_level) = instance.create_device(adapter)?;
//
// Query Features from d3d11
//
let d3d9_features = unsafe {
device.check_feature_support::<d3d11::D3D11_FEATURE_DATA_D3D9_OPTIONS1>(
d3d11::D3D11_FEATURE_D3D9_OPTIONS1,
)
};
let d3d10_features = unsafe {
device.check_feature_support::<d3d11::D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS>(
d3d11::D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS,
)
};
let d3d11_features = unsafe {
device.check_feature_support::<d3d11::D3D11_FEATURE_DATA_D3D11_OPTIONS>(
d3d11::D3D11_FEATURE_D3D11_OPTIONS,
)
};
let d3d11_features1 = unsafe {
device.check_feature_support::<d3d11::D3D11_FEATURE_DATA_D3D11_OPTIONS1>(
d3d11::D3D11_FEATURE_D3D11_OPTIONS1,
)
};
let d3d11_features2 = unsafe {
device.check_feature_support::<d3d11::D3D11_FEATURE_DATA_D3D11_OPTIONS2>(
d3d11::D3D11_FEATURE_D3D11_OPTIONS2,
)
};
let d3d11_features3 = unsafe {
device.check_feature_support::<d3d11::D3D11_FEATURE_DATA_D3D11_OPTIONS3>(
d3d11::D3D11_FEATURE_D3D11_OPTIONS3,
)
};
//
// Fill out features and downlevel features
//
// TODO(cwfitzgerald): Needed downlevel features: 3D dispatch
let mut features = wgt::Features::DEPTH_CLIP_CONTROL
| wgt::Features::PUSH_CONSTANTS
| wgt::Features::POLYGON_MODE_LINE
| wgt::Features::CLEAR_TEXTURE
| wgt::Features::TEXTURE_FORMAT_16BIT_NORM
| wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO;
let mut downlevel =
wgt::DownlevelFlags::BASE_VERTEX | wgt::DownlevelFlags::READ_ONLY_DEPTH_STENCIL;
// Features from queries
downlevel.set(
wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES,
d3d9_features.FullNonPow2TextureSupported == 1,
);
downlevel.set(
wgt::DownlevelFlags::COMPUTE_SHADERS,
d3d10_features.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x == 1,
);
// Features from feature level
if feature_level >= FL9_2 {
downlevel |= wgt::DownlevelFlags::INDEPENDENT_BLEND;
// formally FL9_1 supports aniso 2, but we don't support that level of distinction
downlevel |= wgt::DownlevelFlags::ANISOTROPIC_FILTERING;
}
if feature_level >= FL9_3 {
downlevel |= wgt::DownlevelFlags::COMPARISON_SAMPLERS;
}
if feature_level >= FL10_0 {
downlevel |= wgt::DownlevelFlags::INDEPENDENT_BLEND;
downlevel |= wgt::DownlevelFlags::FRAGMENT_STORAGE;
downlevel |= wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE;
features |= wgt::Features::DEPTH_CLIP_CONTROL;
features |= wgt::Features::TIMESTAMP_QUERY;
features |= wgt::Features::PIPELINE_STATISTICS_QUERY;
}
if feature_level >= FL10_1 {
downlevel |= wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES;
}
if feature_level >= FL11_0 {
downlevel |= wgt::DownlevelFlags::INDIRECT_EXECUTION;
features |= wgt::Features::TEXTURE_COMPRESSION_BC;
}
if feature_level >= FL11_1 {
downlevel |= wgt::DownlevelFlags::VERTEX_STORAGE;
}
//
// Fill out limits and alignments
//
let max_texture_dimension_2d = match feature_level {
FL9_1 | FL9_2 => 2048,
FL9_3 => 4096,
FL10_0 | FL10_1 => 8192,
_ => d3d11::D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION,
};
let max_texture_dimension_3d = match feature_level {
FL9_1..=FL9_3 => 256,
_ => d3d11::D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
};
let max_vertex_buffers = match feature_level {
FL9_1..=FL9_3 => 16,
_ => 32,
};
let max_compute_workgroup_storage_size = match feature_level {
FL9_1..=FL9_3 => 0,
FL10_0 | FL10_1 => 4096 * 4, // This doesn't have an equiv SM4 constant :\
_ => d3d11::D3D11_CS_TGSM_REGISTER_COUNT * 4,
};
let max_workgroup_size_xy = match feature_level {
FL9_1..=FL9_3 => 0,
FL10_0 | FL10_1 => d3d11::D3D11_CS_4_X_THREAD_GROUP_MAX_X,
_ => d3d11::D3D11_CS_THREAD_GROUP_MAX_X,
};
let max_workgroup_size_z = match feature_level {
FL9_1..=FL9_3 => 0,
FL10_0 | FL10_1 => 1,
_ => d3d11::D3D11_CS_THREAD_GROUP_MAX_Z,
};
// let max_workgroup_count_z = match feature_level {
// FL9_1..=FL9_3 => 0,
// FL10_0 | FL10_1 => 1,
// _ => d3d11::D3D11_CS_THREAD_GROUP_MAX_Z,
// };
let max_sampled_textures = d3d11::D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT;
let max_samplers = d3d11::D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
let max_constant_buffers = d3d11::D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1;
let max_uavs = if device.as_device1().is_some() {
d3d11::D3D11_1_UAV_SLOT_COUNT
} else {
d3d11::D3D11_PS_CS_UAV_REGISTER_COUNT
};
let max_output_registers = d3d11::D3D11_VS_OUTPUT_REGISTER_COMPONENTS;
let max_compute_invocations_per_workgroup =
d3d11::D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
let max_compute_workgroups_per_dimension =
d3d11::D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
let limits = wgt::Limits {
max_texture_dimension_1d: max_texture_dimension_2d,
max_texture_dimension_2d: max_texture_dimension_2d,
max_texture_dimension_3d: max_texture_dimension_3d,
max_texture_array_layers: max_texture_dimension_3d,
max_bind_groups: u32::MAX,
max_dynamic_uniform_buffers_per_pipeline_layout: max_constant_buffers,
max_dynamic_storage_buffers_per_pipeline_layout: 0,
max_sampled_textures_per_shader_stage: max_sampled_textures,
max_samplers_per_shader_stage: max_samplers,
max_storage_buffers_per_shader_stage: max_uavs,
max_storage_textures_per_shader_stage: max_uavs,
max_uniform_buffers_per_shader_stage: max_constant_buffers,
max_uniform_buffer_binding_size: 1 << 16,
max_storage_buffer_binding_size: u32::MAX,
max_vertex_buffers: max_vertex_buffers,
max_vertex_attributes: max_vertex_buffers,
max_vertex_buffer_array_stride: u32::MAX,
max_push_constant_size: 1 << 16,
min_uniform_buffer_offset_alignment: 256,
min_storage_buffer_offset_alignment: 1,
max_inter_stage_shader_components: max_output_registers,
max_compute_workgroup_storage_size,
max_compute_invocations_per_workgroup,
max_compute_workgroup_size_x: max_workgroup_size_xy,
max_compute_workgroup_size_y: max_workgroup_size_xy,
max_compute_workgroup_size_z: max_workgroup_size_z,
max_compute_workgroups_per_dimension,
};
//
// Other capabilities
//
let shader_model = match feature_level {
FL9_1..=FL9_3 => wgt::ShaderModel::Sm2,
FL10_0 | FL10_1 => wgt::ShaderModel::Sm4,
_ => wgt::ShaderModel::Sm5,
};
let device_info = wgt::AdapterInfo {
name: String::new(),
vendor: 0,
device: 0,
device_type: match d3d11_features2.UnifiedMemoryArchitecture {
0 => wgt::DeviceType::DiscreteGpu,
1 => wgt::DeviceType::IntegratedGpu,
_ => unreachable!(),
},
backend: wgt::Backend::Dx11,
};
//
// Build up the structs
//
let api_adapter = super::Adapter { device };
let alignments = crate::Alignments {
buffer_copy_offset: NonZeroU64::new(1).unwrap(), // todo
buffer_copy_pitch: NonZeroU64::new(1).unwrap(), // todo
};
let capabilities = crate::Capabilities {
limits,
alignments,
downlevel: wgt::DownlevelCapabilities {
flags: downlevel,
limits: wgt::DownlevelLimits {},
shader_model,
},
};
Some(crate::ExposedAdapter {
adapter: api_adapter,
info: device_info,
features,
capabilities,
})
}
}

View File

@ -0,0 +1,268 @@
impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> {
todo!()
}
unsafe fn discard_encoding(&mut self) {
todo!()
}
unsafe fn end_encoding(&mut self) -> Result<super::CommandBuffer, crate::DeviceError> {
todo!()
}
unsafe fn reset_all<I>(&mut self, command_buffers: I)
where
I: Iterator<Item = super::CommandBuffer>,
{
todo!()
}
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = crate::BufferBarrier<'a, super::Api>>,
{
todo!()
}
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = crate::TextureBarrier<'a, super::Api>>,
{
todo!()
}
unsafe fn clear_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange) {
todo!()
}
unsafe fn copy_buffer_to_buffer<T>(
&mut self,
src: &super::Buffer,
dst: &super::Buffer,
regions: T,
) where
T: Iterator<Item = crate::BufferCopy>,
{
todo!()
}
unsafe fn copy_texture_to_texture<T>(
&mut self,
src: &super::Texture,
src_usage: crate::TextureUses,
dst: &super::Texture,
regions: T,
) where
T: Iterator<Item = crate::TextureCopy>,
{
todo!()
}
unsafe fn copy_buffer_to_texture<T>(
&mut self,
src: &super::Buffer,
dst: &super::Texture,
regions: T,
) where
T: Iterator<Item = crate::BufferTextureCopy>,
{
todo!()
}
unsafe fn copy_texture_to_buffer<T>(
&mut self,
src: &super::Texture,
src_usage: crate::TextureUses,
dst: &super::Buffer,
regions: T,
) where
T: Iterator<Item = crate::BufferTextureCopy>,
{
todo!()
}
unsafe fn set_bind_group(
&mut self,
layout: &super::PipelineLayout,
index: u32,
group: &super::BindGroup,
dynamic_offsets: &[wgt::DynamicOffset],
) {
todo!()
}
unsafe fn set_push_constants(
&mut self,
layout: &super::PipelineLayout,
stages: wgt::ShaderStages,
offset: u32,
data: &[u32],
) {
todo!()
}
unsafe fn insert_debug_marker(&mut self, label: &str) {
todo!()
}
unsafe fn begin_debug_marker(&mut self, group_label: &str) {
todo!()
}
unsafe fn end_debug_marker(&mut self) {
todo!()
}
unsafe fn begin_query(&mut self, set: &super::QuerySet, index: u32) {
todo!()
}
unsafe fn end_query(&mut self, set: &super::QuerySet, index: u32) {
todo!()
}
unsafe fn write_timestamp(&mut self, set: &super::QuerySet, index: u32) {
todo!()
}
unsafe fn reset_queries(&mut self, set: &super::QuerySet, range: std::ops::Range<u32>) {
todo!()
}
unsafe fn copy_query_results(
&mut self,
set: &super::QuerySet,
range: std::ops::Range<u32>,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
stride: wgt::BufferSize,
) {
todo!()
}
unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<super::Api>) {
todo!()
}
unsafe fn end_render_pass(&mut self) {
todo!()
}
unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {
todo!()
}
unsafe fn set_index_buffer<'a>(
&mut self,
binding: crate::BufferBinding<'a, super::Api>,
format: wgt::IndexFormat,
) {
todo!()
}
unsafe fn set_vertex_buffer<'a>(
&mut self,
index: u32,
binding: crate::BufferBinding<'a, super::Api>,
) {
todo!()
}
unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: std::ops::Range<f32>) {
todo!()
}
unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {
todo!()
}
unsafe fn set_stencil_reference(&mut self, value: u32) {
todo!()
}
unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) {
todo!()
}
unsafe fn draw(
&mut self,
start_vertex: u32,
vertex_count: u32,
start_instance: u32,
instance_count: u32,
) {
todo!()
}
unsafe fn draw_indexed(
&mut self,
start_index: u32,
index_count: u32,
base_vertex: i32,
start_instance: u32,
instance_count: u32,
) {
todo!()
}
unsafe fn draw_indirect(
&mut self,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
) {
todo!()
}
unsafe fn draw_indexed_indirect(
&mut self,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
) {
todo!()
}
unsafe fn draw_indirect_count(
&mut self,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
count_buffer: &super::Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
) {
todo!()
}
unsafe fn draw_indexed_indirect_count(
&mut self,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
count_buffer: &super::Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
) {
todo!()
}
unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {
todo!()
}
unsafe fn end_compute_pass(&mut self) {
todo!()
}
unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {
todo!()
}
unsafe fn dispatch(&mut self, count: [u32; 3]) {
todo!()
}
unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) {
todo!()
}
}

240
wgpu-hal/src/dx11/device.rs Normal file
View File

@ -0,0 +1,240 @@
use std::{ffi::c_void, mem};
use winapi::um::d3d11;
use crate::auxil::dxgi::result::HResult;
impl crate::Device<super::Api> for super::Device {
unsafe fn exit(self, queue: super::Queue) {
todo!()
}
unsafe fn create_buffer(
&self,
desc: &crate::BufferDescriptor,
) -> Result<super::Buffer, crate::DeviceError> {
todo!()
}
unsafe fn destroy_buffer(&self, buffer: super::Buffer) {
todo!()
}
unsafe fn map_buffer(
&self,
buffer: &super::Buffer,
range: crate::MemoryRange,
) -> Result<crate::BufferMapping, crate::DeviceError> {
todo!()
}
unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> {
todo!()
}
unsafe fn flush_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
where
I: Iterator<Item = crate::MemoryRange>,
{
todo!()
}
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
where
I: Iterator<Item = crate::MemoryRange>,
{
todo!()
}
unsafe fn create_texture(
&self,
desc: &crate::TextureDescriptor,
) -> Result<super::Texture, crate::DeviceError> {
todo!()
}
unsafe fn destroy_texture(&self, texture: super::Texture) {
todo!()
}
unsafe fn create_texture_view(
&self,
texture: &super::Texture,
desc: &crate::TextureViewDescriptor,
) -> Result<super::TextureView, crate::DeviceError> {
todo!()
}
unsafe fn destroy_texture_view(&self, view: super::TextureView) {
todo!()
}
unsafe fn create_sampler(
&self,
desc: &crate::SamplerDescriptor,
) -> Result<super::Sampler, crate::DeviceError> {
todo!()
}
unsafe fn destroy_sampler(&self, sampler: super::Sampler) {
todo!()
}
unsafe fn create_command_encoder(
&self,
desc: &crate::CommandEncoderDescriptor<super::Api>,
) -> Result<super::CommandEncoder, crate::DeviceError> {
todo!()
}
unsafe fn destroy_command_encoder(&self, pool: super::CommandEncoder) {
todo!()
}
unsafe fn create_bind_group_layout(
&self,
desc: &crate::BindGroupLayoutDescriptor,
) -> Result<super::BindGroupLayout, crate::DeviceError> {
todo!()
}
unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) {
todo!()
}
unsafe fn create_pipeline_layout(
&self,
desc: &crate::PipelineLayoutDescriptor<super::Api>,
) -> Result<super::PipelineLayout, crate::DeviceError> {
todo!()
}
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
todo!()
}
unsafe fn create_bind_group(
&self,
desc: &crate::BindGroupDescriptor<super::Api>,
) -> Result<super::BindGroup, crate::DeviceError> {
todo!()
}
unsafe fn destroy_bind_group(&self, group: super::BindGroup) {
todo!()
}
unsafe fn create_shader_module(
&self,
desc: &crate::ShaderModuleDescriptor,
shader: crate::ShaderInput,
) -> Result<super::ShaderModule, crate::ShaderError> {
todo!()
}
unsafe fn destroy_shader_module(&self, module: super::ShaderModule) {
todo!()
}
unsafe fn create_render_pipeline(
&self,
desc: &crate::RenderPipelineDescriptor<super::Api>,
) -> Result<super::RenderPipeline, crate::PipelineError> {
todo!()
}
unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) {
todo!()
}
unsafe fn create_compute_pipeline(
&self,
desc: &crate::ComputePipelineDescriptor<super::Api>,
) -> Result<super::ComputePipeline, crate::PipelineError> {
todo!()
}
unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {
todo!()
}
unsafe fn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor<crate::Label>,
) -> Result<super::QuerySet, crate::DeviceError> {
todo!()
}
unsafe fn destroy_query_set(&self, set: super::QuerySet) {
todo!()
}
unsafe fn create_fence(&self) -> Result<super::Fence, crate::DeviceError> {
todo!()
}
unsafe fn destroy_fence(&self, fence: super::Fence) {
todo!()
}
unsafe fn get_fence_value(
&self,
fence: &super::Fence,
) -> Result<crate::FenceValue, crate::DeviceError> {
todo!()
}
unsafe fn wait(
&self,
fence: &super::Fence,
value: crate::FenceValue,
timeout_ms: u32,
) -> Result<bool, crate::DeviceError> {
todo!()
}
unsafe fn start_capture(&self) -> bool {
todo!()
}
unsafe fn stop_capture(&self) {
todo!()
}
}
impl crate::Queue<super::Api> for super::Queue {
unsafe fn submit(
&mut self,
command_buffers: &[&super::CommandBuffer],
signal_fence: Option<(&mut super::Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
todo!()
}
unsafe fn present(
&mut self,
surface: &mut super::Surface,
texture: super::SurfaceTexture,
) -> Result<(), crate::SurfaceError> {
todo!()
}
unsafe fn get_timestamp_period(&self) -> f32 {
todo!()
}
}
impl super::D3D11Device {
#[allow(trivial_casts)] // come on
pub unsafe fn check_feature_support<T>(&self, feature: d3d11::D3D11_FEATURE) -> T {
let mut value = mem::zeroed::<T>();
let ret = self.CheckFeatureSupport(
feature,
&mut value as *mut T as *mut c_void,
mem::size_of::<T>() as u32,
);
assert_eq!(ret.into_result(), Ok(()));
value
}
}

View File

@ -0,0 +1,47 @@
use crate::auxil;
impl crate::Instance<super::Api> for super::Instance {
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
let enable_dx11 = match std::env::var("WGPU_UNSTABLE_DX11_BACKEND") {
Ok(string) => string == "1" || string == "true",
Err(_) => false,
};
if !enable_dx11 {
return Err(crate::InstanceError);
}
let lib_d3d11 = super::library::D3D11Lib::new().ok_or(crate::InstanceError)?;
let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory(
auxil::dxgi::factory::DxgiFactoryType::Factory1,
desc.flags,
)?;
Ok(super::Instance {
lib_d3d11,
lib_dxgi,
factory,
})
}
unsafe fn create_surface(
&self,
rwh: &impl raw_window_handle::HasRawWindowHandle,
) -> Result<super::Surface, crate::InstanceError> {
todo!()
}
unsafe fn destroy_surface(&self, surface: super::Surface) {
todo!()
}
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
let adapters = auxil::dxgi::factory::enumerate_adapters(self.factory);
adapters
.into_iter()
.filter_map(|adapter| super::Adapter::expose(&self.lib_d3d11, adapter))
.collect()
}
}

View File

@ -0,0 +1,144 @@
use std::ptr;
use winapi::{
shared::{
dxgi,
minwindef::{HMODULE, UINT},
winerror,
},
um::{d3d11, d3d11_1, d3d11_2, d3dcommon},
};
use crate::auxil::dxgi::result::HResult;
type D3D11CreateDeviceFun = unsafe extern "system" fn(
*mut dxgi::IDXGIAdapter,
d3dcommon::D3D_DRIVER_TYPE,
HMODULE,
UINT,
*const d3dcommon::D3D_FEATURE_LEVEL,
UINT,
UINT,
*mut *mut d3d11::ID3D11Device,
*mut d3dcommon::D3D_FEATURE_LEVEL,
*mut *mut d3d11::ID3D11DeviceContext,
) -> native::HRESULT;
pub(super) struct D3D11Lib {
// We use the os specific symbol to drop the lifetime parameter.
//
// SAFETY: we must ensure this outlives the Library.
d3d11_create_device: libloading::os::windows::Symbol<D3D11CreateDeviceFun>,
lib: libloading::Library,
}
impl D3D11Lib {
pub fn new() -> Option<Self> {
unsafe {
let lib = libloading::Library::new("d3d11.dll").ok()?;
let d3d11_create_device = lib
.get::<D3D11CreateDeviceFun>(b"D3D11CreateDevice")
.ok()?
.into_raw();
Some(Self {
lib,
d3d11_create_device,
})
}
}
pub fn create_device(
&self,
adapter: native::DxgiAdapter,
) -> Option<(super::D3D11Device, d3dcommon::D3D_FEATURE_LEVEL)> {
let feature_levels = [
d3dcommon::D3D_FEATURE_LEVEL_11_1,
d3dcommon::D3D_FEATURE_LEVEL_11_0,
d3dcommon::D3D_FEATURE_LEVEL_10_1,
d3dcommon::D3D_FEATURE_LEVEL_10_0,
d3dcommon::D3D_FEATURE_LEVEL_9_3,
d3dcommon::D3D_FEATURE_LEVEL_9_2,
d3dcommon::D3D_FEATURE_LEVEL_9_1,
];
let mut device = native::WeakPtr::<d3d11::ID3D11Device>::null();
let mut feature_level: d3dcommon::D3D_FEATURE_LEVEL = 0;
// We need to try this twice. If the first time fails due to E_INVALIDARG
// we are running on a machine without a D3D11.1 runtime, and need to
// retry without the feature level 11_1 feature level.
//
// Why they thought this was a good API, who knows.
let mut hr = unsafe {
(self.d3d11_create_device)(
adapter.as_mut_ptr() as *mut _,
d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
ptr::null_mut(), // software implementation DLL???
0, // flags
feature_levels.as_ptr(),
feature_levels.len() as u32,
d3d11::D3D11_SDK_VERSION,
device.mut_self(),
&mut feature_level,
ptr::null_mut(), // device context
)
};
// Try again without FL11_1
if hr == winerror::E_INVALIDARG {
hr = unsafe {
(self.d3d11_create_device)(
adapter.as_mut_ptr() as *mut _,
d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
ptr::null_mut(), // software implementation DLL???
0, // flags
feature_levels[1..].as_ptr(),
feature_levels[1..].len() as u32,
d3d11::D3D11_SDK_VERSION,
device.mut_self(),
&mut feature_level,
ptr::null_mut(), // device context
)
};
}
// Any errors here are real and we should complain about
if let Err(err) = hr.into_result() {
log::error!("Failed to make a D3D11 device: {}", err);
return None;
}
// We always try to upcast in highest -> lowest order
// Device -> Device2
unsafe {
match device.cast::<d3d11_2::ID3D11Device2>().into_result() {
Ok(device2) => {
device.destroy();
return Some((super::D3D11Device::Device2(device2), feature_level));
}
Err(hr) => {
log::info!("Failed to cast device to ID3D11Device2: {}", hr)
}
}
}
// Device -> Device1
unsafe {
match device.cast::<d3d11_1::ID3D11Device1>().into_result() {
Ok(device1) => {
device.destroy();
return Some((super::D3D11Device::Device1(device1), feature_level));
}
Err(hr) => {
log::info!("Failed to cast device to ID3D11Device1: {}", hr)
}
}
}
Some((super::D3D11Device::Device(device), feature_level))
}
}

135
wgpu-hal/src/dx11/mod.rs Normal file
View File

@ -0,0 +1,135 @@
#![allow(dead_code)]
#![allow(unused_variables)]
use winapi::um::{d3d11, d3d11_1, d3d11_2};
mod adapter;
mod command;
mod device;
mod instance;
mod library;
#[derive(Clone)]
pub struct Api;
impl crate::Api for Api {
type Instance = Instance;
type Surface = Surface;
type Adapter = Adapter;
type Device = Device;
type Queue = Queue;
type CommandEncoder = CommandEncoder;
type CommandBuffer = CommandBuffer;
type Buffer = Buffer;
type Texture = Texture;
type SurfaceTexture = SurfaceTexture;
type TextureView = TextureView;
type Sampler = Sampler;
type QuerySet = QuerySet;
type Fence = Fence;
type BindGroupLayout = BindGroupLayout;
type BindGroup = BindGroup;
type PipelineLayout = PipelineLayout;
type ShaderModule = ShaderModule;
type RenderPipeline = RenderPipeline;
type ComputePipeline = ComputePipeline;
}
pub struct Instance {
lib_d3d11: library::D3D11Lib,
lib_dxgi: native::DxgiLib,
factory: native::DxgiFactory,
}
unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}
pub struct Surface {}
pub struct Adapter {
device: D3D11Device,
}
unsafe impl Send for Adapter {}
unsafe impl Sync for Adapter {}
native::weak_com_inheritance_chain! {
#[derive(Debug, Copy, Clone, PartialEq)]
enum D3D11Device {
Device(d3d11::ID3D11Device), from_device, as_device, device;
Device1(d3d11_1::ID3D11Device1), from_device1, as_device1, unwrap_device1;
Device2(d3d11_2::ID3D11Device2), from_device2, as_device2, unwrap_device2;
}
}
pub struct Device {}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
pub struct Queue {}
pub struct CommandEncoder {}
pub struct CommandBuffer {}
#[derive(Debug)]
pub struct Buffer {}
#[derive(Debug)]
pub struct Texture {}
#[derive(Debug)]
pub struct SurfaceTexture {}
impl std::borrow::Borrow<Texture> for SurfaceTexture {
fn borrow(&self) -> &Texture {
todo!()
}
}
#[derive(Debug)]
pub struct TextureView {}
#[derive(Debug)]
pub struct Sampler {}
#[derive(Debug)]
pub struct QuerySet {}
#[derive(Debug)]
pub struct Fence {}
#[derive(Debug)]
pub struct BindGroupLayout {}
#[derive(Debug)]
pub struct BindGroup {}
#[derive(Debug)]
pub struct PipelineLayout {}
#[derive(Debug)]
pub struct ShaderModule {}
pub struct RenderPipeline {}
pub struct ComputePipeline {}
impl crate::Surface<Api> for Surface {
unsafe fn configure(
&mut self,
device: &Device,
config: &crate::SurfaceConfiguration,
) -> Result<(), crate::SurfaceError> {
todo!()
}
unsafe fn unconfigure(&mut self, device: &Device) {
todo!()
}
unsafe fn acquire_texture(
&mut self,
timeout_ms: u32,
) -> Result<Option<crate::AcquiredSurfaceTexture<Api>>, crate::SurfaceError> {
todo!()
}
unsafe fn discard_texture(&mut self, texture: SurfaceTexture) {
todo!()
}
}

View File

@ -1,4 +1,7 @@
use super::{conv, HResult as _, SurfaceTarget};
use crate::{
auxil::{self, dxgi::result::HResult as _},
dx12::SurfaceTarget,
};
use std::{mem, sync::Arc, thread};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_5, minwindef, windef, winerror},
@ -40,14 +43,14 @@ impl super::Adapter {
#[allow(trivial_casts)]
pub(super) fn expose(
adapter: native::WeakPtr<dxgi1_2::IDXGIAdapter2>,
adapter: native::DxgiAdapter,
library: &Arc<native::D3D12Lib>,
instance_flags: crate::InstanceFlags,
) -> Option<crate::ExposedAdapter<super::Api>> {
// Create the device so that we can get the capabilities.
let device = {
profiling::scope!("ID3D12Device::create_device");
match library.create_device(adapter, native::FeatureLevel::L11_0) {
match library.create_device(*adapter, native::FeatureLevel::L11_0) {
Ok(pair) => match pair.into_result() {
Ok(device) => device,
Err(err) => {
@ -68,7 +71,7 @@ impl super::Adapter {
// Acquire the device information.
let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
unsafe {
adapter.GetDesc2(&mut desc);
adapter.unwrap_adapter2().GetDesc2(&mut desc);
}
let device_name = {
@ -317,7 +320,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
) -> crate::TextureFormatCapabilities {
use crate::TextureFormatCapabilities as Tfc;
let raw_format = conv::map_texture_format(format);
let raw_format = auxil::dxgi::conv::map_texture_format(format);
let mut data = d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: raw_format,
Support1: mem::zeroed(),
@ -409,11 +412,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
let mut present_modes = vec![wgt::PresentMode::Fifo];
#[allow(trivial_casts)]
if let Ok(factory5) = surface
.factory
.cast::<dxgi1_5::IDXGIFactory5>()
.into_result()
{
if let Some(factory5) = surface.factory.as_factory5() {
let mut allow_tearing: minwindef::BOOL = minwindef::FALSE;
let hr = factory5.CheckFeatureSupport(
dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
@ -421,7 +420,6 @@ impl crate::Adapter<super::Api> for super::Adapter {
mem::size_of::<minwindef::BOOL>() as _,
);
factory5.destroy();
match hr.into_result() {
Err(err) => log::warn!("Unable to check for tearing support: {}", err),
Ok(()) => present_modes.push(wgt::PresentMode::Immediate),

View File

@ -1,4 +1,6 @@
use super::{conv, HResult as _};
use crate::auxil::{self, dxgi::result::HResult as _};
use super::conv;
use std::{mem, ops::Range, ptr};
use winapi::um::d3d12;
@ -22,7 +24,7 @@ impl crate::BufferTextureCopy {
d3d12::D3D12_PLACED_SUBRESOURCE_FOOTPRINT {
Offset: self.buffer_layout.offset,
Footprint: d3d12::D3D12_SUBRESOURCE_FOOTPRINT {
Format: conv::map_texture_format(format),
Format: auxil::dxgi::conv::map_texture_format(format),
Width: self.size.width,
Height: self
.buffer_layout
@ -834,7 +836,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.list.unwrap().set_index_buffer(
binding.resolve_address(),
binding.resolve_size() as u32,
conv::map_index_format(format),
auxil::dxgi::conv::map_index_format(format),
);
}
unsafe fn set_vertex_buffer<'a>(

View File

@ -1,182 +1,5 @@
use std::iter;
use winapi::{
shared::{dxgi1_2, dxgiformat},
um::{d3d12, d3dcommon},
};
pub(super) fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
use wgt::TextureFormat as Tf;
use winapi::shared::dxgiformat::*;
match format {
Tf::R8Unorm => DXGI_FORMAT_R8_UNORM,
Tf::R8Snorm => DXGI_FORMAT_R8_SNORM,
Tf::R8Uint => DXGI_FORMAT_R8_UINT,
Tf::R8Sint => DXGI_FORMAT_R8_SINT,
Tf::R16Uint => DXGI_FORMAT_R16_UINT,
Tf::R16Sint => DXGI_FORMAT_R16_SINT,
Tf::R16Unorm => DXGI_FORMAT_R16_UNORM,
Tf::R16Snorm => DXGI_FORMAT_R16_SNORM,
Tf::R16Float => DXGI_FORMAT_R16_FLOAT,
Tf::Rg8Unorm => DXGI_FORMAT_R8G8_UNORM,
Tf::Rg8Snorm => DXGI_FORMAT_R8G8_SNORM,
Tf::Rg8Uint => DXGI_FORMAT_R8G8_UINT,
Tf::Rg8Sint => DXGI_FORMAT_R8G8_SINT,
Tf::Rg16Unorm => DXGI_FORMAT_R16G16_UNORM,
Tf::Rg16Snorm => DXGI_FORMAT_R16G16_SNORM,
Tf::R32Uint => DXGI_FORMAT_R32_UINT,
Tf::R32Sint => DXGI_FORMAT_R32_SINT,
Tf::R32Float => DXGI_FORMAT_R32_FLOAT,
Tf::Rg16Uint => DXGI_FORMAT_R16G16_UINT,
Tf::Rg16Sint => DXGI_FORMAT_R16G16_SINT,
Tf::Rg16Float => DXGI_FORMAT_R16G16_FLOAT,
Tf::Rgba8Unorm => DXGI_FORMAT_R8G8B8A8_UNORM,
Tf::Rgba8UnormSrgb => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
Tf::Bgra8UnormSrgb => DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
Tf::Rgba8Snorm => DXGI_FORMAT_R8G8B8A8_SNORM,
Tf::Bgra8Unorm => DXGI_FORMAT_B8G8R8A8_UNORM,
Tf::Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT,
Tf::Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT,
Tf::Rgb10a2Unorm => DXGI_FORMAT_R10G10B10A2_UNORM,
Tf::Rg11b10Float => DXGI_FORMAT_R11G11B10_FLOAT,
Tf::Rg32Uint => DXGI_FORMAT_R32G32_UINT,
Tf::Rg32Sint => DXGI_FORMAT_R32G32_SINT,
Tf::Rg32Float => DXGI_FORMAT_R32G32_FLOAT,
Tf::Rgba16Uint => DXGI_FORMAT_R16G16B16A16_UINT,
Tf::Rgba16Sint => DXGI_FORMAT_R16G16B16A16_SINT,
Tf::Rgba16Unorm => DXGI_FORMAT_R16G16B16A16_UNORM,
Tf::Rgba16Snorm => DXGI_FORMAT_R16G16B16A16_SNORM,
Tf::Rgba16Float => DXGI_FORMAT_R16G16B16A16_FLOAT,
Tf::Rgba32Uint => DXGI_FORMAT_R32G32B32A32_UINT,
Tf::Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT,
Tf::Rgba32Float => DXGI_FORMAT_R32G32B32A32_FLOAT,
Tf::Depth32Float => DXGI_FORMAT_D32_FLOAT,
Tf::Depth24Plus => DXGI_FORMAT_D24_UNORM_S8_UINT,
Tf::Depth24PlusStencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT,
Tf::Rgb9e5Ufloat => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
Tf::Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM,
Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_UNORM_SRGB,
Tf::Bc2RgbaUnorm => DXGI_FORMAT_BC2_UNORM,
Tf::Bc2RgbaUnormSrgb => DXGI_FORMAT_BC2_UNORM_SRGB,
Tf::Bc3RgbaUnorm => DXGI_FORMAT_BC3_UNORM,
Tf::Bc3RgbaUnormSrgb => DXGI_FORMAT_BC3_UNORM_SRGB,
Tf::Bc4RUnorm => DXGI_FORMAT_BC4_UNORM,
Tf::Bc4RSnorm => DXGI_FORMAT_BC4_SNORM,
Tf::Bc5RgUnorm => DXGI_FORMAT_BC5_UNORM,
Tf::Bc5RgSnorm => DXGI_FORMAT_BC5_SNORM,
Tf::Bc6hRgbUfloat => DXGI_FORMAT_BC6H_UF16,
Tf::Bc6hRgbSfloat => DXGI_FORMAT_BC6H_SF16,
Tf::Bc7RgbaUnorm => DXGI_FORMAT_BC7_UNORM,
Tf::Bc7RgbaUnormSrgb => DXGI_FORMAT_BC7_UNORM_SRGB,
Tf::Etc2Rgb8Unorm
| Tf::Etc2Rgb8UnormSrgb
| Tf::Etc2Rgb8A1Unorm
| Tf::Etc2Rgb8A1UnormSrgb
| Tf::Etc2Rgba8Unorm
| Tf::Etc2Rgba8UnormSrgb
| Tf::EacR11Unorm
| Tf::EacR11Snorm
| Tf::EacRg11Unorm
| Tf::EacRg11Snorm => unreachable!(),
Tf::Astc {
block: _,
channel: _,
} => unreachable!(),
}
}
//Note: DXGI doesn't allow sRGB format on the swapchain,
// but creating RTV of swapchain buffers with sRGB works.
pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::TextureFormat::Bgra8UnormSrgb => dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
wgt::TextureFormat::Rgba8UnormSrgb => dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
_ => map_texture_format(format),
}
}
//Note: SRV and UAV can't use the depth formats directly
//TODO: stencil views?
pub fn map_texture_format_nodepth(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::TextureFormat::Depth32Float => dxgiformat::DXGI_FORMAT_R32_FLOAT,
wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8 => {
dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS
}
_ => {
assert_eq!(
crate::FormatAspects::from(format),
crate::FormatAspects::COLOR
);
map_texture_format(format)
}
}
}
pub fn map_texture_format_depth_typeless(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::TextureFormat::Depth32Float => dxgiformat::DXGI_FORMAT_R32_TYPELESS,
wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8 => {
dxgiformat::DXGI_FORMAT_R24G8_TYPELESS
}
_ => unreachable!(),
}
}
pub fn map_index_format(format: wgt::IndexFormat) -> dxgiformat::DXGI_FORMAT {
match format {
wgt::IndexFormat::Uint16 => dxgiformat::DXGI_FORMAT_R16_UINT,
wgt::IndexFormat::Uint32 => dxgiformat::DXGI_FORMAT_R32_UINT,
}
}
pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT {
use wgt::VertexFormat as Vf;
use winapi::shared::dxgiformat::*;
match format {
Vf::Unorm8x2 => DXGI_FORMAT_R8G8_UNORM,
Vf::Snorm8x2 => DXGI_FORMAT_R8G8_SNORM,
Vf::Uint8x2 => DXGI_FORMAT_R8G8_UINT,
Vf::Sint8x2 => DXGI_FORMAT_R8G8_SINT,
Vf::Unorm8x4 => DXGI_FORMAT_R8G8B8A8_UNORM,
Vf::Snorm8x4 => DXGI_FORMAT_R8G8B8A8_SNORM,
Vf::Uint8x4 => DXGI_FORMAT_R8G8B8A8_UINT,
Vf::Sint8x4 => DXGI_FORMAT_R8G8B8A8_SINT,
Vf::Unorm16x2 => DXGI_FORMAT_R16G16_UNORM,
Vf::Snorm16x2 => DXGI_FORMAT_R16G16_SNORM,
Vf::Uint16x2 => DXGI_FORMAT_R16G16_UINT,
Vf::Sint16x2 => DXGI_FORMAT_R16G16_SINT,
Vf::Float16x2 => DXGI_FORMAT_R16G16_FLOAT,
Vf::Unorm16x4 => DXGI_FORMAT_R16G16B16A16_UNORM,
Vf::Snorm16x4 => DXGI_FORMAT_R16G16B16A16_SNORM,
Vf::Uint16x4 => DXGI_FORMAT_R16G16B16A16_UINT,
Vf::Sint16x4 => DXGI_FORMAT_R16G16B16A16_SINT,
Vf::Float16x4 => DXGI_FORMAT_R16G16B16A16_FLOAT,
Vf::Uint32 => DXGI_FORMAT_R32_UINT,
Vf::Sint32 => DXGI_FORMAT_R32_SINT,
Vf::Float32 => DXGI_FORMAT_R32_FLOAT,
Vf::Uint32x2 => DXGI_FORMAT_R32G32_UINT,
Vf::Sint32x2 => DXGI_FORMAT_R32G32_SINT,
Vf::Float32x2 => DXGI_FORMAT_R32G32_FLOAT,
Vf::Uint32x3 => DXGI_FORMAT_R32G32B32_UINT,
Vf::Sint32x3 => DXGI_FORMAT_R32G32B32_SINT,
Vf::Float32x3 => DXGI_FORMAT_R32G32B32_FLOAT,
Vf::Uint32x4 => DXGI_FORMAT_R32G32B32A32_UINT,
Vf::Sint32x4 => DXGI_FORMAT_R32G32B32A32_SINT,
Vf::Float32x4 => DXGI_FORMAT_R32G32B32A32_FLOAT,
Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(),
}
}
pub fn map_acomposite_alpha_mode(mode: crate::CompositeAlphaMode) -> dxgi1_2::DXGI_ALPHA_MODE {
use crate::CompositeAlphaMode as Cam;
match mode {
Cam::Opaque => dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
Cam::PreMultiplied => dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
Cam::PostMultiplied => dxgi1_2::DXGI_ALPHA_MODE_STRAIGHT,
}
}
use winapi::um::{d3d12, d3dcommon};
pub fn map_buffer_usage_to_resource_flags(usage: crate::BufferUses) -> d3d12::D3D12_RESOURCE_FLAGS {
let mut flags = 0;

View File

@ -1,4 +1,4 @@
use super::HResult as _;
use crate::auxil::dxgi::result::HResult as _;
use bit_set::BitSet;
use parking_lot::Mutex;
use range_alloc::RangeAllocator;

View File

@ -1,6 +1,9 @@
use crate::FormatAspects;
use crate::{
auxil::{self, dxgi::result::HResult as _},
FormatAspects,
};
use super::{conv, descriptor, view, HResult as _};
use super::{conv, descriptor, view};
use parking_lot::Mutex;
use std::{ffi, mem, num::NonZeroU32, ptr, slice, sync::Arc};
use winapi::{
@ -432,13 +435,13 @@ impl crate::Device<super::Api> for super::Device {
| crate::TextureUses::STORAGE_READ
| crate::TextureUses::STORAGE_WRITE,
) {
conv::map_texture_format(desc.format)
auxil::dxgi::conv::map_texture_format(desc.format)
} else {
// This branch is needed if it's a depth texture, and it's ever needed to be viewed as SRV or UAV,
// because then we'd create a non-depth format view of it.
// Note: we can skip this branch if
// `D3D12_FEATURE_D3D12_OPTIONS3::CastingFullyTypedFormatSupported`
conv::map_texture_format_depth_typeless(desc.format)
auxil::dxgi::conv::map_texture_format_depth_typeless(desc.format)
},
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
Count: desc.sample_count,
@ -1249,7 +1252,7 @@ impl crate::Device<super::Api> for super::Device {
input_element_descs.push(d3d12::D3D12_INPUT_ELEMENT_DESC {
SemanticName: NAGA_LOCATION_SEMANTIC.as_ptr() as *const _,
SemanticIndex: attribute.shader_location,
Format: conv::map_vertex_format(attribute.format),
Format: auxil::dxgi::conv::map_vertex_format(attribute.format),
InputSlot: i as u32,
AlignedByteOffset: attribute.offset as u32,
InputSlotClass: slot_class,
@ -1261,7 +1264,7 @@ impl crate::Device<super::Api> for super::Device {
let mut rtv_formats = [dxgiformat::DXGI_FORMAT_UNKNOWN;
d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
for (rtv_format, ct) in rtv_formats.iter_mut().zip(desc.color_targets) {
*rtv_format = conv::map_texture_format(ct.format);
*rtv_format = auxil::dxgi::conv::map_texture_format(ct.format);
}
let bias = desc
@ -1350,7 +1353,7 @@ impl crate::Device<super::Api> for super::Device {
.depth_stencil
.as_ref()
.map_or(dxgiformat::DXGI_FORMAT_UNKNOWN, |ds| {
conv::map_texture_format(ds.format)
auxil::dxgi::conv::map_texture_format(ds.format)
}),
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
Count: desc.multisample.count,

View File

@ -1,81 +1,11 @@
use super::{HResult as _, SurfaceTarget};
use std::{borrow::Cow, slice, sync::Arc};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_6, winerror},
um::{errhandlingapi, winnt},
vc::excpt,
Interface,
};
const MESSAGE_PREFIXES: &[(&str, log::Level)] = &[
("CORRUPTION", log::Level::Error),
("ERROR", log::Level::Error),
("WARNING", log::Level::Warn),
("INFO", log::Level::Info),
("MESSAGE", log::Level::Debug),
];
unsafe extern "system" fn output_debug_string_handler(
exception_info: *mut winnt::EXCEPTION_POINTERS,
) -> i32 {
// See https://stackoverflow.com/a/41480827
let record = &*(*exception_info).ExceptionRecord;
if record.NumberParameters != 2 {
return excpt::EXCEPTION_CONTINUE_SEARCH;
}
let message = match record.ExceptionCode {
winnt::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(slice::from_raw_parts(
record.ExceptionInformation[1] as *const u8,
record.ExceptionInformation[0],
)),
winnt::DBG_PRINTEXCEPTION_WIDE_C => {
Cow::Owned(String::from_utf16_lossy(slice::from_raw_parts(
record.ExceptionInformation[1] as *const u16,
record.ExceptionInformation[0],
)))
}
_ => return excpt::EXCEPTION_CONTINUE_SEARCH,
};
let message = match message.strip_prefix("D3D12 ") {
Some(msg) => msg
.trim_end_matches("\n\0")
.trim_end_matches("[ STATE_CREATION WARNING #0: UNKNOWN]"),
None => return excpt::EXCEPTION_CONTINUE_SEARCH,
};
let (message, level) = match MESSAGE_PREFIXES
.iter()
.find(|&&(prefix, _)| message.starts_with(prefix))
{
Some(&(prefix, level)) => (&message[prefix.len() + 2..], level),
None => (message, log::Level::Debug),
};
if level == log::Level::Warn && message.contains("#82") {
// This is are useless spammy warnings (#820, #821):
// "The application did not pass any clear value to resource creation"
return excpt::EXCEPTION_CONTINUE_SEARCH;
}
let _ = std::panic::catch_unwind(|| {
log::log!(level, "{}", message);
});
if cfg!(debug_assertions) && level == log::Level::Error {
// Set canary and continue
crate::VALIDATION_CANARY.set();
}
excpt::EXCEPTION_CONTINUE_EXECUTION
}
use super::SurfaceTarget;
use crate::auxil::{self, dxgi::result::HResult as _};
use std::sync::Arc;
impl Drop for super::Instance {
fn drop(&mut self) {
unsafe {
self.factory.destroy();
errhandlingapi::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _);
}
unsafe { self.factory.destroy() };
crate::auxil::dxgi::exception::unregister_exception_handler();
}
}
@ -83,9 +13,6 @@ impl crate::Instance<super::Api> for super::Instance {
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
let lib_main = native::D3D12Lib::new().map_err(|_| crate::InstanceError)?;
let lib_dxgi = native::DxgiLib::new().map_err(|_| crate::InstanceError)?;
let mut factory_flags = native::FactoryCreationFlags::empty();
if desc.flags.contains(crate::InstanceFlags::VALIDATION) {
// Enable debug layer
match lib_main.get_debug_interface() {
@ -102,45 +29,16 @@ impl crate::Instance<super::Api> for super::Instance {
log::warn!("Debug interface function for D3D12 not found: {:?}", err);
}
}
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
// `CreateDXGIFactory2` if the debug interface is actually available. So
// we check for whether it exists first.
match lib_dxgi.get_debug_interface1() {
Ok(pair) => match pair.into_result() {
Ok(debug_controller) => {
debug_controller.destroy();
factory_flags |= native::FactoryCreationFlags::DEBUG;
}
Err(err) => {
log::warn!("Unable to enable DXGI debug interface: {}", err);
}
},
Err(err) => {
log::warn!("Debug interface function for DXGI not found: {:?}", err);
}
}
// Intercept `OutputDebugString` calls
errhandlingapi::AddVectoredExceptionHandler(0, Some(output_debug_string_handler));
}
// Create DXGI factory
let factory = match lib_dxgi.create_factory2(factory_flags) {
Ok(pair) => match pair.into_result() {
Ok(factory) => factory,
Err(err) => {
log::warn!("Failed to create DXGI factory: {}", err);
return Err(crate::InstanceError);
}
},
Err(err) => {
log::warn!("Factory creation function for DXGI not found: {:?}", err);
return Err(crate::InstanceError);
}
};
// Create DXGIFactory4
let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory(
auxil::dxgi::factory::DxgiFactoryType::Factory4,
desc.flags,
)?;
Ok(Self {
// The call to create_factory will only succeed if we get a factory4, so this is safe.
factory,
library: Arc::new(lib_main),
_lib_dxgi: lib_dxgi,
@ -166,74 +64,11 @@ impl crate::Instance<super::Api> for super::Instance {
}
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
// Try to use high performance order by default (returns None on Windows < 1803)
let factory6 = match self.factory.cast::<dxgi1_6::IDXGIFactory6>().into_result() {
Ok(f6) => {
// It's okay to decrement the refcount here because we
// have another reference to the factory already owned by `self`.
f6.destroy();
Some(f6)
}
Err(err) => {
log::info!("Failed to cast DXGI to 1.6: {}", err);
None
}
};
let adapters = auxil::dxgi::factory::enumerate_adapters(self.factory);
// Enumerate adapters
let mut adapters = Vec::new();
for cur_index in 0.. {
let raw = match factory6 {
Some(factory) => {
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
let mut adapter2 = native::WeakPtr::<dxgi1_2::IDXGIAdapter2>::null();
let hr = factory.EnumAdapterByGpuPreference(
cur_index,
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&dxgi1_2::IDXGIAdapter2::uuidof(),
adapter2.mut_void(),
);
if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
adapter2
}
None => {
profiling::scope!("IDXGIFactory1::EnumAdapters1");
let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
let hr = self
.factory
.EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _);
if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
match adapter1.cast::<dxgi1_2::IDXGIAdapter2>().into_result() {
Ok(adapter2) => {
adapter1.destroy();
adapter2
}
Err(err) => {
log::error!("Failed casting to Adapter2: {}", err);
break;
}
}
}
};
adapters.extend(super::Adapter::expose(raw, &self.library, self.flags));
}
adapters
.into_iter()
.filter_map(|raw| super::Adapter::expose(raw, &self.library, self.flags))
.collect()
}
}

View File

@ -41,11 +41,13 @@ mod device;
mod instance;
mod view;
use crate::auxil::{self, dxgi::result::HResult as _};
use arrayvec::ArrayVec;
use parking_lot::Mutex;
use std::{borrow::Cow, ffi, mem, num::NonZeroU32, ptr, sync::Arc};
use std::{ffi, mem, num::NonZeroU32, sync::Arc};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_4, dxgitype, windef, winerror},
shared::{dxgi, dxgi1_4, dxgitype, windef, winerror},
um::{d3d12, dcomp, synchapi, winbase, winnt},
Interface as _,
};
@ -79,51 +81,12 @@ impl crate::Api for Api {
type ComputePipeline = ComputePipeline;
}
trait HResult<O> {
fn into_result(self) -> Result<O, Cow<'static, str>>;
fn into_device_result(self, description: &str) -> Result<O, crate::DeviceError>;
}
impl HResult<()> for i32 {
fn into_result(self) -> Result<(), Cow<'static, str>> {
if self >= 0 {
return Ok(());
}
let description = match self {
winerror::E_UNEXPECTED => "unexpected",
winerror::E_NOTIMPL => "not implemented",
winerror::E_OUTOFMEMORY => "out of memory",
winerror::E_INVALIDARG => "invalid argument",
_ => return Err(Cow::Owned(format!("0x{:X}", self as u32))),
};
Err(Cow::Borrowed(description))
}
fn into_device_result(self, description: &str) -> Result<(), crate::DeviceError> {
self.into_result().map_err(|err| {
log::error!("{} failed: {}", description, err);
if self == winerror::E_OUTOFMEMORY {
crate::DeviceError::OutOfMemory
} else {
crate::DeviceError::Lost
}
})
}
}
impl<T> HResult<T> for (T, i32) {
fn into_result(self) -> Result<T, Cow<'static, str>> {
self.1.into_result().map(|()| self.0)
}
fn into_device_result(self, description: &str) -> Result<T, crate::DeviceError> {
self.1.into_device_result(description).map(|()| self.0)
}
}
// Limited by D3D12's root signature size of 64. Each element takes 1 or 2 entries.
const MAX_ROOT_ELEMENTS: usize = 64;
const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10;
pub struct Instance {
factory: native::Factory4,
factory: native::DxgiFactory,
library: Arc<native::D3D12Lib>,
_lib_dxgi: native::DxgiLib,
flags: crate::InstanceFlags,
@ -163,7 +126,7 @@ enum SurfaceTarget {
}
pub struct Surface {
factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
factory: native::DxgiFactory,
target: SurfaceTarget,
swap_chain: Option<SwapChain>,
}
@ -197,7 +160,7 @@ struct Workarounds {
}
pub struct Adapter {
raw: native::WeakPtr<dxgi1_2::IDXGIAdapter2>,
raw: native::DxgiAdapter,
device: native::Device,
library: Arc<native::D3D12Lib>,
private_caps: PrivateCapabilities,
@ -592,7 +555,7 @@ impl crate::Surface<Api> for Surface {
_ => {}
}
let non_srgb_format = conv::map_texture_format_nosrgb(config.format);
let non_srgb_format = auxil::dxgi::conv::map_texture_format_nosrgb(config.format);
let swap_chain = match self.swap_chain.take() {
//Note: this path doesn't properly re-initialize all of the things
@ -615,54 +578,56 @@ impl crate::Surface<Api> for Surface {
raw
}
None => {
let mut swap_chain1 = native::WeakPtr::<dxgi1_2::IDXGISwapChain1>::null();
let raw_desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
AlphaMode: conv::map_acomposite_alpha_mode(config.composite_alpha_mode),
BufferCount: config.swap_chain_size,
Width: config.extent.width,
Height: config.extent.height,
Format: non_srgb_format,
Flags: flags,
BufferUsage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
let desc = native::SwapchainDesc {
alpha_mode: auxil::dxgi::conv::map_acomposite_alpha_mode(
config.composite_alpha_mode,
),
width: config.extent.width,
height: config.extent.height,
format: non_srgb_format,
stereo: false,
sample: native::SampleDesc {
count: 1,
quality: 0,
},
Scaling: dxgi1_2::DXGI_SCALING_STRETCH,
Stereo: 0,
SwapEffect: dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
buffer_usage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
buffer_count: config.swap_chain_size,
scaling: native::Scaling::Stretch,
swap_effect: native::SwapEffect::FlipDiscard,
flags,
};
let hr = {
match self.target {
SurfaceTarget::WndHandle(wnd_handle) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
self.factory.CreateSwapChainForHwnd(
let swap_chain1 = match self.target {
SurfaceTarget::Visual(_) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
self.factory
.unwrap_factory2()
.create_swapchain_for_composition(
device.present_queue.as_mut_ptr() as *mut _,
wnd_handle,
&raw_desc,
ptr::null(),
ptr::null_mut(),
swap_chain1.mut_void() as *mut *mut _,
&desc,
)
}
SurfaceTarget::Visual(_) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
self.factory.CreateSwapChainForComposition(
.into_result()
}
SurfaceTarget::WndHandle(hwnd) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
self.factory
.as_factory2()
.unwrap()
.create_swapchain_for_hwnd(
device.present_queue.as_mut_ptr() as *mut _,
&raw_desc,
ptr::null_mut(),
swap_chain1.mut_void() as *mut *mut _,
hwnd,
&desc,
)
}
.into_result()
}
};
if let Err(err) = hr.into_result() {
log::error!("SwapChain creation error: {}", err);
return Err(crate::SurfaceError::Other("swap chain creation"));
}
let swap_chain1 = match swap_chain1 {
Ok(s) => s,
Err(err) => {
log::error!("SwapChain creation error: {}", err);
return Err(crate::SurfaceError::Other("swap chain creation"));
}
};
match self.target {
SurfaceTarget::WndHandle(_) => {}

View File

@ -1,4 +1,4 @@
use super::conv;
use crate::auxil;
use std::mem;
use winapi::um::d3d12;
@ -19,8 +19,8 @@ impl crate::TextureViewDescriptor<'_> {
pub(super) fn to_internal(&self, texture: &super::Texture) -> ViewDescriptor {
ViewDescriptor {
dimension: self.dimension,
format: conv::map_texture_format(self.format),
format_nodepth: conv::map_texture_format_nodepth(self.format),
format: auxil::dxgi::conv::map_texture_format(self.format),
format_nodepth: auxil::dxgi::conv::map_texture_format_nodepth(self.format),
multisampled: texture.sample_count > 1,
mip_level_base: self.range.base_mip_level,
mip_level_count: match self.range.mip_level_count {

View File

@ -52,6 +52,8 @@ compile_error!("Metal API enabled on non-Apple OS. If your project is not using
#[cfg(all(feature = "dx12", not(windows)))]
compile_error!("DX12 API enabled on non-Windows OS. If your project is not using resolver=\"2\" in Cargo.toml, it should.");
#[cfg(all(feature = "dx11", windows))]
mod dx11;
#[cfg(all(feature = "dx12", windows))]
mod dx12;
mod empty;
@ -64,6 +66,8 @@ mod vulkan;
pub mod auxil;
pub mod api {
#[cfg(feature = "dx11")]
pub use super::dx11::Api as Dx11;
#[cfg(feature = "dx12")]
pub use super::dx12::Api as Dx12;
pub use super::empty::Api as Empty;