Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

838
vendor/wgpu-hal/src/dx12/adapter.rs vendored Normal file
View File

@@ -0,0 +1,838 @@
use std::{
mem::{size_of, size_of_val},
ptr,
sync::Arc,
thread,
};
use parking_lot::Mutex;
use windows::{
core::Interface as _,
Win32::{
Graphics::{Direct3D, Direct3D12, Dxgi},
UI::WindowsAndMessaging,
},
};
use super::D3D12Lib;
use crate::{
auxil::{
self,
dxgi::{factory::DxgiAdapter, result::HResult},
},
dx12::{shader_compilation, SurfaceTarget},
};
impl Drop for super::Adapter {
fn drop(&mut self) {
// Debug tracking alive objects
if !thread::panicking()
&& self
.private_caps
.instance_flags
.contains(wgt::InstanceFlags::VALIDATION)
{
unsafe {
self.report_live_objects();
}
}
}
}
impl super::Adapter {
pub unsafe fn report_live_objects(&self) {
if let Ok(debug_device) = self.raw.cast::<Direct3D12::ID3D12DebugDevice>() {
unsafe {
debug_device.ReportLiveDeviceObjects(
Direct3D12::D3D12_RLDO_SUMMARY | Direct3D12::D3D12_RLDO_IGNORE_INTERNAL,
)
}
.unwrap()
}
}
pub fn raw_adapter(&self) -> &DxgiAdapter {
&self.raw
}
pub(super) fn expose(
adapter: DxgiAdapter,
library: &Arc<D3D12Lib>,
instance_flags: wgt::InstanceFlags,
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
) -> Option<crate::ExposedAdapter<super::Api>> {
// Create the device so that we can get the capabilities.
let device = {
profiling::scope!("ID3D12Device::create_device");
library
.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0)
.ok()??
};
profiling::scope!("feature queries");
// Detect the highest supported feature level.
let d3d_feature_level = [
Direct3D::D3D_FEATURE_LEVEL_12_1,
Direct3D::D3D_FEATURE_LEVEL_12_0,
Direct3D::D3D_FEATURE_LEVEL_11_1,
Direct3D::D3D_FEATURE_LEVEL_11_0,
];
let mut device_levels = Direct3D12::D3D12_FEATURE_DATA_FEATURE_LEVELS {
NumFeatureLevels: d3d_feature_level.len() as u32,
pFeatureLevelsRequested: d3d_feature_level.as_ptr().cast(),
MaxSupportedFeatureLevel: Default::default(),
};
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_FEATURE_LEVELS,
<*mut _>::cast(&mut device_levels),
size_of_val(&device_levels) as u32,
)
}
.unwrap();
let max_feature_level = device_levels.MaxSupportedFeatureLevel;
// We have found a possible adapter.
// Acquire the device information.
let desc = unsafe { adapter.GetDesc2() }.unwrap();
let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description);
let mut features_architecture = Direct3D12::D3D12_FEATURE_DATA_ARCHITECTURE::default();
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_ARCHITECTURE,
<*mut _>::cast(&mut features_architecture),
size_of_val(&features_architecture) as u32,
)
}
.unwrap();
let mut workarounds = super::Workarounds::default();
let info = wgt::AdapterInfo {
backend: wgt::Backend::Dx12,
name: device_name,
vendor: desc.VendorId,
device: desc.DeviceId,
device_type: if Dxgi::DXGI_ADAPTER_FLAG(desc.Flags as i32)
.contains(Dxgi::DXGI_ADAPTER_FLAG_SOFTWARE)
{
workarounds.avoid_cpu_descriptor_overwrites = true;
wgt::DeviceType::Cpu
} else if features_architecture.UMA.as_bool() {
wgt::DeviceType::IntegratedGpu
} else {
wgt::DeviceType::DiscreteGpu
},
driver: {
if let Ok(i) = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } {
const MASK: i64 = 0xFFFF;
format!(
"{}.{}.{}.{}",
i >> 48,
(i >> 32) & MASK,
(i >> 16) & MASK,
i & MASK
)
} else {
String::new()
}
},
driver_info: String::new(),
};
let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default();
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS,
<*mut _>::cast(&mut options),
size_of_val(&options) as u32,
)
}
.unwrap();
let _depth_bounds_test_supported = {
let mut features2 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS2::default();
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS2,
<*mut _>::cast(&mut features2),
size_of_val(&features2) as u32,
)
}
.is_ok()
&& features2.DepthBoundsTestSupported.as_bool()
};
let casting_fully_typed_format_supported = {
let mut features3 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS3::default();
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3,
<*mut _>::cast(&mut features3),
size_of_val(&features3) as u32,
)
}
.is_ok()
&& features3.CastingFullyTypedFormatSupported.as_bool()
};
let heap_create_not_zeroed = {
// For D3D12_HEAP_FLAG_CREATE_NOT_ZEROED we just need to
// make sure that options7 can be queried. See also:
// https://devblogs.microsoft.com/directx/coming-to-directx-12-more-control-over-memory-allocation/
let mut features7 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS7::default();
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS7,
<*mut _>::cast(&mut features7),
size_of_val(&features7) as u32,
)
}
.is_ok()
};
let shader_model = if dxc_container.is_none() {
naga::back::hlsl::ShaderModel::V5_1
} else {
let mut versions = [
Direct3D12::D3D_SHADER_MODEL_6_7,
Direct3D12::D3D_SHADER_MODEL_6_6,
Direct3D12::D3D_SHADER_MODEL_6_5,
Direct3D12::D3D_SHADER_MODEL_6_4,
Direct3D12::D3D_SHADER_MODEL_6_3,
Direct3D12::D3D_SHADER_MODEL_6_2,
Direct3D12::D3D_SHADER_MODEL_6_1,
Direct3D12::D3D_SHADER_MODEL_6_0,
]
.iter();
let highest_shader_model = loop {
if let Some(&sm) = versions.next() {
let mut sm = Direct3D12::D3D12_FEATURE_DATA_SHADER_MODEL {
HighestShaderModel: sm,
};
if unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_SHADER_MODEL,
<*mut _>::cast(&mut sm),
size_of_val(&sm) as u32,
)
}
.is_ok()
{
break sm.HighestShaderModel;
}
} else {
break Direct3D12::D3D_SHADER_MODEL_5_1;
}
};
match highest_shader_model {
Direct3D12::D3D_SHADER_MODEL_5_1 => return None, // don't expose this adapter if it doesn't support DXIL
Direct3D12::D3D_SHADER_MODEL_6_0 => naga::back::hlsl::ShaderModel::V6_0,
Direct3D12::D3D_SHADER_MODEL_6_1 => naga::back::hlsl::ShaderModel::V6_1,
Direct3D12::D3D_SHADER_MODEL_6_2 => naga::back::hlsl::ShaderModel::V6_2,
Direct3D12::D3D_SHADER_MODEL_6_3 => naga::back::hlsl::ShaderModel::V6_3,
Direct3D12::D3D_SHADER_MODEL_6_4 => naga::back::hlsl::ShaderModel::V6_4,
Direct3D12::D3D_SHADER_MODEL_6_5 => naga::back::hlsl::ShaderModel::V6_5,
Direct3D12::D3D_SHADER_MODEL_6_6 => naga::back::hlsl::ShaderModel::V6_6,
Direct3D12::D3D_SHADER_MODEL_6_7 => naga::back::hlsl::ShaderModel::V6_7,
_ => unreachable!(),
}
};
let private_caps = super::PrivateCapabilities {
instance_flags,
heterogeneous_resource_heaps: options.ResourceHeapTier
!= Direct3D12::D3D12_RESOURCE_HEAP_TIER_1,
memory_architecture: if features_architecture.UMA.as_bool() {
super::MemoryArchitecture::Unified {
cache_coherent: features_architecture.CacheCoherentUMA.as_bool(),
}
} else {
super::MemoryArchitecture::NonUnified
},
heap_create_not_zeroed,
casting_fully_typed_format_supported,
// See https://github.com/gfx-rs/wgpu/issues/3552
suballocation_supported: !info.name.contains("Iris(R) Xe"),
shader_model,
};
// Theoretically vram limited, but in practice 2^20 is the limit
let tier3_practical_descriptor_limit = 1 << 20;
let (full_heap_count, uav_count) = match options.ResourceBindingTier {
Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => {
let uav_count = match max_feature_level {
Direct3D::D3D_FEATURE_LEVEL_11_0 => 8,
_ => 64,
};
(
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
uav_count,
)
}
Direct3D12::D3D12_RESOURCE_BINDING_TIER_2 => (
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2,
64,
),
Direct3D12::D3D12_RESOURCE_BINDING_TIER_3 => (
tier3_practical_descriptor_limit,
tier3_practical_descriptor_limit,
),
other => {
log::warn!("Unknown resource binding tier {:?}", other);
(
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
8,
)
}
};
// these should always be available on d3d12
let mut features = wgt::Features::empty()
| wgt::Features::DEPTH_CLIP_CONTROL
| wgt::Features::DEPTH32FLOAT_STENCIL8
| wgt::Features::INDIRECT_FIRST_INSTANCE
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS
| wgt::Features::MULTI_DRAW_INDIRECT
| wgt::Features::MULTI_DRAW_INDIRECT_COUNT
| wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER
| wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO
| wgt::Features::POLYGON_MODE_LINE
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
| wgt::Features::TIMESTAMP_QUERY
| wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS
| wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES
| wgt::Features::TEXTURE_COMPRESSION_BC
| wgt::Features::TEXTURE_COMPRESSION_BC_SLICED_3D
| wgt::Features::CLEAR_TEXTURE
| wgt::Features::TEXTURE_FORMAT_16BIT_NORM
| wgt::Features::PUSH_CONSTANTS
| wgt::Features::SHADER_PRIMITIVE_INDEX
| wgt::Features::RG11B10UFLOAT_RENDERABLE
| wgt::Features::DUAL_SOURCE_BLENDING
| wgt::Features::TEXTURE_FORMAT_NV12
| wgt::Features::FLOAT32_FILTERABLE
| wgt::Features::TEXTURE_ATOMIC;
//TODO: in order to expose this, we need to run a compute shader
// that extract the necessary statistics out of the D3D12 result.
// Alternatively, we could allocate a buffer for the query set,
// write the results there, and issue a bunch of copy commands.
//| wgt::Features::PIPELINE_STATISTICS_QUERY
if max_feature_level.0 >= Direct3D::D3D_FEATURE_LEVEL_11_1.0 {
features |= wgt::Features::VERTEX_WRITABLE_STORAGE;
}
features.set(
wgt::Features::CONSERVATIVE_RASTERIZATION,
options.ConservativeRasterizationTier
!= Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
);
features.set(
wgt::Features::TEXTURE_BINDING_ARRAY
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
shader_model >= naga::back::hlsl::ShaderModel::V5_1,
);
// See note below the table https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
features.set(
wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY,
options.ResourceBindingTier.0 >= Direct3D12::D3D12_RESOURCE_BINDING_TIER_3.0,
);
let bgra8unorm_storage_supported = {
let mut bgra8unorm_info = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
..Default::default()
};
let hr = unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
<*mut _>::cast(&mut bgra8unorm_info),
size_of_val(&bgra8unorm_info) as u32,
)
};
hr.is_ok()
&& bgra8unorm_info
.Support2
.contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)
};
features.set(
wgt::Features::BGRA8UNORM_STORAGE,
bgra8unorm_storage_supported,
);
let mut features1 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS1::default();
let hr = unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS1,
<*mut _>::cast(&mut features1),
size_of_val(&features1) as u32,
)
};
features.set(
wgt::Features::SHADER_INT64,
shader_model >= naga::back::hlsl::ShaderModel::V6_0
&& hr.is_ok()
&& features1.Int64ShaderOps.as_bool(),
);
features.set(
wgt::Features::TEXTURE_INT64_ATOMIC,
shader_model >= naga::back::hlsl::ShaderModel::V6_6
&& hr.is_ok()
&& features1.Int64ShaderOps.as_bool(),
);
features.set(
wgt::Features::SUBGROUP,
shader_model >= naga::back::hlsl::ShaderModel::V6_0
&& hr.is_ok()
&& features1.WaveOps.as_bool(),
);
let mut features5 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS5::default();
let has_features5 = unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS5,
<*mut _>::cast(&mut features5),
size_of_val(&features5) as u32,
)
}
.is_ok();
// Since all features for raytracing pipeline (geometry index) and ray queries both come
// from here, there is no point in adding an extra call here given that there will be no
// feature using EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE if all these are not met.
// Once ray tracing pipelines are supported they also will go here
features.set(
wgt::Features::EXPERIMENTAL_RAY_QUERY
| wgt::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE,
features5.RaytracingTier == Direct3D12::D3D12_RAYTRACING_TIER_1_1
&& shader_model >= naga::back::hlsl::ShaderModel::V6_5
&& has_features5,
);
let atomic_int64_on_typed_resource_supported = {
let mut features9 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS9::default();
unsafe {
device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS9,
<*mut _>::cast(&mut features9),
size_of_val(&features9) as u32,
)
}
.is_ok()
&& features9.AtomicInt64OnGroupSharedSupported.as_bool()
&& features9.AtomicInt64OnTypedResourceSupported.as_bool()
};
features.set(
wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX,
atomic_int64_on_typed_resource_supported,
);
// TODO: Determine if IPresentationManager is supported
let presentation_timer = auxil::dxgi::time::PresentationTimer::new_dxgi();
let base = wgt::Limits::default();
let mut downlevel = wgt::DownlevelCapabilities::default();
// https://github.com/gfx-rs/wgpu/issues/2471
downlevel.flags -=
wgt::DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW;
// See https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-feature-levels#feature-level-support
let max_color_attachments = 8;
let max_color_attachment_bytes_per_sample =
max_color_attachments * wgt::TextureFormat::MAX_TARGET_PIXEL_BYTE_COST;
Some(crate::ExposedAdapter {
adapter: super::Adapter {
raw: adapter,
device,
library: Arc::clone(library),
private_caps,
presentation_timer,
workarounds,
dxc_container,
},
info,
features,
capabilities: crate::Capabilities {
limits: wgt::Limits {
max_texture_dimension_1d: Direct3D12::D3D12_REQ_TEXTURE1D_U_DIMENSION,
max_texture_dimension_2d: Direct3D12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
.min(Direct3D12::D3D12_REQ_TEXTURECUBE_DIMENSION),
max_texture_dimension_3d: Direct3D12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
max_texture_array_layers: Direct3D12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
max_bind_groups: crate::MAX_BIND_GROUPS as u32,
max_bindings_per_bind_group: 65535,
// dynamic offsets take a root constant, so we expose the minimum here
max_dynamic_uniform_buffers_per_pipeline_layout: base
.max_dynamic_uniform_buffers_per_pipeline_layout,
max_dynamic_storage_buffers_per_pipeline_layout: base
.max_dynamic_storage_buffers_per_pipeline_layout,
max_sampled_textures_per_shader_stage: match options.ResourceBindingTier {
Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => 128,
_ => full_heap_count,
},
max_samplers_per_shader_stage: match options.ResourceBindingTier {
Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => 16,
_ => Direct3D12::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE,
},
// these both account towards `uav_count`, but we can't express the limit as as sum
// of the two, so we divide it by 4 to account for the worst case scenario
// (2 shader stages, with both using 16 storage textures and 16 storage buffers)
max_storage_buffers_per_shader_stage: uav_count / 4,
max_storage_textures_per_shader_stage: uav_count / 4,
max_uniform_buffers_per_shader_stage: full_heap_count,
max_uniform_buffer_binding_size:
Direct3D12::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16,
max_storage_buffer_binding_size: auxil::MAX_I32_BINDING_SIZE,
max_vertex_buffers: Direct3D12::D3D12_VS_INPUT_REGISTER_COUNT
.min(crate::MAX_VERTEX_BUFFERS as u32),
max_vertex_attributes: Direct3D12::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
max_vertex_buffer_array_stride: Direct3D12::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES,
min_subgroup_size: 4, // Not using `features1.WaveLaneCountMin` as it is unreliable
max_subgroup_size: 128,
// The push constants are part of the root signature which
// has a limit of 64 DWORDS (256 bytes), but other resources
// also share the root signature:
//
// - push constants consume a `DWORD` for each `4 bytes` of data
// - If a bind group has buffers it will consume a `DWORD`
// for the descriptor table
// - If a bind group has samplers it will consume a `DWORD`
// for the descriptor table
// - Each dynamic buffer will consume `2 DWORDs` for the
// root descriptor
// - The special constants buffer count as constants
//
// Since we can't know beforehand all root signatures that
// will be created, the max size to be used for push
// constants needs to be set to a reasonable number instead.
//
// Source: https://learn.microsoft.com/en-us/windows/win32/direct3d12/root-signature-limits#memory-limits-and-costs
max_push_constant_size: 128,
min_uniform_buffer_offset_alignment:
Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT,
min_storage_buffer_offset_alignment: 4,
max_inter_stage_shader_components: base.max_inter_stage_shader_components,
max_color_attachments,
max_color_attachment_bytes_per_sample,
max_compute_workgroup_storage_size: base.max_compute_workgroup_storage_size, //TODO?
max_compute_invocations_per_workgroup:
Direct3D12::D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP,
max_compute_workgroup_size_x: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_X,
max_compute_workgroup_size_y: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_Y,
max_compute_workgroup_size_z: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_Z,
max_compute_workgroups_per_dimension:
Direct3D12::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
// Dx12 does not expose a maximum buffer size in the API.
// This limit is chosen to avoid potential issues with drivers should they internally
// store buffer sizes using 32 bit ints (a situation we have already encountered with vulkan).
max_buffer_size: i32::MAX as u64,
max_non_sampler_bindings: 1_000_000,
},
alignments: crate::Alignments {
buffer_copy_offset: wgt::BufferSize::new(
Direct3D12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64,
)
.unwrap(),
buffer_copy_pitch: wgt::BufferSize::new(
Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
)
.unwrap(),
// Direct3D correctly bounds-checks all array accesses:
// https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#18.6.8.2%20Device%20Memory%20Reads
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
raw_tlas_instance_size: size_of::<Direct3D12::D3D12_RAYTRACING_INSTANCE_DESC>(),
ray_tracing_scratch_buffer_alignment:
Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT,
},
downlevel,
},
})
}
}
impl crate::Adapter for super::Adapter {
type A = super::Api;
unsafe fn open(
&self,
_features: wgt::Features,
limits: &wgt::Limits,
memory_hints: &wgt::MemoryHints,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
let queue: Direct3D12::ID3D12CommandQueue = {
profiling::scope!("ID3D12Device::CreateCommandQueue");
unsafe {
self.device
.CreateCommandQueue(&Direct3D12::D3D12_COMMAND_QUEUE_DESC {
Type: Direct3D12::D3D12_COMMAND_LIST_TYPE_DIRECT,
Priority: Direct3D12::D3D12_COMMAND_QUEUE_PRIORITY_NORMAL.0,
Flags: Direct3D12::D3D12_COMMAND_QUEUE_FLAG_NONE,
NodeMask: 0,
})
}
.into_device_result("Queue creation")?
};
let device = super::Device::new(
self.device.clone(),
queue.clone(),
limits,
memory_hints,
self.private_caps,
&self.library,
self.dxc_container.clone(),
)?;
Ok(crate::OpenDevice {
device,
queue: super::Queue {
raw: queue,
temp_lists: Mutex::new(Vec::new()),
},
})
}
unsafe fn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> crate::TextureFormatCapabilities {
use crate::TextureFormatCapabilities as Tfc;
let raw_format = match auxil::dxgi::conv::map_texture_format_failable(format) {
Some(f) => f,
None => return Tfc::empty(),
};
let srv_uav_format = if format.is_combined_depth_stencil_format() {
auxil::dxgi::conv::map_texture_format_for_srv_uav(
format,
// use the depth aspect here as opposed to stencil since it has more capabilities
crate::FormatAspects::DEPTH,
)
} else {
auxil::dxgi::conv::map_texture_format_for_srv_uav(
format,
crate::FormatAspects::from(format),
)
}
.unwrap();
let mut data = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: raw_format,
..Default::default()
};
unsafe {
self.device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
<*mut _>::cast(&mut data),
size_of_val(&data) as u32,
)
}
.unwrap();
// Because we use a different format for SRV and UAV views of depth textures, we need to check
// the features that use SRV/UAVs using the no-depth format.
let mut data_srv_uav = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: srv_uav_format,
Support1: Direct3D12::D3D12_FORMAT_SUPPORT1_NONE,
Support2: Direct3D12::D3D12_FORMAT_SUPPORT2_NONE,
};
if raw_format != srv_uav_format {
// Only-recheck if we're using a different format
unsafe {
self.device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
ptr::addr_of_mut!(data_srv_uav).cast(),
size_of::<Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as u32,
)
}
.unwrap();
} else {
// Same format, just copy over.
data_srv_uav = data;
}
let mut caps = Tfc::COPY_SRC | Tfc::COPY_DST;
// Cannot use the contains() helper, and windows-rs doesn't provide a .intersect() helper
let is_texture = (data.Support1
& (Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE1D
| Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE2D
| Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE3D
| Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE))
.0
!= 0;
// SRVs use srv_uav_format
caps.set(
Tfc::SAMPLED,
is_texture
&& data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD),
);
caps.set(
Tfc::SAMPLED_LINEAR,
data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE),
);
caps.set(
Tfc::COLOR_ATTACHMENT,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET),
);
caps.set(
Tfc::COLOR_ATTACHMENT_BLEND,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_BLENDABLE),
);
caps.set(
Tfc::DEPTH_STENCIL_ATTACHMENT,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL),
);
// UAVs use srv_uav_format
caps.set(
Tfc::STORAGE_READ_ONLY,
data_srv_uav
.Support2
.contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD),
);
caps.set(
Tfc::STORAGE_ATOMIC,
data_srv_uav
.Support2
.contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX),
);
caps.set(
Tfc::STORAGE_WRITE_ONLY,
data_srv_uav
.Support2
.contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE),
);
caps.set(
Tfc::STORAGE_READ_WRITE,
caps.contains(Tfc::STORAGE_READ_ONLY | Tfc::STORAGE_WRITE_ONLY),
);
// We load via UAV/SRV so use srv_uav_format
let no_msaa_load = caps.contains(Tfc::SAMPLED)
&& !data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD);
let no_msaa_target = (data.Support1
& (Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET
| Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL))
.0
!= 0
&& !data
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET);
caps.set(
Tfc::MULTISAMPLE_RESOLVE,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE),
);
let mut ms_levels = Direct3D12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
Format: raw_format,
SampleCount: 0,
Flags: Direct3D12::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE,
NumQualityLevels: 0,
};
let mut set_sample_count = |sc: u32, tfc: Tfc| {
ms_levels.SampleCount = sc;
if unsafe {
self.device.CheckFeatureSupport(
Direct3D12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
<*mut _>::cast(&mut ms_levels),
size_of_val(&ms_levels) as u32,
)
}
.is_ok()
&& ms_levels.NumQualityLevels != 0
{
caps.set(tfc, !no_msaa_load && !no_msaa_target);
}
};
set_sample_count(2, Tfc::MULTISAMPLE_X2);
set_sample_count(4, Tfc::MULTISAMPLE_X4);
set_sample_count(8, Tfc::MULTISAMPLE_X8);
set_sample_count(16, Tfc::MULTISAMPLE_X16);
caps
}
unsafe fn surface_capabilities(
&self,
surface: &super::Surface,
) -> Option<crate::SurfaceCapabilities> {
let current_extent = {
match surface.target {
SurfaceTarget::WndHandle(wnd_handle) => {
let mut rect = Default::default();
if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok()
{
Some(wgt::Extent3d {
width: (rect.right - rect.left) as u32,
height: (rect.bottom - rect.top) as u32,
depth_or_array_layers: 1,
})
} else {
log::warn!("Unable to get the window client rect");
None
}
}
SurfaceTarget::Visual(_)
| SurfaceTarget::SurfaceHandle(_)
| SurfaceTarget::SwapChainPanel(_) => None,
}
};
let mut present_modes = vec![wgt::PresentMode::Mailbox, wgt::PresentMode::Fifo];
if surface.supports_allow_tearing {
present_modes.push(wgt::PresentMode::Immediate);
}
Some(crate::SurfaceCapabilities {
formats: vec![
wgt::TextureFormat::Bgra8UnormSrgb,
wgt::TextureFormat::Bgra8Unorm,
wgt::TextureFormat::Rgba8UnormSrgb,
wgt::TextureFormat::Rgba8Unorm,
wgt::TextureFormat::Rgb10a2Unorm,
wgt::TextureFormat::Rgba16Float,
],
// See https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgidevice1-setmaximumframelatency
maximum_frame_latency: 1..=16,
current_extent,
usage: crate::TextureUses::COLOR_TARGET
| crate::TextureUses::COPY_SRC
| crate::TextureUses::COPY_DST,
present_modes,
composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque],
})
}
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
wgt::PresentationTimestamp(self.presentation_timer.get_timestamp_ns())
}
}

1463
vendor/wgpu-hal/src/dx12/command.rs vendored Normal file

File diff suppressed because it is too large Load Diff

400
vendor/wgpu-hal/src/dx12/conv.rs vendored Normal file
View File

@@ -0,0 +1,400 @@
use windows::Win32::Graphics::{Direct3D, Direct3D12};
pub fn map_buffer_usage_to_resource_flags(
usage: crate::BufferUses,
) -> Direct3D12::D3D12_RESOURCE_FLAGS {
let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE;
if usage.contains(crate::BufferUses::STORAGE_READ_WRITE) {
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
flags
}
pub fn map_texture_dimension(dim: wgt::TextureDimension) -> Direct3D12::D3D12_RESOURCE_DIMENSION {
match dim {
wgt::TextureDimension::D1 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE1D,
wgt::TextureDimension::D2 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
wgt::TextureDimension::D3 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE3D,
}
}
pub fn map_texture_usage_to_resource_flags(
usage: crate::TextureUses,
) -> Direct3D12::D3D12_RESOURCE_FLAGS {
let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE;
if usage.contains(crate::TextureUses::COLOR_TARGET) {
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
}
if usage.intersects(
crate::TextureUses::DEPTH_STENCIL_READ | crate::TextureUses::DEPTH_STENCIL_WRITE,
) {
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
if !usage.contains(crate::TextureUses::RESOURCE) {
flags |= Direct3D12::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
}
}
if usage.intersects(
crate::TextureUses::STORAGE_READ_ONLY
| crate::TextureUses::STORAGE_WRITE_ONLY
| crate::TextureUses::STORAGE_READ_WRITE,
) {
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
flags
}
pub fn map_address_mode(mode: wgt::AddressMode) -> Direct3D12::D3D12_TEXTURE_ADDRESS_MODE {
use wgt::AddressMode as Am;
match mode {
Am::Repeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_WRAP,
Am::MirrorRepeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
Am::ClampToEdge => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
Am::ClampToBorder => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_BORDER,
//Am::MirrorClamp => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
}
}
pub fn map_filter_mode(mode: wgt::FilterMode) -> Direct3D12::D3D12_FILTER_TYPE {
match mode {
wgt::FilterMode::Nearest => Direct3D12::D3D12_FILTER_TYPE_POINT,
wgt::FilterMode::Linear => Direct3D12::D3D12_FILTER_TYPE_LINEAR,
}
}
pub fn map_comparison(func: wgt::CompareFunction) -> Direct3D12::D3D12_COMPARISON_FUNC {
use wgt::CompareFunction as Cf;
match func {
Cf::Never => Direct3D12::D3D12_COMPARISON_FUNC_NEVER,
Cf::Less => Direct3D12::D3D12_COMPARISON_FUNC_LESS,
Cf::LessEqual => Direct3D12::D3D12_COMPARISON_FUNC_LESS_EQUAL,
Cf::Equal => Direct3D12::D3D12_COMPARISON_FUNC_EQUAL,
Cf::GreaterEqual => Direct3D12::D3D12_COMPARISON_FUNC_GREATER_EQUAL,
Cf::Greater => Direct3D12::D3D12_COMPARISON_FUNC_GREATER,
Cf::NotEqual => Direct3D12::D3D12_COMPARISON_FUNC_NOT_EQUAL,
Cf::Always => Direct3D12::D3D12_COMPARISON_FUNC_ALWAYS,
}
}
pub fn map_border_color(border_color: Option<wgt::SamplerBorderColor>) -> [f32; 4] {
use wgt::SamplerBorderColor as Sbc;
match border_color {
Some(Sbc::TransparentBlack) | Some(Sbc::Zero) | None => [0.0; 4],
Some(Sbc::OpaqueBlack) => [0.0, 0.0, 0.0, 1.0],
Some(Sbc::OpaqueWhite) => [1.0; 4],
}
}
pub fn map_visibility(visibility: wgt::ShaderStages) -> Direct3D12::D3D12_SHADER_VISIBILITY {
match visibility {
wgt::ShaderStages::VERTEX => Direct3D12::D3D12_SHADER_VISIBILITY_VERTEX,
wgt::ShaderStages::FRAGMENT => Direct3D12::D3D12_SHADER_VISIBILITY_PIXEL,
_ => Direct3D12::D3D12_SHADER_VISIBILITY_ALL,
}
}
pub fn map_binding_type(ty: &wgt::BindingType) -> Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE {
use wgt::BindingType as Bt;
match *ty {
Bt::Sampler { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
Bt::Buffer {
ty: wgt::BufferBindingType::Uniform,
..
} => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { read_only: true },
..
}
| Bt::Texture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { read_only: false },
..
}
| Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
Bt::AccelerationStructure => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
}
}
pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> Direct3D12::D3D12_RESOURCE_STATES {
use crate::BufferUses as Bu;
let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON;
if usage.intersects(Bu::COPY_SRC) {
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE;
}
if usage.intersects(Bu::COPY_DST) {
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST;
}
if usage.intersects(Bu::INDEX) {
state |= Direct3D12::D3D12_RESOURCE_STATE_INDEX_BUFFER;
}
if usage.intersects(Bu::VERTEX | Bu::UNIFORM) {
state |= Direct3D12::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
}
if usage.intersects(Bu::STORAGE_READ_WRITE) {
state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
} else if usage.intersects(Bu::STORAGE_READ_ONLY) {
state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}
if usage.intersects(Bu::INDIRECT) {
state |= Direct3D12::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
}
state
}
pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> Direct3D12::D3D12_RESOURCE_STATES {
use crate::TextureUses as Tu;
let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON;
//Note: `RESOLVE_SOURCE` and `RESOLVE_DEST` are not used here
//Note: `PRESENT` is the same as `COMMON`
if usage == crate::TextureUses::UNINITIALIZED {
return state;
}
if usage.intersects(Tu::COPY_SRC) {
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE;
}
if usage.intersects(Tu::COPY_DST) {
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST;
}
if usage.intersects(Tu::RESOURCE) {
state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}
if usage.intersects(Tu::COLOR_TARGET) {
state |= Direct3D12::D3D12_RESOURCE_STATE_RENDER_TARGET;
}
if usage.intersects(Tu::DEPTH_STENCIL_READ) {
state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_READ;
}
if usage.intersects(Tu::DEPTH_STENCIL_WRITE) {
state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
if usage.intersects(Tu::STORAGE_READ_ONLY | Tu::STORAGE_WRITE_ONLY | Tu::STORAGE_READ_WRITE) {
state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
state
}
pub fn map_topology(
topology: wgt::PrimitiveTopology,
) -> (
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY,
) {
match topology {
wgt::PrimitiveTopology::PointList => (
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
),
wgt::PrimitiveTopology::LineList => (
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINELIST,
),
wgt::PrimitiveTopology::LineStrip => (
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
),
wgt::PrimitiveTopology::TriangleList => (
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
),
wgt::PrimitiveTopology::TriangleStrip => (
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
),
}
}
pub fn map_polygon_mode(mode: wgt::PolygonMode) -> Direct3D12::D3D12_FILL_MODE {
match mode {
wgt::PolygonMode::Fill => Direct3D12::D3D12_FILL_MODE_SOLID,
wgt::PolygonMode::Line => Direct3D12::D3D12_FILL_MODE_WIREFRAME,
wgt::PolygonMode::Point => panic!(
"{:?} is not enabled for this backend",
wgt::Features::POLYGON_MODE_POINT
),
}
}
/// D3D12 doesn't support passing factors ending in `_COLOR` for alpha blending
/// (see <https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc>).
/// Therefore this function takes an additional `is_alpha` argument
/// which if set will return an equivalent `_ALPHA` factor.
fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> Direct3D12::D3D12_BLEND {
use wgt::BlendFactor as Bf;
match factor {
Bf::Zero => Direct3D12::D3D12_BLEND_ZERO,
Bf::One => Direct3D12::D3D12_BLEND_ONE,
Bf::Src if is_alpha => Direct3D12::D3D12_BLEND_SRC_ALPHA,
Bf::Src => Direct3D12::D3D12_BLEND_SRC_COLOR,
Bf::OneMinusSrc if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA,
Bf::OneMinusSrc => Direct3D12::D3D12_BLEND_INV_SRC_COLOR,
Bf::Dst if is_alpha => Direct3D12::D3D12_BLEND_DEST_ALPHA,
Bf::Dst => Direct3D12::D3D12_BLEND_DEST_COLOR,
Bf::OneMinusDst if is_alpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA,
Bf::OneMinusDst => Direct3D12::D3D12_BLEND_INV_DEST_COLOR,
Bf::SrcAlpha => Direct3D12::D3D12_BLEND_SRC_ALPHA,
Bf::OneMinusSrcAlpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA,
Bf::DstAlpha => Direct3D12::D3D12_BLEND_DEST_ALPHA,
Bf::OneMinusDstAlpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA,
Bf::Constant => Direct3D12::D3D12_BLEND_BLEND_FACTOR,
Bf::OneMinusConstant => Direct3D12::D3D12_BLEND_INV_BLEND_FACTOR,
Bf::SrcAlphaSaturated => Direct3D12::D3D12_BLEND_SRC_ALPHA_SAT,
Bf::Src1 if is_alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA,
Bf::Src1 => Direct3D12::D3D12_BLEND_SRC1_COLOR,
Bf::OneMinusSrc1 if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA,
Bf::OneMinusSrc1 => Direct3D12::D3D12_BLEND_INV_SRC1_COLOR,
Bf::Src1Alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA,
Bf::OneMinusSrc1Alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA,
}
}
fn map_blend_component(
component: &wgt::BlendComponent,
is_alpha: bool,
) -> (
Direct3D12::D3D12_BLEND_OP,
Direct3D12::D3D12_BLEND,
Direct3D12::D3D12_BLEND,
) {
let raw_op = match component.operation {
wgt::BlendOperation::Add => Direct3D12::D3D12_BLEND_OP_ADD,
wgt::BlendOperation::Subtract => Direct3D12::D3D12_BLEND_OP_SUBTRACT,
wgt::BlendOperation::ReverseSubtract => Direct3D12::D3D12_BLEND_OP_REV_SUBTRACT,
wgt::BlendOperation::Min => Direct3D12::D3D12_BLEND_OP_MIN,
wgt::BlendOperation::Max => Direct3D12::D3D12_BLEND_OP_MAX,
};
let raw_src = map_blend_factor(component.src_factor, is_alpha);
let raw_dst = map_blend_factor(component.dst_factor, is_alpha);
(raw_op, raw_src, raw_dst)
}
pub fn map_render_targets(
color_targets: &[Option<wgt::ColorTargetState>],
) -> [Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC;
Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] {
let dummy_target = Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC {
BlendEnable: false.into(),
LogicOpEnable: false.into(),
SrcBlend: Direct3D12::D3D12_BLEND_ZERO,
DestBlend: Direct3D12::D3D12_BLEND_ZERO,
BlendOp: Direct3D12::D3D12_BLEND_OP_ADD,
SrcBlendAlpha: Direct3D12::D3D12_BLEND_ZERO,
DestBlendAlpha: Direct3D12::D3D12_BLEND_ZERO,
BlendOpAlpha: Direct3D12::D3D12_BLEND_OP_ADD,
LogicOp: Direct3D12::D3D12_LOGIC_OP_CLEAR,
RenderTargetWriteMask: 0,
};
let mut raw_targets =
[dummy_target; Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
for (raw, ct) in raw_targets.iter_mut().zip(color_targets.iter()) {
if let Some(ct) = ct.as_ref() {
raw.RenderTargetWriteMask = ct.write_mask.bits() as u8;
if let Some(ref blend) = ct.blend {
let (color_op, color_src, color_dst) = map_blend_component(&blend.color, false);
let (alpha_op, alpha_src, alpha_dst) = map_blend_component(&blend.alpha, true);
raw.BlendEnable = true.into();
raw.BlendOp = color_op;
raw.SrcBlend = color_src;
raw.DestBlend = color_dst;
raw.BlendOpAlpha = alpha_op;
raw.SrcBlendAlpha = alpha_src;
raw.DestBlendAlpha = alpha_dst;
}
}
}
raw_targets
}
fn map_stencil_op(op: wgt::StencilOperation) -> Direct3D12::D3D12_STENCIL_OP {
use wgt::StencilOperation as So;
match op {
So::Keep => Direct3D12::D3D12_STENCIL_OP_KEEP,
So::Zero => Direct3D12::D3D12_STENCIL_OP_ZERO,
So::Replace => Direct3D12::D3D12_STENCIL_OP_REPLACE,
So::IncrementClamp => Direct3D12::D3D12_STENCIL_OP_INCR_SAT,
So::IncrementWrap => Direct3D12::D3D12_STENCIL_OP_INCR,
So::DecrementClamp => Direct3D12::D3D12_STENCIL_OP_DECR_SAT,
So::DecrementWrap => Direct3D12::D3D12_STENCIL_OP_DECR,
So::Invert => Direct3D12::D3D12_STENCIL_OP_INVERT,
}
}
fn map_stencil_face(face: &wgt::StencilFaceState) -> Direct3D12::D3D12_DEPTH_STENCILOP_DESC {
Direct3D12::D3D12_DEPTH_STENCILOP_DESC {
StencilFailOp: map_stencil_op(face.fail_op),
StencilDepthFailOp: map_stencil_op(face.depth_fail_op),
StencilPassOp: map_stencil_op(face.pass_op),
StencilFunc: map_comparison(face.compare),
}
}
pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> Direct3D12::D3D12_DEPTH_STENCIL_DESC {
Direct3D12::D3D12_DEPTH_STENCIL_DESC {
DepthEnable: ds.is_depth_enabled().into(),
DepthWriteMask: if ds.depth_write_enabled {
Direct3D12::D3D12_DEPTH_WRITE_MASK_ALL
} else {
Direct3D12::D3D12_DEPTH_WRITE_MASK_ZERO
},
DepthFunc: map_comparison(ds.depth_compare),
StencilEnable: ds.stencil.is_enabled().into(),
StencilReadMask: ds.stencil.read_mask as u8,
StencilWriteMask: ds.stencil.write_mask as u8,
FrontFace: map_stencil_face(&ds.stencil.front),
BackFace: map_stencil_face(&ds.stencil.back),
}
}
pub(crate) fn map_acceleration_structure_build_flags(
flags: wgt::AccelerationStructureFlags,
mode: Option<crate::AccelerationStructureBuildMode>,
) -> Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS {
let mut d3d_flags = Default::default();
if flags.contains(wgt::AccelerationStructureFlags::ALLOW_COMPACTION) {
d3d_flags |=
Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION;
}
if flags.contains(wgt::AccelerationStructureFlags::ALLOW_UPDATE) {
d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
}
if flags.contains(wgt::AccelerationStructureFlags::LOW_MEMORY) {
d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY;
}
if flags.contains(wgt::AccelerationStructureFlags::PREFER_FAST_BUILD) {
d3d_flags |=
Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD;
}
if flags.contains(wgt::AccelerationStructureFlags::PREFER_FAST_TRACE) {
d3d_flags |=
Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;
}
if let Some(crate::AccelerationStructureBuildMode::Update) = mode {
d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE
}
d3d_flags
}
pub(crate) fn map_acceleration_structure_geometry_flags(
flags: wgt::AccelerationStructureGeometryFlags,
) -> Direct3D12::D3D12_RAYTRACING_GEOMETRY_FLAGS {
let mut d3d_flags = Default::default();
if flags.contains(wgt::AccelerationStructureGeometryFlags::OPAQUE) {
d3d_flags |= Direct3D12::D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE;
}
if flags.contains(wgt::AccelerationStructureGeometryFlags::NO_DUPLICATE_ANY_HIT_INVOCATION) {
d3d_flags |= Direct3D12::D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION;
}
d3d_flags
}

323
vendor/wgpu-hal/src/dx12/descriptor.rs vendored Normal file
View File

@@ -0,0 +1,323 @@
use std::fmt;
use bit_set::BitSet;
use parking_lot::Mutex;
use range_alloc::RangeAllocator;
use windows::Win32::Graphics::Direct3D12;
use crate::auxil::dxgi::result::HResult as _;
const HEAP_SIZE_FIXED: usize = 64;
#[derive(Copy, Clone)]
pub(super) struct DualHandle {
cpu: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
pub gpu: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE,
/// How large the block allocated to this handle is.
count: u64,
}
impl fmt::Debug for DualHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DualHandle")
.field("cpu", &self.cpu.ptr)
.field("gpu", &self.gpu.ptr)
.field("count", &self.count)
.finish()
}
}
type DescriptorIndex = u64;
pub(super) struct GeneralHeap {
pub raw: Direct3D12::ID3D12DescriptorHeap,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
handle_size: u64,
total_handles: u64,
start: DualHandle,
ranges: Mutex<RangeAllocator<DescriptorIndex>>,
}
impl GeneralHeap {
pub(super) fn new(
device: &Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
total_handles: u64,
) -> Result<Self, crate::DeviceError> {
let raw = {
profiling::scope!("ID3D12Device::CreateDescriptorHeap");
let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC {
Type: ty,
NumDescriptors: total_handles as u32,
Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
NodeMask: 0,
};
unsafe { device.CreateDescriptorHeap::<Direct3D12::ID3D12DescriptorHeap>(&desc) }
.into_device_result("Descriptor heap creation")?
};
let start = DualHandle {
cpu: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
gpu: unsafe { raw.GetGPUDescriptorHandleForHeapStart() },
count: 0,
};
Ok(Self {
raw,
ty,
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as u64,
total_handles,
start,
ranges: Mutex::new(RangeAllocator::new(0..total_handles)),
})
}
pub(super) fn at(&self, index: DescriptorIndex, count: u64) -> DualHandle {
assert!(index < self.total_handles);
DualHandle {
cpu: self.cpu_descriptor_at(index),
gpu: self.gpu_descriptor_at(index),
count,
}
}
fn cpu_descriptor_at(&self, index: u64) -> Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: self.start.cpu.ptr + (self.handle_size * index) as usize,
}
}
fn gpu_descriptor_at(&self, index: u64) -> Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE {
Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE {
ptr: self.start.gpu.ptr + self.handle_size * index,
}
}
pub(super) fn allocate_slice(&self, count: u64) -> Result<DescriptorIndex, crate::DeviceError> {
let range = self.ranges.lock().allocate_range(count).map_err(|err| {
log::error!("Unable to allocate descriptors: {:?}", err);
crate::DeviceError::OutOfMemory
})?;
Ok(range.start)
}
/// Free handles previously given out by this `DescriptorHeapSlice`.
/// Do not use this with handles not given out by this `DescriptorHeapSlice`.
pub(crate) fn free_slice(&self, handle: DualHandle) {
let start = (handle.gpu.ptr - self.start.gpu.ptr) / self.handle_size;
self.ranges.lock().free_range(start..start + handle.count);
}
}
/// Fixed-size free-list allocator for CPU descriptors.
struct FixedSizeHeap {
_raw: Direct3D12::ID3D12DescriptorHeap,
/// Bit flag representation of available handles in the heap.
///
/// 0 - Occupied
/// 1 - free
availability: u64,
handle_size: usize,
start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
}
impl FixedSizeHeap {
fn new(
device: &Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
) -> Result<Self, crate::DeviceError> {
let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC {
Type: ty,
NumDescriptors: HEAP_SIZE_FIXED as u32,
Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
NodeMask: 0,
};
let heap =
unsafe { device.CreateDescriptorHeap::<Direct3D12::ID3D12DescriptorHeap>(&desc) }
.into_device_result("Descriptor heap creation")?;
Ok(Self {
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as usize,
availability: !0, // all free!
start: unsafe { heap.GetCPUDescriptorHandleForHeapStart() },
_raw: heap,
})
}
fn alloc_handle(
&mut self,
) -> Result<Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE, crate::DeviceError> {
// Find first free slot.
let slot = self.availability.trailing_zeros() as usize;
if slot >= HEAP_SIZE_FIXED {
log::error!("Failed to allocate a handle form a fixed size heap");
return Err(crate::DeviceError::OutOfMemory);
}
// Set the slot as occupied.
self.availability ^= 1 << slot;
Ok(Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: self.start.ptr + self.handle_size * slot,
})
}
fn free_handle(&mut self, handle: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE) {
let slot = (handle.ptr - self.start.ptr) / self.handle_size;
assert!(slot < HEAP_SIZE_FIXED);
assert_eq!(self.availability & (1 << slot), 0);
self.availability ^= 1 << slot;
}
fn is_full(&self) -> bool {
self.availability == 0
}
}
#[derive(Clone, Copy)]
pub(super) struct Handle {
pub raw: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
heap_index: usize,
}
impl fmt::Debug for Handle {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Handle")
.field("ptr", &self.raw.ptr)
.field("heap_index", &self.heap_index)
.finish()
}
}
pub(super) struct CpuPool {
device: Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
heaps: Vec<FixedSizeHeap>,
available_heap_indices: BitSet,
}
impl CpuPool {
pub(super) fn new(
device: Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
) -> Self {
Self {
device,
ty,
heaps: Vec::new(),
available_heap_indices: BitSet::new(),
}
}
pub(super) fn alloc_handle(&mut self) -> Result<Handle, crate::DeviceError> {
let heap_index = self
.available_heap_indices
.iter()
.next()
.unwrap_or(self.heaps.len());
// Allocate a new heap
if heap_index == self.heaps.len() {
self.heaps.push(FixedSizeHeap::new(&self.device, self.ty)?);
self.available_heap_indices.insert(heap_index);
}
let heap = &mut self.heaps[heap_index];
let handle = Handle {
raw: heap.alloc_handle()?,
heap_index,
};
if heap.is_full() {
self.available_heap_indices.remove(heap_index);
}
Ok(handle)
}
pub(super) fn free_handle(&mut self, handle: Handle) {
self.heaps[handle.heap_index].free_handle(handle.raw);
self.available_heap_indices.insert(handle.heap_index);
}
}
pub(super) struct CpuHeapInner {
pub _raw: Direct3D12::ID3D12DescriptorHeap,
pub stage: Vec<Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE>,
}
pub(super) struct CpuHeap {
pub inner: Mutex<CpuHeapInner>,
start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
handle_size: u32,
total: u32,
}
unsafe impl Send for CpuHeap {}
unsafe impl Sync for CpuHeap {}
impl CpuHeap {
pub(super) fn new(
device: &Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
total: u32,
) -> Result<Self, crate::DeviceError> {
let handle_size = unsafe { device.GetDescriptorHandleIncrementSize(ty) };
let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC {
Type: ty,
NumDescriptors: total,
Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
NodeMask: 0,
};
let raw = unsafe { device.CreateDescriptorHeap::<Direct3D12::ID3D12DescriptorHeap>(&desc) }
.into_device_result("CPU descriptor heap creation")?;
let start = unsafe { raw.GetCPUDescriptorHandleForHeapStart() };
Ok(Self {
inner: Mutex::new(CpuHeapInner {
_raw: raw,
stage: Vec::new(),
}),
start,
handle_size,
total,
})
}
pub(super) fn at(&self, index: u32) -> Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: self.start.ptr + (self.handle_size * index) as usize,
}
}
}
impl fmt::Debug for CpuHeap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CpuHeap")
.field("start", &self.start.ptr)
.field("handle_size", &self.handle_size)
.field("total", &self.total)
.finish()
}
}
pub(super) unsafe fn upload(
device: &Direct3D12::ID3D12Device,
src: &CpuHeapInner,
dst: &GeneralHeap,
dummy_copy_counts: &[u32],
) -> Result<DualHandle, crate::DeviceError> {
let count = src.stage.len() as u32;
let index = dst.allocate_slice(count as u64)?;
unsafe {
device.CopyDescriptors(
1,
&dst.cpu_descriptor_at(index),
Some(&count),
count,
src.stage.as_ptr(),
Some(dummy_copy_counts.as_ptr()),
dst.ty,
)
};
Ok(dst.at(index, count as u64))
}

2136
vendor/wgpu-hal/src/dx12/device.rs vendored Normal file

File diff suppressed because it is too large Load Diff

149
vendor/wgpu-hal/src/dx12/instance.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
use std::{mem::size_of_val, sync::Arc};
use parking_lot::RwLock;
use windows::{
core::Interface as _,
Win32::{
Foundation,
Graphics::{Direct3D12, Dxgi},
},
};
use super::SurfaceTarget;
use crate::{auxil, dx12::D3D12Lib};
impl crate::Instance for super::Instance {
type A = super::Api;
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
profiling::scope!("Init DX12 Backend");
let lib_main = D3D12Lib::new().map_err(|e| {
crate::InstanceError::with_source(String::from("failed to load d3d12.dll"), e)
})?;
if desc
.flags
.intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
// Enable debug layer
if let Ok(Some(debug_controller)) = lib_main.debug_interface() {
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
unsafe { debug_controller.EnableDebugLayer() }
}
if desc
.flags
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
#[allow(clippy::collapsible_if)]
if let Ok(debug1) = debug_controller.cast::<Direct3D12::ID3D12Debug1>() {
unsafe { debug1.SetEnableGPUBasedValidation(true) }
} else {
log::warn!("Failed to enable GPU-based validation");
}
}
}
}
let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory(desc.flags)?;
// Create IDXGIFactoryMedia
let factory_media = lib_dxgi.create_factory_media().ok();
let mut supports_allow_tearing = false;
if let Some(factory5) = factory.as_factory5() {
let mut allow_tearing = Foundation::FALSE;
let hr = unsafe {
factory5.CheckFeatureSupport(
Dxgi::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
<*mut _>::cast(&mut allow_tearing),
size_of_val(&allow_tearing) as u32,
)
};
match hr {
Err(err) => log::warn!("Unable to check for tearing support: {err}"),
Ok(()) => supports_allow_tearing = true,
}
}
// Initialize DXC shader compiler
let dxc_container = match desc.dx12_shader_compiler.clone() {
wgt::Dx12Compiler::DynamicDxc {
dxil_path,
dxc_path,
} => {
let container = super::shader_compilation::get_dynamic_dxc_container(
dxc_path.into(),
dxil_path.into(),
)
.map_err(|e| {
crate::InstanceError::with_source(String::from("Failed to load dynamic DXC"), e)
})?;
Some(Arc::new(container))
}
wgt::Dx12Compiler::StaticDxc => {
let container =
super::shader_compilation::get_static_dxc_container().map_err(|e| {
crate::InstanceError::with_source(
String::from("Failed to load static DXC"),
e,
)
})?;
Some(Arc::new(container))
}
wgt::Dx12Compiler::Fxc => None,
};
match dxc_container {
Some(_) => log::debug!("Using DXC for shader compilation"),
None => log::debug!("Using FXC for shader compilation"),
}
Ok(Self {
// The call to create_factory will only succeed if we get a factory4, so this is safe.
factory,
factory_media,
library: Arc::new(lib_main),
_lib_dxgi: lib_dxgi,
supports_allow_tearing,
flags: desc.flags,
dxc_container,
})
}
unsafe fn create_surface(
&self,
_display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Result<super::Surface, crate::InstanceError> {
match window_handle {
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
// https://github.com/rust-windowing/raw-window-handle/issues/171
target: SurfaceTarget::WndHandle(Foundation::HWND(handle.hwnd.get() as *mut _)),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: RwLock::new(None),
}),
_ => Err(crate::InstanceError::new(format!(
"window handle {window_handle:?} is not a Win32 handle"
))),
}
}
unsafe fn enumerate_adapters(
&self,
_surface_hint: Option<&super::Surface>,
) -> Vec<crate::ExposedAdapter<super::Api>> {
let adapters = auxil::dxgi::factory::enumerate_adapters(self.factory.clone());
adapters
.into_iter()
.filter_map(|raw| {
super::Adapter::expose(raw, &self.library, self.flags, self.dxc_container.clone())
})
.collect()
}
}

1364
vendor/wgpu-hal/src/dx12/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
use crate::auxil::dxgi::result::HResult;
use std::ffi::CStr;
use std::path::PathBuf;
use thiserror::Error;
use windows::{
core::{Interface, PCSTR, PCWSTR},
Win32::Graphics::Direct3D::{Dxc, Fxc},
};
// Currently this will use Dxc if it is chosen as the dx12 compiler at `Instance` creation time, and will
// fallback to FXC if the Dxc libraries (dxil.dll and dxcompiler.dll) are not found, or if Fxc is chosen at'
// `Instance` creation time.
pub(super) fn compile_fxc(
device: &super::Device,
source: &str,
source_name: Option<&CStr>,
raw_ep: &str,
stage_bit: wgt::ShaderStages,
full_stage: &str,
) -> Result<super::CompiledShader, crate::PipelineError> {
profiling::scope!("compile_fxc");
let mut shader_data = None;
let mut compile_flags = Fxc::D3DCOMPILE_ENABLE_STRICTNESS;
if device
.private_caps
.instance_flags
.contains(wgt::InstanceFlags::DEBUG)
{
compile_flags |= Fxc::D3DCOMPILE_DEBUG | Fxc::D3DCOMPILE_SKIP_OPTIMIZATION;
}
let raw_ep = std::ffi::CString::new(raw_ep).unwrap();
let full_stage = std::ffi::CString::new(full_stage).unwrap();
// If no name has been set, D3DCompile wants the null pointer.
let source_name = source_name
.map(|cstr| cstr.as_ptr().cast())
.unwrap_or(core::ptr::null());
let mut error = None;
let hr = unsafe {
profiling::scope!("Fxc::D3DCompile");
Fxc::D3DCompile(
// TODO: Update low-level bindings to accept a slice here
source.as_ptr().cast(),
source.len(),
PCSTR(source_name),
None,
None,
PCSTR(raw_ep.as_ptr().cast()),
PCSTR(full_stage.as_ptr().cast()),
compile_flags,
0,
&mut shader_data,
Some(&mut error),
)
};
match hr {
Ok(()) => {
let shader_data = shader_data.unwrap();
Ok(super::CompiledShader::Fxc(shader_data))
}
Err(e) => {
let mut full_msg = format!("FXC D3DCompile error ({e})");
if let Some(error) = error {
use std::fmt::Write as _;
let message = unsafe {
std::slice::from_raw_parts(
error.GetBufferPointer().cast(),
error.GetBufferSize(),
)
};
let _ = write!(full_msg, ": {}", String::from_utf8_lossy(message));
}
Err(crate::PipelineError::Linkage(stage_bit, full_msg))
}
}
}
trait DxcObj: Interface {
const CLSID: windows::core::GUID;
}
impl DxcObj for Dxc::IDxcCompiler3 {
const CLSID: windows::core::GUID = Dxc::CLSID_DxcCompiler;
}
impl DxcObj for Dxc::IDxcUtils {
const CLSID: windows::core::GUID = Dxc::CLSID_DxcUtils;
}
impl DxcObj for Dxc::IDxcValidator {
const CLSID: windows::core::GUID = Dxc::CLSID_DxcValidator;
}
#[derive(Debug)]
struct DxcLib {
lib: crate::dx12::DynLib,
}
impl DxcLib {
fn new_dynamic(lib_path: PathBuf) -> Result<Self, libloading::Error> {
unsafe { crate::dx12::DynLib::new(lib_path).map(|lib| Self { lib }) }
}
pub fn create_instance<T: DxcObj>(&self) -> Result<T, crate::DeviceError> {
unsafe {
type DxcCreateInstanceFn = unsafe extern "system" fn(
rclsid: *const windows_core::GUID,
riid: *const windows_core::GUID,
ppv: *mut *mut core::ffi::c_void,
)
-> windows_core::HRESULT;
let func: libloading::Symbol<DxcCreateInstanceFn> =
self.lib.get(b"DxcCreateInstance\0")?;
dxc_create_instance::<T>(|clsid, iid, ppv| func(clsid, iid, ppv))
}
}
}
/// Invokes the provided library function to create a DXC object.
unsafe fn dxc_create_instance<T: DxcObj>(
f: impl Fn(
*const windows_core::GUID,
*const windows_core::GUID,
*mut *mut core::ffi::c_void,
) -> windows_core::HRESULT,
) -> Result<T, crate::DeviceError> {
let mut result__ = None;
f(&T::CLSID, &T::IID, <*mut _>::cast(&mut result__))
.ok()
.into_device_result("DxcCreateInstance")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
// Destructor order should be fine since _dxil and _dxc don't rely on each other.
pub(super) struct DxcContainer {
compiler: Dxc::IDxcCompiler3,
utils: Dxc::IDxcUtils,
validator: Option<Dxc::IDxcValidator>,
// Has to be held onto for the lifetime of the device otherwise shaders will fail to compile.
// Only needed when using dynamic linking.
_dxc: Option<DxcLib>,
// Also Has to be held onto for the lifetime of the device otherwise shaders will fail to validate.
// Only needed when using dynamic linking.
_dxil: Option<DxcLib>,
}
#[derive(Debug, Error)]
pub(super) enum GetDynamicDXCContainerError {
#[error(transparent)]
Device(#[from] crate::DeviceError),
#[error("Failed to load {0}: {1}")]
FailedToLoad(&'static str, libloading::Error),
}
pub(super) fn get_dynamic_dxc_container(
dxc_path: PathBuf,
dxil_path: PathBuf,
) -> Result<DxcContainer, GetDynamicDXCContainerError> {
let dxc = DxcLib::new_dynamic(dxc_path)
.map_err(|e| GetDynamicDXCContainerError::FailedToLoad("dxcompiler.dll", e))?;
let dxil = DxcLib::new_dynamic(dxil_path)
.map_err(|e| GetDynamicDXCContainerError::FailedToLoad("dxil.dll", e))?;
let compiler = dxc.create_instance::<Dxc::IDxcCompiler3>()?;
let utils = dxc.create_instance::<Dxc::IDxcUtils>()?;
let validator = dxil.create_instance::<Dxc::IDxcValidator>()?;
Ok(DxcContainer {
compiler,
utils,
validator: Some(validator),
_dxc: Some(dxc),
_dxil: Some(dxil),
})
}
/// Creates a [`DxcContainer`] that delegates to the statically-linked version of DXC.
pub(super) fn get_static_dxc_container() -> Result<DxcContainer, crate::DeviceError> {
#[cfg(static_dxc)]
{
unsafe {
let compiler = dxc_create_instance::<Dxc::IDxcCompiler3>(|clsid, iid, ppv| {
windows_core::HRESULT(mach_dxcompiler_rs::DxcCreateInstance(
clsid.cast(),
iid.cast(),
ppv,
))
})?;
let utils = dxc_create_instance::<Dxc::IDxcUtils>(|clsid, iid, ppv| {
windows_core::HRESULT(mach_dxcompiler_rs::DxcCreateInstance(
clsid.cast(),
iid.cast(),
ppv,
))
})?;
Ok(DxcContainer {
compiler,
utils,
validator: None,
_dxc: None,
_dxil: None,
})
}
}
#[cfg(not(static_dxc))]
{
panic!("Attempted to create a static DXC shader compiler, but the static-dxc feature was not enabled")
}
}
/// Owned PCWSTR
#[allow(clippy::upper_case_acronyms)]
struct OPCWSTR {
inner: Vec<u16>,
}
impl OPCWSTR {
fn new(s: &str) -> Self {
let mut inner: Vec<_> = s.encode_utf16().collect();
inner.push(0);
Self { inner }
}
fn ptr(&self) -> PCWSTR {
PCWSTR(self.inner.as_ptr())
}
}
fn get_output<T: Interface>(
res: &Dxc::IDxcResult,
kind: Dxc::DXC_OUT_KIND,
) -> Result<T, crate::DeviceError> {
let mut result__: Option<T> = None;
unsafe { res.GetOutput::<T>(kind, &mut None, <*mut _>::cast(&mut result__)) }
.into_device_result("GetOutput")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
fn as_err_str(blob: &Dxc::IDxcBlobUtf8) -> Result<&str, crate::DeviceError> {
let ptr = unsafe { blob.GetStringPointer() };
let len = unsafe { blob.GetStringLength() };
core::str::from_utf8(unsafe { core::slice::from_raw_parts(ptr.0, len) })
.map_err(|_| crate::DeviceError::Unexpected)
}
pub(super) fn compile_dxc(
device: &crate::dx12::Device,
source: &str,
source_name: Option<&CStr>,
raw_ep: &str,
stage_bit: wgt::ShaderStages,
full_stage: &str,
dxc_container: &DxcContainer,
) -> Result<crate::dx12::CompiledShader, crate::PipelineError> {
profiling::scope!("compile_dxc");
let source_name = source_name.and_then(|cstr| cstr.to_str().ok());
let source_name = source_name.map(OPCWSTR::new);
let raw_ep = OPCWSTR::new(raw_ep);
let full_stage = OPCWSTR::new(full_stage);
let mut compile_args = arrayvec::ArrayVec::<PCWSTR, 12>::new_const();
if let Some(source_name) = source_name.as_ref() {
compile_args.push(source_name.ptr())
}
compile_args.extend([
windows::core::w!("-E"),
raw_ep.ptr(),
windows::core::w!("-T"),
full_stage.ptr(),
windows::core::w!("-HV"),
windows::core::w!("2018"), // Use HLSL 2018, Naga doesn't supported 2021 yet.
windows::core::w!("-no-warnings"),
Dxc::DXC_ARG_ENABLE_STRICTNESS,
]);
if dxc_container.validator.is_some() {
compile_args.push(Dxc::DXC_ARG_SKIP_VALIDATION); // Disable implicit validation to work around bugs when dxil.dll isn't in the local directory.)
}
if device
.private_caps
.instance_flags
.contains(wgt::InstanceFlags::DEBUG)
{
compile_args.push(Dxc::DXC_ARG_DEBUG);
compile_args.push(Dxc::DXC_ARG_SKIP_OPTIMIZATIONS);
}
let buffer = Dxc::DxcBuffer {
Ptr: source.as_ptr().cast(),
Size: source.len(),
Encoding: Dxc::DXC_CP_UTF8.0,
};
let compile_res: Dxc::IDxcResult = unsafe {
dxc_container
.compiler
.Compile(&buffer, Some(&compile_args), None)
}
.into_device_result("Compile")?;
drop(compile_args);
drop(source_name);
drop(raw_ep);
drop(full_stage);
let err_blob = get_output::<Dxc::IDxcBlobUtf8>(&compile_res, Dxc::DXC_OUT_ERRORS)?;
let len = unsafe { err_blob.GetStringLength() };
if len != 0 {
let err = as_err_str(&err_blob)?;
return Err(crate::PipelineError::Linkage(
stage_bit,
format!("DXC compile error: {err}"),
));
}
let blob = get_output::<Dxc::IDxcBlob>(&compile_res, Dxc::DXC_OUT_OBJECT)?;
if let Some(validator) = &dxc_container.validator {
let err_blob = {
let res = unsafe { validator.Validate(&blob, Dxc::DxcValidatorFlags_InPlaceEdit) }
.into_device_result("Validate")?;
unsafe { res.GetErrorBuffer() }.into_device_result("GetErrorBuffer")?
};
let size = unsafe { err_blob.GetBufferSize() };
if size != 0 {
let err_blob = unsafe { dxc_container.utils.GetBlobAsUtf8(&err_blob) }
.into_device_result("GetBlobAsUtf8")?;
let err = as_err_str(&err_blob)?;
return Err(crate::PipelineError::Linkage(
stage_bit,
format!("DXC validation error: {err}"),
));
}
}
Ok(crate::dx12::CompiledShader::Dxc(blob))
}

View File

@@ -0,0 +1,407 @@
use gpu_allocator::{d3d12::AllocationCreateDesc, MemoryLocation};
use parking_lot::Mutex;
use windows::Win32::Graphics::Direct3D12;
use crate::auxil::dxgi::result::HResult as _;
#[derive(Debug)]
pub(crate) struct GpuAllocatorWrapper {
pub(crate) allocator: gpu_allocator::d3d12::Allocator,
}
#[derive(Debug)]
pub(crate) struct AllocationWrapper {
pub(crate) allocation: gpu_allocator::d3d12::Allocation,
}
pub(crate) fn create_allocator_wrapper(
raw: &Direct3D12::ID3D12Device,
memory_hints: &wgt::MemoryHints,
) -> Result<Mutex<GpuAllocatorWrapper>, crate::DeviceError> {
// TODO: the allocator's configuration should take hardware capability into
// account.
let mb = 1024 * 1024;
let allocation_sizes = match memory_hints {
wgt::MemoryHints::Performance => gpu_allocator::AllocationSizes::default(),
wgt::MemoryHints::MemoryUsage => gpu_allocator::AllocationSizes::new(8 * mb, 4 * mb),
wgt::MemoryHints::Manual {
suballocated_device_memory_block_size,
} => {
// TODO: Would it be useful to expose the host size in memory hints
// instead of always using half of the device size?
let device_size = suballocated_device_memory_block_size.start;
let host_size = device_size / 2;
gpu_allocator::AllocationSizes::new(device_size, host_size)
}
};
match gpu_allocator::d3d12::Allocator::new(&gpu_allocator::d3d12::AllocatorCreateDesc {
device: gpu_allocator::d3d12::ID3D12DeviceVersion::Device(raw.clone()),
debug_settings: Default::default(),
allocation_sizes,
}) {
Ok(allocator) => Ok(Mutex::new(GpuAllocatorWrapper { allocator })),
Err(e) => {
log::error!("Failed to create d3d12 allocator, error: {}", e);
Err(e)?
}
}
}
pub(crate) fn create_buffer_resource(
device: &crate::dx12::Device,
desc: &crate::BufferDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
) -> Result<(Direct3D12::ID3D12Resource, Option<AllocationWrapper>), crate::DeviceError> {
let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
// Workaround for Intel Xe drivers
if !device.private_caps.suballocation_supported {
return create_committed_buffer_resource(device, desc, raw_desc)
.map(|resource| (resource, None));
}
let location = match (is_cpu_read, is_cpu_write) {
(true, true) => MemoryLocation::CpuToGpu,
(true, false) => MemoryLocation::GpuToCpu,
(false, true) => MemoryLocation::CpuToGpu,
(false, false) => MemoryLocation::GpuOnly,
};
let name = desc.label.unwrap_or("Unlabeled buffer");
let mut allocator = device.mem_allocator.lock();
let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc(
allocator.allocator.device(),
&raw_desc,
name,
location,
);
let allocation = allocator.allocator.allocate(&allocation_desc)?;
let mut resource = None;
unsafe {
device.raw.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None,
&mut resource,
)
}
.into_device_result("Placed buffer creation")?;
let resource = resource.ok_or(crate::DeviceError::Unexpected)?;
device
.counters
.buffer_memory
.add(allocation.size() as isize);
Ok((resource, Some(AllocationWrapper { allocation })))
}
pub(crate) fn create_texture_resource(
device: &crate::dx12::Device,
desc: &crate::TextureDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
) -> Result<(Direct3D12::ID3D12Resource, Option<AllocationWrapper>), crate::DeviceError> {
// Workaround for Intel Xe drivers
if !device.private_caps.suballocation_supported {
return create_committed_texture_resource(device, desc, raw_desc)
.map(|resource| (resource, None));
}
let location = MemoryLocation::GpuOnly;
let name = desc.label.unwrap_or("Unlabeled texture");
let mut allocator = device.mem_allocator.lock();
let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc(
allocator.allocator.device(),
&raw_desc,
name,
location,
);
let allocation = allocator.allocator.allocate(&allocation_desc)?;
let mut resource = None;
unsafe {
device.raw.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None, // clear value
&mut resource,
)
}
.into_device_result("Placed texture creation")?;
let resource = resource.ok_or(crate::DeviceError::Unexpected)?;
device
.counters
.texture_memory
.add(allocation.size() as isize);
Ok((resource, Some(AllocationWrapper { allocation })))
}
pub(crate) fn create_acceleration_structure_resource(
device: &crate::dx12::Device,
desc: &crate::AccelerationStructureDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
) -> Result<(Direct3D12::ID3D12Resource, Option<AllocationWrapper>), crate::DeviceError> {
// Workaround for Intel Xe drivers
if !device.private_caps.suballocation_supported {
return create_committed_acceleration_structure_resource(device, desc, raw_desc)
.map(|resource| (resource, None));
}
let location = MemoryLocation::GpuOnly;
let name = desc.label.unwrap_or("Unlabeled acceleration structure");
let mut allocator = device.mem_allocator.lock();
let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc(
allocator.allocator.device(),
&raw_desc,
name,
location,
);
let allocation = allocator.allocator.allocate(&allocation_desc)?;
let mut resource = None;
unsafe {
device.raw.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE,
None,
&mut resource,
)
}
.into_device_result("Placed acceleration structure creation")?;
let resource = resource.ok_or(crate::DeviceError::Unexpected)?;
device
.counters
.acceleration_structure_memory
.add(allocation.size() as isize);
Ok((resource, Some(AllocationWrapper { allocation })))
}
pub(crate) fn free_buffer_allocation(
device: &crate::dx12::Device,
allocation: AllocationWrapper,
allocator: &Mutex<GpuAllocatorWrapper>,
) {
device
.counters
.buffer_memory
.sub(allocation.allocation.size() as isize);
match allocator.lock().allocator.free(allocation.allocation) {
Ok(_) => (),
// TODO: Don't panic here
Err(e) => panic!("Failed to destroy dx12 buffer, {e}"),
};
}
pub(crate) fn free_texture_allocation(
device: &crate::dx12::Device,
allocation: AllocationWrapper,
allocator: &Mutex<GpuAllocatorWrapper>,
) {
device
.counters
.texture_memory
.sub(allocation.allocation.size() as isize);
match allocator.lock().allocator.free(allocation.allocation) {
Ok(_) => (),
// TODO: Don't panic here
Err(e) => panic!("Failed to destroy dx12 texture, {e}"),
};
}
pub(crate) fn free_acceleration_structure_allocation(
device: &crate::dx12::Device,
allocation: AllocationWrapper,
allocator: &Mutex<GpuAllocatorWrapper>,
) {
device
.counters
.acceleration_structure_memory
.sub(allocation.allocation.size() as isize);
match allocator.lock().allocator.free(allocation.allocation) {
Ok(_) => (),
// TODO: Don't panic here
Err(e) => panic!("Failed to destroy dx12 acceleration structure, {e}"),
};
}
impl From<gpu_allocator::AllocationError> for crate::DeviceError {
fn from(result: gpu_allocator::AllocationError) -> Self {
match result {
gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory,
gpu_allocator::AllocationError::FailedToMap(e) => {
log::error!("DX12 gpu-allocator: Failed to map: {}", e);
Self::Lost
}
gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => {
log::error!("DX12 gpu-allocator: No Compatible Memory Type Found");
Self::Lost
}
gpu_allocator::AllocationError::InvalidAllocationCreateDesc => {
log::error!("DX12 gpu-allocator: Invalid Allocation Creation Description");
Self::Lost
}
gpu_allocator::AllocationError::InvalidAllocatorCreateDesc(e) => {
log::error!(
"DX12 gpu-allocator: Invalid Allocator Creation Description: {}",
e
);
Self::Lost
}
gpu_allocator::AllocationError::Internal(e) => {
log::error!("DX12 gpu-allocator: Internal Error: {}", e);
Self::Lost
}
gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10
| gpu_allocator::AllocationError::CastableFormatsRequiresEnhancedBarriers
| gpu_allocator::AllocationError::CastableFormatsRequiresAtLeastDevice12 => {
unreachable!()
}
}
}
}
pub(crate) fn create_committed_buffer_resource(
device: &crate::dx12::Device,
desc: &crate::BufferDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
) -> Result<Direct3D12::ID3D12Resource, crate::DeviceError> {
let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES {
Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM,
CPUPageProperty: if is_cpu_read {
Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK
} else if is_cpu_write {
Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE
} else {
Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE
},
MemoryPoolPreference: match device.private_caps.memory_architecture {
crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => {
Direct3D12::D3D12_MEMORY_POOL_L1
}
_ => Direct3D12::D3D12_MEMORY_POOL_L0,
},
CreationNodeMask: 0,
VisibleNodeMask: 0,
};
let mut resource = None;
unsafe {
device.raw.CreateCommittedResource(
&heap_properties,
if device.private_caps.heap_create_not_zeroed {
Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
} else {
Direct3D12::D3D12_HEAP_FLAG_NONE
},
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None,
&mut resource,
)
}
.into_device_result("Committed buffer creation")?;
resource.ok_or(crate::DeviceError::Unexpected)
}
pub(crate) fn create_committed_texture_resource(
device: &crate::dx12::Device,
_desc: &crate::TextureDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
) -> Result<Direct3D12::ID3D12Resource, crate::DeviceError> {
let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES {
Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM,
CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
MemoryPoolPreference: match device.private_caps.memory_architecture {
crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1,
crate::dx12::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0,
},
CreationNodeMask: 0,
VisibleNodeMask: 0,
};
let mut resource = None;
unsafe {
device.raw.CreateCommittedResource(
&heap_properties,
if device.private_caps.heap_create_not_zeroed {
Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
} else {
Direct3D12::D3D12_HEAP_FLAG_NONE
},
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None, // clear value
&mut resource,
)
}
.into_device_result("Committed texture creation")?;
resource.ok_or(crate::DeviceError::Unexpected)
}
pub(crate) fn create_committed_acceleration_structure_resource(
device: &crate::dx12::Device,
_desc: &crate::AccelerationStructureDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
) -> Result<Direct3D12::ID3D12Resource, crate::DeviceError> {
let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES {
Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM,
CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
MemoryPoolPreference: match device.private_caps.memory_architecture {
crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1,
_ => Direct3D12::D3D12_MEMORY_POOL_L0,
},
CreationNodeMask: 0,
VisibleNodeMask: 0,
};
let mut resource = None;
unsafe {
device.raw.CreateCommittedResource(
&heap_properties,
if device.private_caps.heap_create_not_zeroed {
Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
} else {
Direct3D12::D3D12_HEAP_FLAG_NONE
},
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE,
None,
&mut resource,
)
}
.into_device_result("Committed acceleration structure creation")?;
resource.ok_or(crate::DeviceError::Unexpected)
}

39
vendor/wgpu-hal/src/dx12/types.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use windows::Win32::Graphics::Dxgi;
windows_core::imp::define_interface!(
ISwapChainPanelNative,
ISwapChainPanelNative_Vtbl,
0x63aad0b8_7c24_40ff_85a8_640d944cc325
);
impl core::ops::Deref for ISwapChainPanelNative {
type Target = windows_core::IUnknown;
fn deref(&self) -> &Self::Target {
unsafe { core::mem::transmute(self) }
}
}
windows_core::imp::interface_hierarchy!(ISwapChainPanelNative, windows_core::IUnknown);
impl ISwapChainPanelNative {
pub unsafe fn SetSwapChain<P0>(&self, swap_chain: P0) -> windows_core::Result<()>
where
P0: windows_core::Param<Dxgi::IDXGISwapChain1>,
{
unsafe {
(windows_core::Interface::vtable(self).SetSwapChain)(
windows_core::Interface::as_raw(self),
swap_chain.param().abi(),
)
}
.ok()
}
}
#[repr(C)]
pub struct ISwapChainPanelNative_Vtbl {
pub base__: windows_core::IUnknown_Vtbl,
pub SetSwapChain: unsafe extern "system" fn(
swap_chain_panel_native: *mut core::ffi::c_void,
swap_chain: *mut core::ffi::c_void,
) -> windows_core::HRESULT,
}

346
vendor/wgpu-hal/src/dx12/view.rs vendored Normal file
View File

@@ -0,0 +1,346 @@
use windows::Win32::Graphics::{Direct3D12, Dxgi};
use crate::auxil;
pub(super) struct ViewDescriptor {
dimension: wgt::TextureViewDimension,
pub aspects: crate::FormatAspects,
pub rtv_dsv_format: Dxgi::Common::DXGI_FORMAT,
srv_uav_format: Option<Dxgi::Common::DXGI_FORMAT>,
multisampled: bool,
array_layer_base: u32,
array_layer_count: u32,
mip_level_base: u32,
mip_level_count: u32,
}
impl crate::TextureViewDescriptor<'_> {
pub(super) fn to_internal(&self, texture: &super::Texture) -> ViewDescriptor {
let aspects = crate::FormatAspects::new(texture.format, self.range.aspect);
ViewDescriptor {
dimension: self.dimension,
aspects,
rtv_dsv_format: auxil::dxgi::conv::map_texture_format(self.format),
srv_uav_format: auxil::dxgi::conv::map_texture_format_for_srv_uav(self.format, aspects),
multisampled: texture.sample_count > 1,
mip_level_base: self.range.base_mip_level,
mip_level_count: self.range.mip_level_count.unwrap_or(!0),
array_layer_base: self.range.base_array_layer,
array_layer_count: self.range.array_layer_count.unwrap_or(!0),
}
}
}
fn aspects_to_plane(aspects: crate::FormatAspects) -> u32 {
match aspects {
crate::FormatAspects::STENCIL => 1,
crate::FormatAspects::PLANE_1 => 1,
crate::FormatAspects::PLANE_2 => 2,
_ => 0,
}
}
impl ViewDescriptor {
pub(crate) unsafe fn to_srv(&self) -> Option<Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC> {
let mut desc = Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC {
Format: self.srv_uav_format?,
ViewDimension: Direct3D12::D3D12_SRV_DIMENSION_UNKNOWN,
Shader4ComponentMapping: Direct3D12::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
ResourceMinLODClamp: 0.0,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
ResourceMinLODClamp: 0.0,
}
}
*/
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DMS;
desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_SRV {
UnusedField_NothingToDefine: 0,
}
}
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2D;
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
PlaneSlice: aspects_to_plane(self.aspects),
ResourceMinLODClamp: 0.0,
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
if self.multisampled =>
{
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_SRV {
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
PlaneSlice: aspects_to_plane(self.aspects),
ResourceMinLODClamp: 0.0,
}
}
wgt::TextureViewDimension::D3 => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE3D;
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
ResourceMinLODClamp: 0.0,
}
}
wgt::TextureViewDimension::Cube if self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURECUBE;
desc.Anonymous.TextureCube = Direct3D12::D3D12_TEXCUBE_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
ResourceMinLODClamp: 0.0,
}
}
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
desc.Anonymous.TextureCubeArray = Direct3D12::D3D12_TEXCUBE_ARRAY_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
First2DArrayFace: self.array_layer_base,
NumCubes: if self.array_layer_count == !0 {
!0
} else {
self.array_layer_count / 6
},
ResourceMinLODClamp: 0.0,
}
}
}
Some(desc)
}
pub(crate) unsafe fn to_uav(&self) -> Option<Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC> {
let mut desc = Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
Format: self.srv_uav_format?,
ViewDimension: Direct3D12::D3D12_UAV_DIMENSION_UNKNOWN,
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_UAV {
MipSlice: self.mip_level_base,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_UAV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize,
}
}*/
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2D;
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_UAV {
MipSlice: self.mip_level_base,
PlaneSlice: aspects_to_plane(self.aspects),
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_UAV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
PlaneSlice: aspects_to_plane(self.aspects),
}
}
wgt::TextureViewDimension::D3 => {
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE3D;
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_UAV {
MipSlice: self.mip_level_base,
FirstWSlice: self.array_layer_base,
WSize: self.array_layer_count,
}
}
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
panic!("Unable to view texture as cube UAV")
}
}
Some(desc)
}
pub(crate) unsafe fn to_rtv(&self) -> Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC {
let mut desc = Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC {
Format: self.rtv_dsv_format,
ViewDimension: Direct3D12::D3D12_RTV_DIMENSION_UNKNOWN,
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_RTV {
MipSlice: self.mip_level_base,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_RTV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize,
}
}*/
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DMS;
desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_RTV {
UnusedField_NothingToDefine: 0,
}
}
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2D;
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_RTV {
MipSlice: self.mip_level_base,
PlaneSlice: aspects_to_plane(self.aspects),
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
if self.multisampled =>
{
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_RTV {
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_RTV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
PlaneSlice: aspects_to_plane(self.aspects),
}
}
wgt::TextureViewDimension::D3 => {
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE3D;
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_RTV {
MipSlice: self.mip_level_base,
FirstWSlice: self.array_layer_base,
WSize: self.array_layer_count,
}
}
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
panic!("Unable to view texture as cube RTV")
}
}
desc
}
pub(crate) unsafe fn to_dsv(
&self,
read_only: bool,
) -> Direct3D12::D3D12_DEPTH_STENCIL_VIEW_DESC {
let mut desc = Direct3D12::D3D12_DEPTH_STENCIL_VIEW_DESC {
Format: self.rtv_dsv_format,
ViewDimension: Direct3D12::D3D12_DSV_DIMENSION_UNKNOWN,
Flags: {
let mut flags = Direct3D12::D3D12_DSV_FLAG_NONE;
if read_only {
if self.aspects.contains(crate::FormatAspects::DEPTH) {
flags |= Direct3D12::D3D12_DSV_FLAG_READ_ONLY_DEPTH;
}
if self.aspects.contains(crate::FormatAspects::STENCIL) {
flags |= Direct3D12::D3D12_DSV_FLAG_READ_ONLY_STENCIL;
}
}
flags
},
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_DSV {
MipSlice: self.mip_level_base,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_DSV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize,
}
}*/
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DMS;
desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_DSV {
UnusedField_NothingToDefine: 0,
}
}
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2D;
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_DSV {
MipSlice: self.mip_level_base,
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
if self.multisampled =>
{
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_DSV {
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
}
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_DSV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
}
wgt::TextureViewDimension::D3
| wgt::TextureViewDimension::Cube
| wgt::TextureViewDimension::CubeArray => {
panic!("Unable to view texture as cube or 3D RTV")
}
}
desc
}
}