mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-26 00:33:51 +00:00
hal/dx12: adapter initialization
This commit is contained in:
parent
4b4e393eec
commit
3a2bbfd563
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -444,6 +444,17 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "091ed1b25fe47c7ff129fc440c23650b6114f36aa00bc7212cc8041879294428"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libloading 0.7.0",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
@ -1984,6 +1995,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-graphics-types",
|
||||
"d3d12",
|
||||
"env_logger",
|
||||
"foreign-types",
|
||||
"fxhash",
|
||||
|
@ -16,6 +16,7 @@ default = []
|
||||
metal = ["naga/msl-out", "block", "foreign-types"]
|
||||
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it", "renderdoc-sys"]
|
||||
gles = ["naga/glsl-out", "glow", "egl", "libloading"]
|
||||
dx12 = ["native", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
@ -39,6 +40,9 @@ inplace_it = { version ="0.3.3", optional = true }
|
||||
renderdoc-sys = { version = "0.7.1", optional = true }
|
||||
# backend: Gles
|
||||
glow = { git = "https://github.com/grovesNL/glow", rev = "0864897a28bbdd43f89f4fd8fdd4ed781b719f8a", optional = true }
|
||||
# backend: Dx12
|
||||
native = { package = "d3d12", version = "0.4", features = ["libloading"], optional = true }
|
||||
#winapi = { version = "0.3", features = ["basetsd","d3dcommon","d3dcompiler","dxgi1_2","dxgi1_3","dxgi1_4","dxgi1_5","dxgi1_6","dxgidebug","dxgiformat","dxgitype","handleapi","minwindef","synchapi","unknwnbase","winbase","winerror","winnt"] }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true }
|
||||
|
319
wgpu-hal/src/dx12/adapter.rs
Normal file
319
wgpu-hal/src/dx12/adapter.rs
Normal file
@ -0,0 +1,319 @@
|
||||
use super::{conv, HResultPair as _};
|
||||
use std::{mem, sync::Arc};
|
||||
use winapi::{
|
||||
shared::{dxgi, dxgi1_2, winerror},
|
||||
um::d3d12,
|
||||
};
|
||||
|
||||
impl Drop for super::Adapter {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.raw.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Adapter {
|
||||
#[allow(trivial_casts)]
|
||||
pub(super) fn expose(
|
||||
adapter: native::WeakPtr<dxgi1_2::IDXGIAdapter2>,
|
||||
library: &Arc<native::D3D12Lib>,
|
||||
) -> Option<crate::ExposedAdapter<super::Api>> {
|
||||
// Create the device so that we can get the capabilities.
|
||||
let device = match library.create_device(adapter, native::FeatureLevel::L11_0) {
|
||||
Ok(pair) => match pair.check() {
|
||||
Ok(device) => device,
|
||||
Err(err) => {
|
||||
log::warn!("Device creation failed: {}", err);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Device creation function is not found: {:?}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// We have found a possible adapter.
|
||||
// Acquire the device information.
|
||||
let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
|
||||
unsafe {
|
||||
adapter.GetDesc2(&mut desc);
|
||||
}
|
||||
|
||||
let device_name = {
|
||||
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
|
||||
let len = desc.Description.iter().take_while(|&&c| c != 0).count();
|
||||
let name = OsString::from_wide(&desc.Description[..len]);
|
||||
name.to_string_lossy().into_owned()
|
||||
};
|
||||
|
||||
let mut features_architecture: d3d12::D3D12_FEATURE_DATA_ARCHITECTURE =
|
||||
unsafe { mem::zeroed() };
|
||||
assert_eq!(0, unsafe {
|
||||
device.CheckFeatureSupport(
|
||||
d3d12::D3D12_FEATURE_ARCHITECTURE,
|
||||
&mut features_architecture as *mut _ as *mut _,
|
||||
mem::size_of::<d3d12::D3D12_FEATURE_DATA_ARCHITECTURE>() as _,
|
||||
)
|
||||
});
|
||||
|
||||
let mut workarounds = super::Workarounds::default();
|
||||
|
||||
let info = wgt::AdapterInfo {
|
||||
backend: wgt::Backend::Dx12,
|
||||
name: device_name,
|
||||
vendor: desc.VendorId as usize,
|
||||
device: desc.DeviceId as usize,
|
||||
device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 {
|
||||
workarounds.avoid_cpu_descriptor_overwrites = true;
|
||||
wgt::DeviceType::VirtualGpu
|
||||
} else if features_architecture.CacheCoherentUMA != 0 {
|
||||
wgt::DeviceType::IntegratedGpu
|
||||
} else {
|
||||
wgt::DeviceType::DiscreteGpu
|
||||
},
|
||||
};
|
||||
|
||||
let mut options: d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS = unsafe { mem::zeroed() };
|
||||
assert_eq!(0, unsafe {
|
||||
device.CheckFeatureSupport(
|
||||
d3d12::D3D12_FEATURE_D3D12_OPTIONS,
|
||||
&mut options as *mut _ as *mut _,
|
||||
mem::size_of::<d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS>() as _,
|
||||
)
|
||||
});
|
||||
|
||||
let _depth_bounds_test_supported = {
|
||||
let mut features2: d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS2 = unsafe { mem::zeroed() };
|
||||
let hr = unsafe {
|
||||
device.CheckFeatureSupport(
|
||||
d3d12::D3D12_FEATURE_D3D12_OPTIONS2,
|
||||
&mut features2 as *mut _ as *mut _,
|
||||
mem::size_of::<d3d12::D3D12_FEATURE_DATA_D3D12_OPTIONS2>() as _,
|
||||
)
|
||||
};
|
||||
hr == 0 && features2.DepthBoundsTestSupported != 0
|
||||
};
|
||||
|
||||
let private_caps = super::PrivateCapabilities {
|
||||
heterogeneous_resource_heaps: options.ResourceHeapTier
|
||||
!= d3d12::D3D12_RESOURCE_HEAP_TIER_1,
|
||||
memory_architecture: if features_architecture.UMA != 0 {
|
||||
super::MemoryArchitecture::Unified {
|
||||
cache_coherent: features_architecture.CacheCoherentUMA != 0,
|
||||
}
|
||||
} else {
|
||||
super::MemoryArchitecture::NonUnified
|
||||
},
|
||||
};
|
||||
|
||||
// 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 {
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_1 => (
|
||||
d3d12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
|
||||
8, // conservative, is 64 on feature level 11.1
|
||||
),
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_2 => (
|
||||
d3d12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2,
|
||||
64,
|
||||
),
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_3 => (
|
||||
tier3_practical_descriptor_limit,
|
||||
tier3_practical_descriptor_limit,
|
||||
),
|
||||
other => {
|
||||
log::warn!("Unknown resource binding tier {}", other);
|
||||
(
|
||||
d3d12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
|
||||
8,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mut features = wgt::Features::empty()
|
||||
| wgt::Features::DEPTH_CLAMPING
|
||||
//TODO: Naga part
|
||||
//| wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
//| wgt::Features::BUFFER_BINDING_ARRAY
|
||||
//| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
//| wgt::Features::UNSIZED_BINDING_ARRAY
|
||||
| wgt::Features::MULTI_DRAW_INDIRECT
|
||||
| wgt::Features::MULTI_DRAW_INDIRECT_COUNT
|
||||
| wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER
|
||||
| wgt::Features::NON_FILL_POLYGON_MODE
|
||||
|wgt::Features::VERTEX_WRITABLE_STORAGE;
|
||||
|
||||
features.set(
|
||||
wgt::Features::CONSERVATIVE_RASTERIZATION,
|
||||
options.ConservativeRasterizationTier
|
||||
!= d3d12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
|
||||
);
|
||||
|
||||
let base = wgt::Limits::default();
|
||||
|
||||
Some(crate::ExposedAdapter {
|
||||
adapter: super::Adapter {
|
||||
raw: adapter,
|
||||
device,
|
||||
library: Arc::clone(library),
|
||||
private_caps,
|
||||
workarounds,
|
||||
},
|
||||
info,
|
||||
features,
|
||||
capabilities: crate::Capabilities {
|
||||
limits: wgt::Limits {
|
||||
max_texture_dimension_1d: d3d12::D3D12_REQ_TEXTURE1D_U_DIMENSION,
|
||||
max_texture_dimension_2d: d3d12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||
.min(d3d12::D3D12_REQ_TEXTURECUBE_DIMENSION),
|
||||
max_texture_dimension_3d: d3d12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
|
||||
max_texture_array_layers: d3d12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
|
||||
max_bind_groups: crate::MAX_BIND_GROUPS as u32,
|
||||
// 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 {
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_1 => 128,
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_2
|
||||
| d3d12::D3D12_RESOURCE_BINDING_TIER_3
|
||||
| _ => full_heap_count,
|
||||
},
|
||||
max_samplers_per_shader_stage: match options.ResourceBindingTier {
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_1 => 16,
|
||||
d3d12::D3D12_RESOURCE_BINDING_TIER_2
|
||||
| d3d12::D3D12_RESOURCE_BINDING_TIER_3
|
||||
| _ => d3d12::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE,
|
||||
},
|
||||
// these both account towards `uav_count`, but we can't express the limit as as sum
|
||||
max_storage_buffers_per_shader_stage: base.max_storage_buffers_per_shader_stage,
|
||||
max_storage_textures_per_shader_stage: base
|
||||
.max_storage_textures_per_shader_stage,
|
||||
max_uniform_buffers_per_shader_stage: full_heap_count,
|
||||
max_uniform_buffer_binding_size: d3d12::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT
|
||||
* 16,
|
||||
max_storage_buffer_binding_size: !0,
|
||||
max_vertex_buffers: d3d12::D3D12_VS_INPUT_REGISTER_COUNT
|
||||
.min(crate::MAX_VERTEX_BUFFERS as u32),
|
||||
max_vertex_attributes: d3d12::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
|
||||
max_vertex_buffer_array_stride: d3d12::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES,
|
||||
max_push_constant_size: 0,
|
||||
},
|
||||
alignments: crate::Alignments {
|
||||
buffer_copy_offset: wgt::BufferSize::new(
|
||||
d3d12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
buffer_copy_pitch: wgt::BufferSize::new(
|
||||
d3d12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
uniform_buffer_offset: wgt::BufferSize::new(
|
||||
d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
storage_buffer_offset: wgt::BufferSize::new(4).unwrap(), //TODO?
|
||||
},
|
||||
downlevel: wgt::DownlevelCapabilities::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Adapter<super::Api> for super::Adapter {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
_features: wgt::Features,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
let queue = self
|
||||
.device
|
||||
.create_command_queue(
|
||||
native::CmdListType::Direct,
|
||||
native::Priority::Normal,
|
||||
native::CommandQueueFlags::empty(),
|
||||
0,
|
||||
)
|
||||
.check()
|
||||
.map_err(|err| {
|
||||
log::warn!("Queue creation failed: {}", err);
|
||||
crate::DeviceError::OutOfMemory
|
||||
})?;
|
||||
|
||||
Ok(crate::OpenDevice {
|
||||
device: super::Device { raw: self.device },
|
||||
queue: super::Queue { raw: queue },
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(trivial_casts)]
|
||||
unsafe fn texture_format_capabilities(
|
||||
&self,
|
||||
format: wgt::TextureFormat,
|
||||
) -> crate::TextureFormatCapabilities {
|
||||
use crate::TextureFormatCapabilities as Tfc;
|
||||
|
||||
let info = format.describe();
|
||||
let is_compressed = info.block_dimensions != (1, 1);
|
||||
let raw_format = conv::map_texture_format(format);
|
||||
|
||||
let mut data = d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
|
||||
Format: raw_format,
|
||||
Support1: mem::zeroed(),
|
||||
Support2: mem::zeroed(),
|
||||
};
|
||||
assert_eq!(
|
||||
winerror::S_OK,
|
||||
self.device.CheckFeatureSupport(
|
||||
d3d12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||
&mut data as *mut _ as *mut _,
|
||||
mem::size_of::<d3d12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
|
||||
)
|
||||
);
|
||||
|
||||
let mut caps = Tfc::COPY_SRC | Tfc::COPY_DST;
|
||||
let can_image = 0
|
||||
!= data.Support1
|
||||
& (d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE1D
|
||||
| d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE2D
|
||||
| d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE3D
|
||||
| d3d12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE);
|
||||
caps.set(Tfc::SAMPLED, can_image);
|
||||
caps.set(
|
||||
Tfc::SAMPLED_LINEAR,
|
||||
data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE != 0,
|
||||
);
|
||||
caps.set(
|
||||
Tfc::COLOR_ATTACHMENT,
|
||||
data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET != 0,
|
||||
);
|
||||
caps.set(
|
||||
Tfc::COLOR_ATTACHMENT_BLEND,
|
||||
data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_BLENDABLE != 0,
|
||||
);
|
||||
caps.set(
|
||||
Tfc::DEPTH_STENCIL_ATTACHMENT,
|
||||
data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL != 0,
|
||||
);
|
||||
caps.set(
|
||||
Tfc::STORAGE,
|
||||
data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW != 0,
|
||||
);
|
||||
caps.set(
|
||||
Tfc::STORAGE_READ_WRITE,
|
||||
data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD != 0,
|
||||
);
|
||||
|
||||
caps
|
||||
}
|
||||
|
||||
unsafe fn surface_capabilities(
|
||||
&self,
|
||||
surface: &super::Surface,
|
||||
) -> Option<crate::SurfaceCapabilities> {
|
||||
None
|
||||
}
|
||||
}
|
97
wgpu-hal/src/dx12/conv.rs
Normal file
97
wgpu-hal/src/dx12/conv.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use winapi::shared::dxgiformat;
|
||||
|
||||
pub(super) fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
|
||||
use wgt::TextureFormat as Tf;
|
||||
use winapi::shared::dxgiformat::*;
|
||||
|
||||
match format {
|
||||
Tf::R8Unorm => DXGI_FORMAT_R8_UNORM,
|
||||
Tf::R8Snorm => DXGI_FORMAT_R8_SNORM,
|
||||
Tf::R8Uint => DXGI_FORMAT_R8_UINT,
|
||||
Tf::R8Sint => DXGI_FORMAT_R8_SINT,
|
||||
Tf::R16Uint => DXGI_FORMAT_R16_UINT,
|
||||
Tf::R16Sint => DXGI_FORMAT_R16_SINT,
|
||||
Tf::R16Float => DXGI_FORMAT_R16_FLOAT,
|
||||
Tf::Rg8Unorm => DXGI_FORMAT_R8G8_UNORM,
|
||||
Tf::Rg8Snorm => DXGI_FORMAT_R8G8_SNORM,
|
||||
Tf::Rg8Uint => DXGI_FORMAT_R8G8_UINT,
|
||||
Tf::Rg8Sint => DXGI_FORMAT_R8G8_SINT,
|
||||
Tf::R32Uint => DXGI_FORMAT_R32_UINT,
|
||||
Tf::R32Sint => DXGI_FORMAT_R32_SINT,
|
||||
Tf::R32Float => DXGI_FORMAT_R32_FLOAT,
|
||||
Tf::Rg16Uint => DXGI_FORMAT_R16G16_UINT,
|
||||
Tf::Rg16Sint => DXGI_FORMAT_R16G16_SINT,
|
||||
Tf::Rg16Float => DXGI_FORMAT_R16G16_FLOAT,
|
||||
Tf::Rgba8Unorm => DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
Tf::Rgba8UnormSrgb => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
||||
Tf::Bgra8UnormSrgb => DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
|
||||
Tf::Rgba8Snorm => DXGI_FORMAT_R8G8B8A8_SNORM,
|
||||
Tf::Bgra8Unorm => DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
Tf::Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT,
|
||||
Tf::Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT,
|
||||
Tf::Rgb10a2Unorm => DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
Tf::Rg11b10Float => DXGI_FORMAT_R11G11B10_FLOAT,
|
||||
Tf::Rg32Uint => DXGI_FORMAT_R32G32_UINT,
|
||||
Tf::Rg32Sint => DXGI_FORMAT_R32G32_SINT,
|
||||
Tf::Rg32Float => DXGI_FORMAT_R32G32_FLOAT,
|
||||
Tf::Rgba16Uint => DXGI_FORMAT_R16G16B16A16_UINT,
|
||||
Tf::Rgba16Sint => DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
Tf::Rgba16Float => DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
Tf::Rgba32Uint => DXGI_FORMAT_R32G32B32A32_UINT,
|
||||
Tf::Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT,
|
||||
Tf::Rgba32Float => DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
Tf::Depth32Float => DXGI_FORMAT_D32_FLOAT,
|
||||
Tf::Depth24Plus => DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
Tf::Depth24PlusStencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
Tf::Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM,
|
||||
Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_UNORM_SRGB,
|
||||
Tf::Bc2RgbaUnorm => DXGI_FORMAT_BC2_UNORM,
|
||||
Tf::Bc2RgbaUnormSrgb => DXGI_FORMAT_BC2_UNORM_SRGB,
|
||||
Tf::Bc3RgbaUnorm => DXGI_FORMAT_BC3_UNORM,
|
||||
Tf::Bc3RgbaUnormSrgb => DXGI_FORMAT_BC3_UNORM_SRGB,
|
||||
Tf::Bc4RUnorm => DXGI_FORMAT_BC4_UNORM,
|
||||
Tf::Bc4RSnorm => DXGI_FORMAT_BC4_SNORM,
|
||||
Tf::Bc5RgUnorm => DXGI_FORMAT_BC5_UNORM,
|
||||
Tf::Bc5RgSnorm => DXGI_FORMAT_BC5_SNORM,
|
||||
Tf::Bc6hRgbUfloat => DXGI_FORMAT_BC6H_UF16,
|
||||
Tf::Bc6hRgbSfloat => DXGI_FORMAT_BC6H_SF16,
|
||||
Tf::Bc7RgbaUnorm => DXGI_FORMAT_BC7_UNORM,
|
||||
Tf::Bc7RgbaUnormSrgb => DXGI_FORMAT_BC7_UNORM_SRGB,
|
||||
Tf::Etc2RgbUnorm
|
||||
| Tf::Etc2RgbUnormSrgb
|
||||
| Tf::Etc2RgbA1Unorm
|
||||
| Tf::Etc2RgbA1UnormSrgb
|
||||
| Tf::EacRUnorm
|
||||
| Tf::EacRSnorm
|
||||
| Tf::EacRgUnorm
|
||||
| Tf::EacRgSnorm
|
||||
| Tf::Astc4x4RgbaUnorm
|
||||
| Tf::Astc4x4RgbaUnormSrgb
|
||||
| Tf::Astc5x4RgbaUnorm
|
||||
| Tf::Astc5x4RgbaUnormSrgb
|
||||
| Tf::Astc5x5RgbaUnorm
|
||||
| Tf::Astc5x5RgbaUnormSrgb
|
||||
| Tf::Astc6x5RgbaUnorm
|
||||
| Tf::Astc6x5RgbaUnormSrgb
|
||||
| Tf::Astc6x6RgbaUnorm
|
||||
| Tf::Astc6x6RgbaUnormSrgb
|
||||
| Tf::Astc8x5RgbaUnorm
|
||||
| Tf::Astc8x5RgbaUnormSrgb
|
||||
| Tf::Astc8x6RgbaUnorm
|
||||
| Tf::Astc8x6RgbaUnormSrgb
|
||||
| Tf::Astc10x5RgbaUnorm
|
||||
| Tf::Astc10x5RgbaUnormSrgb
|
||||
| Tf::Astc10x6RgbaUnorm
|
||||
| Tf::Astc10x6RgbaUnormSrgb
|
||||
| Tf::Astc8x8RgbaUnorm
|
||||
| Tf::Astc8x8RgbaUnormSrgb
|
||||
| Tf::Astc10x8RgbaUnorm
|
||||
| Tf::Astc10x8RgbaUnormSrgb
|
||||
| Tf::Astc10x10RgbaUnorm
|
||||
| Tf::Astc10x10RgbaUnormSrgb
|
||||
| Tf::Astc12x10RgbaUnorm
|
||||
| Tf::Astc12x10RgbaUnormSrgb
|
||||
| Tf::Astc12x12RgbaUnorm
|
||||
| Tf::Astc12x12RgbaUnormSrgb => unreachable!(),
|
||||
}
|
||||
}
|
627
wgpu-hal/src/dx12/mod.rs
Normal file
627
wgpu-hal/src/dx12/mod.rs
Normal file
@ -0,0 +1,627 @@
|
||||
/*!
|
||||
# DirectX12 API internals.
|
||||
|
||||
## Pipeline Layout
|
||||
|
||||
!*/
|
||||
|
||||
#![allow(unused_variables)]
|
||||
|
||||
mod adapter;
|
||||
mod conv;
|
||||
|
||||
use std::{borrow::Cow, ops::Range, sync::Arc};
|
||||
use winapi::{
|
||||
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, windef, winerror},
|
||||
Interface as _,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Api;
|
||||
//TODO: remove these temporaries
|
||||
pub struct Encoder;
|
||||
#[derive(Debug)]
|
||||
pub struct Resource;
|
||||
|
||||
type DeviceResult<T> = Result<T, crate::DeviceError>;
|
||||
|
||||
impl crate::Api for Api {
|
||||
type Instance = Instance;
|
||||
type Surface = Surface;
|
||||
type Adapter = Adapter;
|
||||
type Device = Device;
|
||||
|
||||
type Queue = Queue;
|
||||
type CommandEncoder = Encoder;
|
||||
type CommandBuffer = Resource;
|
||||
|
||||
type Buffer = Resource;
|
||||
type Texture = Resource;
|
||||
type SurfaceTexture = Resource;
|
||||
type TextureView = Resource;
|
||||
type Sampler = Resource;
|
||||
type QuerySet = Resource;
|
||||
type Fence = Resource;
|
||||
|
||||
type BindGroupLayout = Resource;
|
||||
type BindGroup = Resource;
|
||||
type PipelineLayout = Resource;
|
||||
type ShaderModule = Resource;
|
||||
type RenderPipeline = Resource;
|
||||
type ComputePipeline = Resource;
|
||||
}
|
||||
|
||||
trait HResult {
|
||||
fn to_error(self) -> Option<Cow<'static, str>>;
|
||||
}
|
||||
impl HResult for i32 {
|
||||
fn to_error(self) -> Option<Cow<'static, str>> {
|
||||
if self >= 0 {
|
||||
return None;
|
||||
}
|
||||
let description = match self {
|
||||
winerror::E_UNEXPECTED => "unexpected",
|
||||
winerror::E_NOTIMPL => "not implemented",
|
||||
winerror::E_OUTOFMEMORY => "out of memory",
|
||||
winerror::E_INVALIDARG => "invalid argument",
|
||||
_ => return Some(Cow::Owned(format!("0x{:X}", self as u32))),
|
||||
};
|
||||
Some(Cow::Borrowed(description))
|
||||
}
|
||||
}
|
||||
|
||||
trait HResultPair {
|
||||
type Object;
|
||||
fn check(self) -> Result<Self::Object, Cow<'static, str>>;
|
||||
}
|
||||
impl<T> HResultPair for (T, i32) {
|
||||
type Object = T;
|
||||
fn check(self) -> Result<T, Cow<'static, str>> {
|
||||
match self.1.to_error() {
|
||||
None => Ok(self.0),
|
||||
Some(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
factory: native::Factory4,
|
||||
library: Arc<native::D3D12Lib>,
|
||||
lib_dxgi: native::DxgiLib,
|
||||
}
|
||||
|
||||
impl Drop for Instance {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.factory.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Instance {}
|
||||
unsafe impl Sync for Instance {}
|
||||
|
||||
pub struct Surface {
|
||||
factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
|
||||
wnd_handle: windef::HWND,
|
||||
//presentation: Option<Presentation>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Surface {}
|
||||
unsafe impl Sync for Surface {}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum MemoryArchitecture {
|
||||
Unified { cache_coherent: bool },
|
||||
NonUnified,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct PrivateCapabilities {
|
||||
heterogeneous_resource_heaps: bool,
|
||||
memory_architecture: MemoryArchitecture,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Workarounds {
|
||||
// On WARP, temporary CPU descriptors are still used by the runtime
|
||||
// after we call `CopyDescriptors`.
|
||||
avoid_cpu_descriptor_overwrites: bool,
|
||||
}
|
||||
|
||||
pub struct Adapter {
|
||||
raw: native::WeakPtr<dxgi1_2::IDXGIAdapter2>,
|
||||
device: native::Device,
|
||||
library: Arc<native::D3D12Lib>,
|
||||
private_caps: PrivateCapabilities,
|
||||
workarounds: Workarounds,
|
||||
}
|
||||
|
||||
unsafe impl Send for Adapter {}
|
||||
unsafe impl Sync for Adapter {}
|
||||
|
||||
pub struct Device {
|
||||
raw: native::Device,
|
||||
}
|
||||
|
||||
unsafe impl Send for Device {}
|
||||
unsafe impl Sync for Device {}
|
||||
|
||||
pub struct Queue {
|
||||
raw: native::CommandQueue,
|
||||
}
|
||||
|
||||
unsafe impl Send for Queue {}
|
||||
unsafe impl Sync for Queue {}
|
||||
|
||||
impl crate::Instance<Api> for Instance {
|
||||
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
||||
let lib_main = native::D3D12Lib::new().map_err(|_| crate::InstanceError)?;
|
||||
|
||||
let lib_dxgi = native::DxgiLib::new().map_err(|_| crate::InstanceError)?;
|
||||
let mut factory_flags = native::FactoryCreationFlags::empty();
|
||||
|
||||
if desc.flags.contains(crate::InstanceFlags::VALIDATION) {
|
||||
// Enable debug layer
|
||||
match lib_main.get_debug_interface() {
|
||||
Ok(pair) => match pair.check() {
|
||||
Ok(debug_controller) => {
|
||||
debug_controller.enable_layer();
|
||||
debug_controller.Release();
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Unable to enable D3D12 debug interface: {}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Debug interface function for D3D12 not found: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
|
||||
// `CreateDXGIFactory2` if the debug interface is actually available. So
|
||||
// we check for whether it exists first.
|
||||
match lib_dxgi.get_debug_interface1() {
|
||||
Ok(pair) => match pair.check() {
|
||||
Ok(debug_controller) => {
|
||||
debug_controller.destroy();
|
||||
factory_flags |= native::FactoryCreationFlags::DEBUG;
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Unable to enable DXGI debug interface: {}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Debug interface function for DXGI not found: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create DXGI factory
|
||||
let factory = match lib_dxgi.create_factory2(factory_flags) {
|
||||
Ok(pair) => match pair.check() {
|
||||
Ok(factory) => factory,
|
||||
Err(err) => {
|
||||
log::warn!("Failed to create DXGI factory: {}", err);
|
||||
return Err(crate::InstanceError);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Factory creation function for DXGI not found: {:?}", err);
|
||||
return Err(crate::InstanceError);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
factory,
|
||||
library: Arc::new(lib_main),
|
||||
lib_dxgi,
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn create_surface(
|
||||
&self,
|
||||
has_handle: &impl raw_window_handle::HasRawWindowHandle,
|
||||
) -> Result<Surface, crate::InstanceError> {
|
||||
match has_handle.raw_window_handle() {
|
||||
raw_window_handle::RawWindowHandle::Windows(handle) => {
|
||||
Ok(Surface {
|
||||
factory: self.factory,
|
||||
wnd_handle: handle.hwnd as *mut _,
|
||||
//presentation: None,
|
||||
})
|
||||
}
|
||||
_ => Err(crate::InstanceError),
|
||||
}
|
||||
}
|
||||
unsafe fn destroy_surface(&self, _surface: Surface) {
|
||||
// just drop
|
||||
}
|
||||
|
||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<Api>> {
|
||||
// Try to use high performance order by default (returns None on Windows < 1803)
|
||||
let factory6 = match self.factory.cast::<dxgi1_6::IDXGIFactory6>().check() {
|
||||
Ok(f6) => {
|
||||
// It's okay to decrement the refcount here because we
|
||||
// have another reference to the factory already owned by `self`.
|
||||
f6.destroy();
|
||||
Some(f6)
|
||||
}
|
||||
Err(err) => {
|
||||
log::info!("Failed to cast DXGI to 1.6: {}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Enumerate adapters
|
||||
let mut adapters = Vec::new();
|
||||
for cur_index in 0.. {
|
||||
let raw = match factory6 {
|
||||
Some(factory) => {
|
||||
let mut adapter2 = native::WeakPtr::<dxgi1_2::IDXGIAdapter2>::null();
|
||||
let hr = factory.EnumAdapterByGpuPreference(
|
||||
cur_index,
|
||||
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
||||
&dxgi1_2::IDXGIAdapter2::uuidof(),
|
||||
adapter2.mut_void(),
|
||||
);
|
||||
|
||||
if hr == winerror::DXGI_ERROR_NOT_FOUND {
|
||||
break;
|
||||
}
|
||||
if let Some(err) = hr.to_error() {
|
||||
log::error!("Failed enumerating adapters: {}", err);
|
||||
break;
|
||||
}
|
||||
|
||||
adapter2
|
||||
}
|
||||
None => {
|
||||
let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
|
||||
let hr = self
|
||||
.factory
|
||||
.EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _);
|
||||
|
||||
if hr == winerror::DXGI_ERROR_NOT_FOUND {
|
||||
break;
|
||||
}
|
||||
if let Some(err) = hr.to_error() {
|
||||
log::error!("Failed enumerating adapters: {}", err);
|
||||
break;
|
||||
}
|
||||
|
||||
match adapter1.cast::<dxgi1_2::IDXGIAdapter2>().check() {
|
||||
Ok(adapter2) => {
|
||||
adapter1.destroy();
|
||||
adapter2
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed casting to Adapter2: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
adapters.extend(Adapter::expose(raw, &self.library));
|
||||
}
|
||||
adapters
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Surface<Api> for Surface {
|
||||
unsafe fn configure(
|
||||
&mut self,
|
||||
device: &Device,
|
||||
config: &crate::SurfaceConfiguration,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn unconfigure(&mut self, device: &Device) {}
|
||||
|
||||
unsafe fn acquire_texture(
|
||||
&mut self,
|
||||
timeout_ms: u32,
|
||||
) -> Result<Option<crate::AcquiredSurfaceTexture<Api>>, crate::SurfaceError> {
|
||||
Ok(None)
|
||||
}
|
||||
unsafe fn discard_texture(&mut self, texture: Resource) {}
|
||||
}
|
||||
|
||||
impl crate::Queue<Api> for Queue {
|
||||
unsafe fn submit(
|
||||
&mut self,
|
||||
command_buffers: &[&Resource],
|
||||
signal_fence: Option<(&mut Resource, crate::FenceValue)>,
|
||||
) -> DeviceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn present(
|
||||
&mut self,
|
||||
surface: &mut Surface,
|
||||
texture: Resource,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Device<Api> for Device {
|
||||
unsafe fn exit(self) {}
|
||||
unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_buffer(&self, buffer: Resource) {}
|
||||
unsafe fn map_buffer(
|
||||
&self,
|
||||
buffer: &Resource,
|
||||
range: crate::MemoryRange,
|
||||
) -> DeviceResult<crate::BufferMapping> {
|
||||
Err(crate::DeviceError::Lost)
|
||||
}
|
||||
unsafe fn unmap_buffer(&self, buffer: &Resource) -> DeviceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn flush_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
|
||||
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
|
||||
|
||||
unsafe fn create_texture(&self, desc: &crate::TextureDescriptor) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_texture(&self, texture: Resource) {}
|
||||
unsafe fn create_texture_view(
|
||||
&self,
|
||||
texture: &Resource,
|
||||
desc: &crate::TextureViewDescriptor,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_texture_view(&self, view: Resource) {}
|
||||
unsafe fn create_sampler(&self, desc: &crate::SamplerDescriptor) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_sampler(&self, sampler: Resource) {}
|
||||
|
||||
unsafe fn create_command_encoder(
|
||||
&self,
|
||||
desc: &crate::CommandEncoderDescriptor<Api>,
|
||||
) -> DeviceResult<Encoder> {
|
||||
Ok(Encoder)
|
||||
}
|
||||
unsafe fn destroy_command_encoder(&self, encoder: Encoder) {}
|
||||
|
||||
unsafe fn create_bind_group_layout(
|
||||
&self,
|
||||
desc: &crate::BindGroupLayoutDescriptor,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {}
|
||||
unsafe fn create_pipeline_layout(
|
||||
&self,
|
||||
desc: &crate::PipelineLayoutDescriptor<Api>,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {}
|
||||
unsafe fn create_bind_group(
|
||||
&self,
|
||||
desc: &crate::BindGroupDescriptor<Api>,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_bind_group(&self, group: Resource) {}
|
||||
|
||||
unsafe fn create_shader_module(
|
||||
&self,
|
||||
desc: &crate::ShaderModuleDescriptor,
|
||||
shader: crate::ShaderInput,
|
||||
) -> Result<Resource, crate::ShaderError> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_shader_module(&self, module: Resource) {}
|
||||
unsafe fn create_render_pipeline(
|
||||
&self,
|
||||
desc: &crate::RenderPipelineDescriptor<Api>,
|
||||
) -> Result<Resource, crate::PipelineError> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {}
|
||||
unsafe fn create_compute_pipeline(
|
||||
&self,
|
||||
desc: &crate::ComputePipelineDescriptor<Api>,
|
||||
) -> Result<Resource, crate::PipelineError> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
|
||||
|
||||
unsafe fn create_query_set(
|
||||
&self,
|
||||
desc: &wgt::QuerySetDescriptor<crate::Label>,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_query_set(&self, set: Resource) {}
|
||||
unsafe fn create_fence(&self) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_fence(&self, fence: Resource) {}
|
||||
unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult<crate::FenceValue> {
|
||||
Ok(0)
|
||||
}
|
||||
unsafe fn wait(
|
||||
&self,
|
||||
fence: &Resource,
|
||||
value: crate::FenceValue,
|
||||
timeout_ms: u32,
|
||||
) -> DeviceResult<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
unsafe fn start_capture(&self) -> bool {
|
||||
false
|
||||
}
|
||||
unsafe fn stop_capture(&self) {}
|
||||
}
|
||||
|
||||
impl crate::CommandEncoder<Api> for Encoder {
|
||||
unsafe fn begin_encoding(&mut self, label: crate::Label) -> DeviceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn discard_encoding(&mut self) {}
|
||||
unsafe fn end_encoding(&mut self) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn reset_all<I>(&mut self, command_buffers: I) {}
|
||||
|
||||
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
|
||||
where
|
||||
T: Iterator<Item = crate::BufferBarrier<'a, Api>>,
|
||||
{
|
||||
}
|
||||
|
||||
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
|
||||
where
|
||||
T: Iterator<Item = crate::TextureBarrier<'a, Api>>,
|
||||
{
|
||||
}
|
||||
|
||||
unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {}
|
||||
|
||||
unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &Resource, dst: &Resource, regions: T) {}
|
||||
|
||||
unsafe fn copy_texture_to_texture<T>(
|
||||
&mut self,
|
||||
src: &Resource,
|
||||
src_usage: crate::TextureUses,
|
||||
dst: &Resource,
|
||||
regions: T,
|
||||
) {
|
||||
}
|
||||
|
||||
unsafe fn copy_buffer_to_texture<T>(&mut self, src: &Resource, dst: &Resource, regions: T) {}
|
||||
|
||||
unsafe fn copy_texture_to_buffer<T>(
|
||||
&mut self,
|
||||
src: &Resource,
|
||||
src_usage: crate::TextureUses,
|
||||
dst: &Resource,
|
||||
regions: T,
|
||||
) {
|
||||
}
|
||||
|
||||
unsafe fn begin_query(&mut self, set: &Resource, index: u32) {}
|
||||
unsafe fn end_query(&mut self, set: &Resource, index: u32) {}
|
||||
unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {}
|
||||
unsafe fn reset_queries(&mut self, set: &Resource, range: Range<u32>) {}
|
||||
unsafe fn copy_query_results(
|
||||
&mut self,
|
||||
set: &Resource,
|
||||
range: Range<u32>,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
stride: wgt::BufferSize,
|
||||
) {
|
||||
}
|
||||
|
||||
// render
|
||||
|
||||
unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<Api>) {}
|
||||
unsafe fn end_render_pass(&mut self) {}
|
||||
|
||||
unsafe fn set_bind_group(
|
||||
&mut self,
|
||||
layout: &Resource,
|
||||
index: u32,
|
||||
group: &Resource,
|
||||
dynamic_offsets: &[wgt::DynamicOffset],
|
||||
) {
|
||||
}
|
||||
unsafe fn set_push_constants(
|
||||
&mut self,
|
||||
layout: &Resource,
|
||||
stages: wgt::ShaderStages,
|
||||
offset: u32,
|
||||
data: &[u32],
|
||||
) {
|
||||
}
|
||||
|
||||
unsafe fn insert_debug_marker(&mut self, label: &str) {}
|
||||
unsafe fn begin_debug_marker(&mut self, group_label: &str) {}
|
||||
unsafe fn end_debug_marker(&mut self) {}
|
||||
|
||||
unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {}
|
||||
|
||||
unsafe fn set_index_buffer<'a>(
|
||||
&mut self,
|
||||
binding: crate::BufferBinding<'a, Api>,
|
||||
format: wgt::IndexFormat,
|
||||
) {
|
||||
}
|
||||
unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: crate::BufferBinding<'a, Api>) {
|
||||
}
|
||||
unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {}
|
||||
unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {}
|
||||
unsafe fn set_stencil_reference(&mut self, value: u32) {}
|
||||
unsafe fn set_blend_constants(&mut self, color: &wgt::Color) {}
|
||||
|
||||
unsafe fn draw(
|
||||
&mut self,
|
||||
start_vertex: u32,
|
||||
vertex_count: u32,
|
||||
start_instance: u32,
|
||||
instance_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indexed(
|
||||
&mut self,
|
||||
start_index: u32,
|
||||
index_count: u32,
|
||||
base_vertex: i32,
|
||||
start_instance: u32,
|
||||
instance_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indirect(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
draw_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indexed_indirect(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
draw_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indirect_count(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
count_buffer: &Resource,
|
||||
count_offset: wgt::BufferAddress,
|
||||
max_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indexed_indirect_count(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
count_buffer: &Resource,
|
||||
count_offset: wgt::BufferAddress,
|
||||
max_count: u32,
|
||||
) {
|
||||
}
|
||||
|
||||
// compute
|
||||
|
||||
unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {}
|
||||
unsafe fn end_compute_pass(&mut self) {}
|
||||
|
||||
unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {}
|
||||
|
||||
unsafe fn dispatch(&mut self, count: [u32; 3]) {}
|
||||
unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {}
|
||||
}
|
@ -204,7 +204,9 @@ impl super::Adapter {
|
||||
vertex_shader_storage_blocks.min(fragment_shader_storage_blocks)
|
||||
};
|
||||
|
||||
let mut features = wgt::Features::empty() | wgt::Features::TEXTURE_COMPRESSION_ETC2;
|
||||
let mut features = wgt::Features::empty()
|
||||
| wgt::Features::TEXTURE_COMPRESSION_ETC2
|
||||
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
|
||||
features.set(
|
||||
wgt::Features::DEPTH_CLAMPING,
|
||||
extensions.contains("GL_EXT_depth_clamp"),
|
||||
|
@ -70,8 +70,8 @@ impl super::AdapterShared {
|
||||
| Tf::Bc4RSnorm
|
||||
| Tf::Bc5RgUnorm
|
||||
| Tf::Bc5RgSnorm
|
||||
| Tf::Bc6hRgbSfloat
|
||||
| Tf::Bc6hRgbUfloat
|
||||
| Tf::Bc6hRgbSfloat
|
||||
| Tf::Bc7RgbaUnorm
|
||||
| Tf::Bc7RgbaUnormSrgb => unimplemented!(),
|
||||
Tf::Etc2RgbUnorm => (glow::COMPRESSED_RGB8_ETC2, glow::RGB, 0),
|
||||
|
@ -44,6 +44,8 @@
|
||||
#[cfg(all(feature = "metal", not(any(target_os = "macos", target_os = "ios"))))]
|
||||
compile_error!("Metal backend enabled on non-Apple OS. If your project is not using resolver=\"2\" in Cargo.toml, it should.");
|
||||
|
||||
#[cfg(all(feature = "dx12", windows))]
|
||||
mod dx12;
|
||||
mod empty;
|
||||
#[cfg(feature = "gles")]
|
||||
mod gles;
|
||||
@ -54,6 +56,8 @@ mod vulkan;
|
||||
|
||||
pub mod util;
|
||||
pub mod api {
|
||||
#[cfg(feature = "dx12")]
|
||||
pub use super::dx12::Api as Dx12;
|
||||
pub use super::empty::Api as Empty;
|
||||
#[cfg(feature = "gles")]
|
||||
pub use super::gles::Api as Gles;
|
||||
|
@ -199,8 +199,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
| Tf::Bc4RSnorm
|
||||
| Tf::Bc5RgUnorm
|
||||
| Tf::Bc5RgSnorm
|
||||
| Tf::Bc6hRgbSfloat
|
||||
| Tf::Bc6hRgbUfloat
|
||||
| Tf::Bc6hRgbSfloat
|
||||
| Tf::Bc7RgbaUnorm
|
||||
| Tf::Bc7RgbaUnormSrgb => {
|
||||
if pc.format_bc {
|
||||
@ -889,6 +889,7 @@ impl super::PrivateCapabilities {
|
||||
.flags
|
||||
.set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, true);
|
||||
|
||||
let base = wgt::Limits::default();
|
||||
crate::Capabilities {
|
||||
limits: wgt::Limits {
|
||||
max_texture_dimension_1d: self.max_texture_size as u32,
|
||||
@ -896,18 +897,20 @@ impl super::PrivateCapabilities {
|
||||
max_texture_dimension_3d: self.max_texture_3d_size as u32,
|
||||
max_texture_array_layers: self.max_texture_layers as u32,
|
||||
max_bind_groups: 8,
|
||||
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: 4,
|
||||
max_sampled_textures_per_shader_stage: 16,
|
||||
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: base.max_sampled_textures_per_shader_stage,
|
||||
max_samplers_per_shader_stage: self.max_samplers_per_stage,
|
||||
max_storage_buffers_per_shader_stage: 8,
|
||||
max_storage_textures_per_shader_stage: 8,
|
||||
max_storage_buffers_per_shader_stage: base.max_storage_buffers_per_shader_stage,
|
||||
max_storage_textures_per_shader_stage: base.max_storage_textures_per_shader_stage,
|
||||
max_uniform_buffers_per_shader_stage: 12,
|
||||
max_uniform_buffer_binding_size: self.max_buffer_size.min(!0u32 as u64) as u32,
|
||||
max_storage_buffer_binding_size: self.max_buffer_size.min(!0u32 as u64) as u32,
|
||||
max_vertex_buffers: 8,
|
||||
max_vertex_attributes: 16,
|
||||
max_vertex_buffer_array_stride: 2048,
|
||||
max_vertex_buffers: base.max_vertex_buffers,
|
||||
max_vertex_attributes: base.max_vertex_attributes,
|
||||
max_vertex_buffer_array_stride: base.max_vertex_buffer_array_stride,
|
||||
max_push_constant_size: 0x1000,
|
||||
},
|
||||
alignments: crate::Alignments {
|
||||
|
@ -66,8 +66,8 @@ impl super::PrivateCapabilities {
|
||||
Tf::Bc4RSnorm => F::BC4_SNORM_BLOCK,
|
||||
Tf::Bc5RgUnorm => F::BC5_UNORM_BLOCK,
|
||||
Tf::Bc5RgSnorm => F::BC5_SNORM_BLOCK,
|
||||
Tf::Bc6hRgbSfloat => F::BC6H_SFLOAT_BLOCK,
|
||||
Tf::Bc6hRgbUfloat => F::BC6H_UFLOAT_BLOCK,
|
||||
Tf::Bc6hRgbSfloat => F::BC6H_SFLOAT_BLOCK,
|
||||
Tf::Bc7RgbaUnorm => F::BC7_UNORM_BLOCK,
|
||||
Tf::Bc7RgbaUnormSrgb => F::BC7_SRGB_BLOCK,
|
||||
Tf::Etc2RgbUnorm => F::ETC2_R8G8B8_UNORM_BLOCK,
|
||||
|
Loading…
Reference in New Issue
Block a user