From 6c40f7835820c29891d01de0fb0f2e0b2d2c2d32 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 3 Mar 2022 17:24:23 -0500 Subject: [PATCH] hal/dx11: fully expose wgpu adapters --- Cargo.lock | 2 +- Cargo.toml | 2 +- wgpu-core/src/lib.rs | 4 +- wgpu-hal/src/dx11/adapter.rs | 242 +++++++++++++++++++++++++++++++++- wgpu-hal/src/dx11/device.rs | 21 +++ wgpu-hal/src/dx11/instance.rs | 9 ++ wgpu-hal/src/dx11/library.rs | 2 +- wgpu-hal/src/dx11/mod.rs | 12 +- wgpu-hal/src/dx12/adapter.rs | 1 - 9 files changed, 286 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a5b77ec947..089422515ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -436,7 +436,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "d3d12" version = "0.4.1" -source = "git+https://github.com/cwfitzgerald/d3d12-rs.git?rev=83d6486819887eb01266b2f86a2decb492acf12e#83d6486819887eb01266b2f86a2decb492acf12e" +source = "git+https://github.com/cwfitzgerald/d3d12-rs.git?rev=cb59d12ed831ed1755d6753ccecb6d76949624e9#cb59d12ed831ed1755d6753ccecb6d76949624e9" dependencies = [ "bitflags", "libloading", diff --git a/Cargo.toml b/Cargo.toml index 98e8335cc28..570df91d357 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ default-members = ["wgpu", "wgpu-hal", "wgpu-info"] [patch.crates-io] #naga = { path = "../naga" } #glow = { path = "../glow" } -d3d12 = { git = "https://github.com/cwfitzgerald/d3d12-rs.git", rev = "83d6486819887eb01266b2f86a2decb492acf12e" } +d3d12 = { git = "https://github.com/cwfitzgerald/d3d12-rs.git", rev = "cb59d12ed831ed1755d6753ccecb6d76949624e9" } # d3d12 = { path = "../d3d12-rs" } #metal = { path = "../metal-rs" } #web-sys = { path = "../wasm-bindgen/crates/web-sys" } diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 81b414429a3..edef81afc9f 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -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", diff --git a/wgpu-hal/src/dx11/adapter.rs b/wgpu-hal/src/dx11/adapter.rs index 98a1340148b..7ae35168177 100644 --- a/wgpu-hal/src/dx11/adapter.rs +++ b/wgpu-hal/src/dx11/adapter.rs @@ -1,3 +1,7 @@ +use std::num::NonZeroU64; + +use winapi::um::{d3d11, d3dcommon}; + impl crate::Adapter for super::Adapter { unsafe fn open( &self, @@ -27,8 +31,244 @@ impl super::Adapter { instance: &super::library::D3D11Lib, adapter: native::DxgiAdapter, ) -> Option> { + 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)?; - todo!() + // + // Query Features from d3d11 + // + + let d3d9_features = unsafe { + device.check_feature_support::( + d3d11::D3D11_FEATURE_D3D9_OPTIONS1, + ) + }; + + let d3d10_features = unsafe { + device.check_feature_support::( + d3d11::D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, + ) + }; + + let d3d11_features = unsafe { + device.check_feature_support::( + d3d11::D3D11_FEATURE_D3D11_OPTIONS, + ) + }; + + let d3d11_features1 = unsafe { + device.check_feature_support::( + d3d11::D3D11_FEATURE_D3D11_OPTIONS1, + ) + }; + + let d3d11_features2 = unsafe { + device.check_feature_support::( + d3d11::D3D11_FEATURE_D3D11_OPTIONS2, + ) + }; + + let d3d11_features3 = unsafe { + device.check_feature_support::( + 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, + _ => 16384, + }; + + let max_texture_dimension_3d = match feature_level { + FL9_1..=FL9_3 => 256, + _ => 2048, + }; + 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, + }) } } diff --git a/wgpu-hal/src/dx11/device.rs b/wgpu-hal/src/dx11/device.rs index 3922155ea12..7b095ba1df3 100644 --- a/wgpu-hal/src/dx11/device.rs +++ b/wgpu-hal/src/dx11/device.rs @@ -1,3 +1,9 @@ +use std::{ffi::c_void, mem}; + +use winapi::um::d3d11; + +use crate::auxil::dxgi::result::HResult; + impl crate::Device for super::Device { unsafe fn exit(self, queue: super::Queue) { todo!() @@ -217,3 +223,18 @@ impl crate::Queue for super::Queue { todo!() } } + +impl super::D3D11Device { + #[allow(trivial_casts)] // come on + pub unsafe fn check_feature_support(&self, feature: d3d11::D3D11_FEATURE) -> T { + let mut value = mem::zeroed::(); + let ret = self.CheckFeatureSupport( + feature, + &mut value as *mut T as *mut c_void, + mem::size_of::() as u32, + ); + assert_eq!(ret.into_result(), Ok(())); + + value + } +} diff --git a/wgpu-hal/src/dx11/instance.rs b/wgpu-hal/src/dx11/instance.rs index 484ad83e8e9..ac0fdbe597e 100644 --- a/wgpu-hal/src/dx11/instance.rs +++ b/wgpu-hal/src/dx11/instance.rs @@ -2,6 +2,15 @@ use crate::auxil; impl crate::Instance for super::Instance { unsafe fn init(desc: &crate::InstanceDescriptor) -> Result { + 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( diff --git a/wgpu-hal/src/dx11/library.rs b/wgpu-hal/src/dx11/library.rs index 268ce326f3e..1b2defe4f83 100644 --- a/wgpu-hal/src/dx11/library.rs +++ b/wgpu-hal/src/dx11/library.rs @@ -24,7 +24,7 @@ type D3D11CreateDeviceFun = unsafe extern "system" fn( *mut *mut d3d11::ID3D11DeviceContext, ) -> native::HRESULT; -pub struct D3D11Lib { +pub(super) struct D3D11Lib { // We use the os specific symbol to drop the lifetime parameter. // // SAFETY: we must ensure this outlives the Library. diff --git a/wgpu-hal/src/dx11/mod.rs b/wgpu-hal/src/dx11/mod.rs index ded1ae5bf68..ff9c49e0b3e 100644 --- a/wgpu-hal/src/dx11/mod.rs +++ b/wgpu-hal/src/dx11/mod.rs @@ -49,11 +49,16 @@ unsafe impl Sync for Instance {} pub struct Surface {} -pub struct Adapter {} +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)] - pub enum D3D11Device { + 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; @@ -62,6 +67,9 @@ native::weak_com_inheritance_chain! { pub struct Device {} +unsafe impl Send for Device {} +unsafe impl Sync for Device {} + pub struct Queue {} pub struct CommandEncoder {} diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 123eaf9968d..88959bdb475 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -420,7 +420,6 @@ impl crate::Adapter for super::Adapter { mem::size_of::() 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),