[wgpu-hal] Migrate d3d12 backend over to windows-rs (#5956)

* windows-rs 0.58

* Clean up suspicious committed allocation workaround

* dx12: Flatten suballocation module
This commit is contained in:
Marijn Suijten 2024-08-20 17:48:37 +02:00 committed by GitHub
parent 222f1ea733
commit a157c3cf4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 2466 additions and 4692 deletions

View File

@ -88,6 +88,10 @@ By @wumpf in [#6069](https://github.com/gfx-rs/wgpu/pull/6069), [#6099](https://
- Replace `winapi` code in WGL wrapper to use the `windows` crate. By @MarijnS95 in [#6006](https://github.com/gfx-rs/wgpu/pull/6006)
#### DX12
- Replace `winapi` code to use the `windows` crate. By @MarijnS95 in [#5956](https://github.com/gfx-rs/wgpu/pull/5956)
## 22.0.0 (2024-07-17)
### Overview
@ -749,7 +753,7 @@ The easiest way to make this code safe is to use shared ownership:
```rust
let window: Arc<winit::Window>;
// ...
let surface = instance.create_surface(my_window.clone())?;
let surface = instance.create_surface(window.clone())?;
```
All platform specific surface creation using points have moved into `SurfaceTargetUnsafe` as well.

13
Cargo.lock generated
View File

@ -915,15 +915,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
[[package]]
name = "d3d12"
version = "22.0.0"
dependencies = [
"bitflags 2.6.0",
"libloading 0.8.5",
"winapi",
]
[[package]]
name = "darling"
version = "0.13.4"
@ -1684,7 +1675,6 @@ dependencies = [
"log",
"presser",
"thiserror",
"winapi",
"windows",
]
@ -4325,7 +4315,6 @@ dependencies = [
"cfg-if",
"cfg_aliases",
"core-graphics-types",
"d3d12",
"env_logger",
"glam",
"glow",
@ -4356,8 +4345,8 @@ dependencies = [
"wasm-bindgen",
"web-sys",
"wgpu-types",
"winapi",
"windows",
"windows-core",
"winit 0.29.15",
]

View File

@ -6,7 +6,6 @@ members = [
# default members
"benches",
"d3d12",
"examples",
"naga-cli",
"naga",
@ -24,7 +23,6 @@ members = [
exclude = []
default-members = [
"benches",
"d3d12",
"examples",
"naga-cli",
"naga",
@ -96,8 +94,7 @@ indexmap = "2"
itertools = { version = "0.10.5" }
ktx2 = "0.3"
libc = "0.2"
# libloading 0.8 switches from `winapi` to `windows-sys`; permit either
libloading = ">=0.7, <0.9"
libloading = "0.8"
libtest-mimic = "0.6"
log = "0.4"
nanorand = { version = "0.7", default-features = false, features = ["wyrand"] }
@ -148,14 +145,10 @@ gpu-descriptor = "0.3"
# DX dependencies
bit-set = "0.8"
gpu-allocator = { version = "0.27", default-features = false, features = [
"d3d12",
"public-winapi",
] }
d3d12 = { version = "22.0.0", path = "./d3d12/" }
gpu-allocator = { version = "0.27", default-features = false }
range-alloc = "0.1"
winapi = "0.3"
hassle-rs = "0.11.0"
windows-core = { version = "0.58", default-features = false }
# Gles dependencies
khronos-egl = "6"

View File

@ -1,32 +0,0 @@
# Change Log
## v0.6.0 (2023-01-25)
- add helpers for IDXGIFactoryMedia
- add `create_swapchain_for_composition_surface_handle`
## v0.5.0 (2022-07-01)
- add COM helpers
- enable D3D11 adapter use
## v0.4.1 (2021-08-18)
- expose all indirect argument types
- expose methods for setting root constants
## v0.4.0 (2021-04-29)
- update `libloading` to 0.7
## v0.3.1 (2020-07-07)
- create shader from IL
- fix default doc target
- debug impl for root descriptors
## v0.3.0 (2019-11-01)
- resource transitions
- dynamic library loading
## v0.2.2 (2019-10-04)
- add `D3DHeap`
- add root descriptor
## v0.1.0 (2018-12-26)
- basic version

View File

@ -1,45 +0,0 @@
[package]
name = "d3d12"
version = "22.0.0"
authors = ["gfx-rs developers"]
description = "Low level D3D12 API wrapper"
repository = "https://github.com/gfx-rs/wgpu/tree/trunk/d3d12"
keywords = ["windows", "graphics"]
license = "MIT OR Apache-2.0"
documentation = "https://docs.rs/d3d12"
categories = [
"api-bindings",
"graphics",
"memory-management",
"os::windows-apis",
]
edition = "2018"
[features]
implicit-link = []
[target.'cfg(windows)'.dependencies]
bitflags = "2"
# libloading 0.8 switches from `winapi` to `windows-sys`; permit either
libloading = { version = ">=0.7, <0.9", optional = true }
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = [
"dxgi1_2",
"dxgi1_3",
"dxgi1_4",
"dxgi1_5",
"dxgi1_6",
"dxgidebug",
"d3d12",
"d3d12sdklayers",
"d3dcommon",
"d3dcompiler",
"dxgiformat",
"synchapi",
"winerror",
]
[package.metadata.docs.rs]
targets = ["x86_64-pc-windows-msvc"]

View File

@ -1,5 +0,0 @@
# d3d12-rs
[![Crates.io](https://img.shields.io/crates/v/d3d12.svg)](https://crates.io/crates/d3d12)
[![Docs.rs](https://docs.rs/d3d12/badge.svg)](https://docs.rs/d3d12)
Rust wrapper for raw D3D12 access.

View File

@ -1,263 +0,0 @@
use crate::D3DResult;
use std::{
fmt,
hash::{Hash, Hasher},
ops::Deref,
ptr,
};
use winapi::{ctypes::c_void, um::unknwnbase::IUnknown, Interface};
#[repr(transparent)]
pub struct ComPtr<T: Interface>(*mut T);
impl<T: Interface> ComPtr<T> {
pub fn null() -> Self {
ComPtr(ptr::null_mut())
}
pub unsafe fn from_raw(raw: *mut T) -> Self {
if !raw.is_null() {
(*(raw as *mut IUnknown)).AddRef();
}
ComPtr(raw)
}
pub fn is_null(&self) -> bool {
self.0.is_null()
}
pub fn as_ptr(&self) -> *const T {
self.0
}
pub fn as_mut_ptr(&self) -> *mut T {
self.0
}
pub fn mut_void(&mut self) -> *mut *mut c_void {
&mut self.0 as *mut *mut _ as *mut *mut _
}
pub fn mut_self(&mut self) -> *mut *mut T {
&mut self.0 as *mut *mut _
}
}
impl<T: Interface> ComPtr<T> {
pub unsafe fn as_unknown(&self) -> &IUnknown {
debug_assert!(!self.is_null());
&*(self.0 as *mut IUnknown)
}
pub unsafe fn cast<U>(&self) -> D3DResult<ComPtr<U>>
where
U: Interface,
{
debug_assert!(!self.is_null());
let mut obj = ComPtr::<U>::null();
let hr = self
.as_unknown()
.QueryInterface(&U::uuidof(), obj.mut_void());
(obj, hr)
}
}
impl<T: Interface> Clone for ComPtr<T> {
fn clone(&self) -> Self {
debug_assert!(!self.is_null());
unsafe {
self.as_unknown().AddRef();
}
ComPtr(self.0)
}
}
impl<T: Interface> Drop for ComPtr<T> {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
self.as_unknown().Release();
}
}
}
}
impl<T: Interface> Deref for ComPtr<T> {
type Target = T;
fn deref(&self) -> &T {
debug_assert!(!self.is_null());
unsafe { &*self.0 }
}
}
impl<T: Interface> fmt::Debug for ComPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ComPtr( ptr: {:?} )", self.0)
}
}
impl<T: Interface> PartialEq<*mut T> for ComPtr<T> {
fn eq(&self, other: &*mut T) -> bool {
self.0 == *other
}
}
impl<T: Interface> PartialEq for ComPtr<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: Interface> Hash for ComPtr<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
/// Macro that allows generation of an easy to use enum for dealing with many different possible versions of a COM object.
///
/// Give the variants so that parents come before children. This often manifests as going up in order (1 -> 2 -> 3). This is vital for safety.
///
/// Three function names need to be attached to each variant. The examples are given for the MyComObject1 variant below:
/// - the from function (`ComPtr<actual::ComObject1> -> Self`)
/// - the as function (`&self -> Option<ComPtr<actual::ComObject1>>`)
/// - the unwrap function (`&self -> ComPtr<actual::ComObject1>` panicking on failure to cast)
///
/// ```rust
/// # pub use d3d12::weak_com_inheritance_chain;
/// # mod actual {
/// # pub struct ComObject; impl winapi::Interface for ComObject { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } }
/// # pub struct ComObject1; impl winapi::Interface for ComObject1 { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } }
/// # pub struct ComObject2; impl winapi::Interface for ComObject2 { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } }
/// # }
/// weak_com_inheritance_chain! {
/// pub enum MyComObject {
/// MyComObject(actual::ComObject), from_my_com_object, as_my_com_object, my_com_object; // First variant doesn't use "unwrap" as it can never fail
/// MyComObject1(actual::ComObject1), from_my_com_object1, as_my_com_object1, unwrap_my_com_object1;
/// MyComObject2(actual::ComObject2), from_my_com_object2, as_my_com_object2, unwrap_my_com_object2;
/// }
/// }
/// ```
#[macro_export]
macro_rules! weak_com_inheritance_chain {
// We first match a human readable enum style, before going into the recursive section.
//
// Internal calls to the macro have either the prefix
// - @recursion_logic for the recursion and termination
// - @render_members for the actual call to fill in the members.
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$first_variant:ident($first_type:ty), $first_from_name:ident, $first_as_name:ident, $first_unwrap_name:ident $(;)?
$($variant:ident($type:ty), $from_name:ident, $as_name:ident, $unwrap_name:ident);* $(;)?
}
) => {
$(#[$meta])*
$vis enum $name {
$first_variant($crate::ComPtr<$first_type>),
$(
$variant($crate::ComPtr<$type>)
),+
}
impl $name {
$crate::weak_com_inheritance_chain! {
@recursion_logic,
$vis,
;
$first_variant($first_type), $first_from_name, $first_as_name, $first_unwrap_name;
$($variant($type), $from_name, $as_name, $unwrap_name);*
}
}
impl std::ops::Deref for $name {
type Target = $crate::ComPtr<$first_type>;
fn deref(&self) -> &Self::Target {
self.$first_unwrap_name()
}
}
};
// This is the iteration case of the recursion. We instantiate the member functions for the variant we
// are currently at, recursing on ourself for the next variant. Note we only keep track of the previous
// variant name, not the functions names, as those are not needed.
(
@recursion_logic,
$vis:vis,
$(,)? $($prev_variant:ident),* $(,)?;
$this_variant:ident($this_type:ty), $this_from_name:ident, $this_as_name:ident, $this_unwrap_name:ident $(;)?
$($next_variant:ident($next_type:ty), $next_from_name:ident, $next_as_name:ident, $next_unwrap_name:ident);*
) => {
// Actually generate the members for this variant. Needs the previous and future variant names.
$crate::weak_com_inheritance_chain! {
@render_members,
$vis,
$this_from_name, $this_as_name, $this_unwrap_name;
$($prev_variant),*;
$this_variant($this_type);
$($next_variant),*;
}
// Recurse on ourselves. If there is no future variants left, we'll hit the base case as the final expansion returns no tokens.
$crate::weak_com_inheritance_chain! {
@recursion_logic,
$vis,
$($prev_variant),* , $this_variant;
$($next_variant($next_type), $next_from_name, $next_as_name, $next_unwrap_name);*
}
};
// Base case for recursion. There are no more variants left
(
@recursion_logic,
$vis:vis,
$($prev_variant:ident),*;
) => {};
// This is where we generate the members using the given names.
(
@render_members,
$vis:vis,
$from_name:ident, $as_name:ident, $unwrap_name:ident;
$($prev_variant:ident),*;
$variant:ident($type:ty);
$($next_variant:ident),*;
) => {
// Construct this enum from weak pointer to this interface. For best usability, always use the highest constructor you can. This doesn't try to upcast.
$vis unsafe fn $from_name(value: $crate::ComPtr<$type>) -> Self {
Self::$variant(value)
}
// Returns Some if the value implements the interface otherwise returns None.
$vis fn $as_name(&self) -> Option<&$crate::ComPtr<$type>> {
match *self {
$(
Self::$prev_variant(_) => None,
)*
Self::$variant(ref v) => Some(v),
$(
Self::$next_variant(ref v) => {
// v is &ComPtr<NextType> and se cast to &ComPtr<Type>
Some(unsafe { std::mem::transmute(v) })
}
)*
}
}
// Returns the interface if the value implements it, otherwise panics.
#[track_caller]
$vis fn $unwrap_name(&self) -> &$crate::ComPtr<$type> {
match *self {
$(
Self::$prev_variant(_) => panic!(concat!("Tried to unwrap a ", stringify!($prev_variant), " as a ", stringify!($variant))),
)*
Self::$variant(ref v) => &*v,
$(
Self::$next_variant(ref v) => {
// v is &ComPtr<NextType> and se cast to &ComPtr<Type>
unsafe { std::mem::transmute(v) }
}
)*
}
}
};
}

View File

@ -1,14 +0,0 @@
//! Command Allocator
use crate::com::ComPtr;
use winapi::um::d3d12;
pub type CommandAllocator = ComPtr<d3d12::ID3D12CommandAllocator>;
impl CommandAllocator {
pub fn reset(&self) {
unsafe {
self.Reset();
}
}
}

View File

@ -1,406 +0,0 @@
//! Graphics command list
use crate::{
com::ComPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format,
GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, RootIndex,
RootSignature, Subresource, VertexCount, VertexOffset, WorkGroupCount, HRESULT,
};
use std::{mem, ptr};
use winapi::um::d3d12;
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum CmdListType {
Direct = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT,
Bundle = d3d12::D3D12_COMMAND_LIST_TYPE_BUNDLE,
Compute = d3d12::D3D12_COMMAND_LIST_TYPE_COMPUTE,
Copy = d3d12::D3D12_COMMAND_LIST_TYPE_COPY,
// VideoDecode = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
// VideoProcess = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ClearFlags: u32 {
const DEPTH = d3d12::D3D12_CLEAR_FLAG_DEPTH;
const STENCIL = d3d12::D3D12_CLEAR_FLAG_STENCIL;
}
}
#[repr(transparent)]
pub struct IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC);
impl IndirectArgument {
pub fn draw() -> Self {
IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
..unsafe { mem::zeroed() }
})
}
pub fn draw_indexed() -> Self {
IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
..unsafe { mem::zeroed() }
})
}
pub fn dispatch() -> Self {
IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
..unsafe { mem::zeroed() }
})
}
pub fn vertex_buffer(slot: u32) -> Self {
let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW,
..unsafe { mem::zeroed() }
};
*unsafe { desc.u.VertexBuffer_mut() } =
d3d12::D3D12_INDIRECT_ARGUMENT_DESC_VertexBuffer { Slot: slot };
IndirectArgument(desc)
}
pub fn constant(root_index: RootIndex, dest_offset_words: u32, count: u32) -> Self {
let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
..unsafe { mem::zeroed() }
};
*unsafe { desc.u.Constant_mut() } = d3d12::D3D12_INDIRECT_ARGUMENT_DESC_Constant {
RootParameterIndex: root_index,
DestOffsetIn32BitValues: dest_offset_words,
Num32BitValuesToSet: count,
};
IndirectArgument(desc)
}
pub fn constant_buffer_view(root_index: RootIndex) -> Self {
let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW,
..unsafe { mem::zeroed() }
};
*unsafe { desc.u.ConstantBufferView_mut() } =
d3d12::D3D12_INDIRECT_ARGUMENT_DESC_ConstantBufferView {
RootParameterIndex: root_index,
};
IndirectArgument(desc)
}
pub fn shader_resource_view(root_index: RootIndex) -> Self {
let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW,
..unsafe { mem::zeroed() }
};
*unsafe { desc.u.ShaderResourceView_mut() } =
d3d12::D3D12_INDIRECT_ARGUMENT_DESC_ShaderResourceView {
RootParameterIndex: root_index,
};
IndirectArgument(desc)
}
pub fn unordered_access_view(root_index: RootIndex) -> Self {
let mut desc = d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW,
..unsafe { mem::zeroed() }
};
*unsafe { desc.u.UnorderedAccessView_mut() } =
d3d12::D3D12_INDIRECT_ARGUMENT_DESC_UnorderedAccessView {
RootParameterIndex: root_index,
};
IndirectArgument(desc)
}
}
#[repr(transparent)]
pub struct ResourceBarrier(d3d12::D3D12_RESOURCE_BARRIER);
impl ResourceBarrier {
pub fn transition(
resource: Resource,
subresource: Subresource,
state_before: d3d12::D3D12_RESOURCE_STATES,
state_after: d3d12::D3D12_RESOURCE_STATES,
flags: d3d12::D3D12_RESOURCE_BARRIER_FLAGS,
) -> Self {
let mut barrier = d3d12::D3D12_RESOURCE_BARRIER {
Type: d3d12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
Flags: flags,
..unsafe { mem::zeroed() }
};
unsafe {
*barrier.u.Transition_mut() = d3d12::D3D12_RESOURCE_TRANSITION_BARRIER {
pResource: resource.as_mut_ptr(),
Subresource: subresource,
StateBefore: state_before,
StateAfter: state_after,
};
}
ResourceBarrier(barrier)
}
}
pub type CommandSignature = ComPtr<d3d12::ID3D12CommandSignature>;
pub type CommandList = ComPtr<d3d12::ID3D12CommandList>;
pub type GraphicsCommandList = ComPtr<d3d12::ID3D12GraphicsCommandList>;
impl GraphicsCommandList {
pub fn as_list(&self) -> CommandList {
unsafe { CommandList::from_raw(self.as_mut_ptr() as *mut _) }
}
pub fn close(&self) -> HRESULT {
unsafe { self.Close() }
}
pub fn reset(&self, allocator: &CommandAllocator, initial_pso: PipelineState) -> HRESULT {
unsafe { self.Reset(allocator.as_mut_ptr(), initial_pso.as_mut_ptr()) }
}
pub fn discard_resource(&self, resource: Resource, region: DiscardRegion) {
debug_assert!(region.subregions.start < region.subregions.end);
unsafe {
self.DiscardResource(
resource.as_mut_ptr(),
&d3d12::D3D12_DISCARD_REGION {
NumRects: region.rects.len() as _,
pRects: region.rects.as_ptr(),
FirstSubresource: region.subregions.start,
NumSubresources: region.subregions.end - region.subregions.start - 1,
},
);
}
}
pub fn clear_depth_stencil_view(
&self,
dsv: CpuDescriptor,
flags: ClearFlags,
depth: f32,
stencil: u8,
rects: &[Rect],
) {
let num_rects = rects.len() as _;
let rects = if num_rects > 0 {
rects.as_ptr()
} else {
ptr::null()
};
unsafe {
self.ClearDepthStencilView(dsv, flags.bits(), depth, stencil, num_rects, rects);
}
}
pub fn clear_render_target_view(&self, rtv: CpuDescriptor, color: [f32; 4], rects: &[Rect]) {
let num_rects = rects.len() as _;
let rects = if num_rects > 0 {
rects.as_ptr()
} else {
ptr::null()
};
unsafe {
self.ClearRenderTargetView(rtv, &color, num_rects, rects);
}
}
pub fn dispatch(&self, count: WorkGroupCount) {
unsafe {
self.Dispatch(count[0], count[1], count[2]);
}
}
pub fn draw(
&self,
num_vertices: VertexCount,
num_instances: InstanceCount,
first_vertex: VertexCount,
first_instance: InstanceCount,
) {
unsafe {
self.DrawInstanced(num_vertices, num_instances, first_vertex, first_instance);
}
}
pub fn draw_indexed(
&self,
num_indices: IndexCount,
num_instances: InstanceCount,
first_index: IndexCount,
base_vertex: VertexOffset,
first_instance: InstanceCount,
) {
unsafe {
self.DrawIndexedInstanced(
num_indices,
num_instances,
first_index,
base_vertex,
first_instance,
);
}
}
pub fn set_index_buffer(&self, gpu_address: GpuAddress, size: u32, format: Format) {
let ibv = d3d12::D3D12_INDEX_BUFFER_VIEW {
BufferLocation: gpu_address,
SizeInBytes: size,
Format: format,
};
unsafe {
self.IASetIndexBuffer(&ibv);
}
}
pub fn set_blend_factor(&self, factor: [f32; 4]) {
unsafe {
self.OMSetBlendFactor(&factor);
}
}
pub fn set_stencil_reference(&self, reference: u32) {
unsafe {
self.OMSetStencilRef(reference);
}
}
pub fn set_pipeline_state(&self, pso: &PipelineState) {
unsafe {
self.SetPipelineState(pso.as_mut_ptr());
}
}
pub fn execute_bundle(&self, bundle: GraphicsCommandList) {
unsafe {
self.ExecuteBundle(bundle.as_mut_ptr());
}
}
pub fn set_descriptor_heaps(&self, heaps: &[DescriptorHeap]) {
unsafe {
self.SetDescriptorHeaps(
heaps.len() as _,
heaps.as_ptr() as *mut &DescriptorHeap as *mut _,
);
}
}
pub fn set_compute_root_signature(&self, signature: &RootSignature) {
unsafe {
self.SetComputeRootSignature(signature.as_mut_ptr());
}
}
pub fn set_graphics_root_signature(&self, signature: &RootSignature) {
unsafe {
self.SetGraphicsRootSignature(signature.as_mut_ptr());
}
}
pub fn set_compute_root_descriptor_table(
&self,
root_index: RootIndex,
base_descriptor: GpuDescriptor,
) {
unsafe {
self.SetComputeRootDescriptorTable(root_index, base_descriptor);
}
}
pub fn set_compute_root_constant_buffer_view(
&self,
root_index: RootIndex,
buffer_location: GpuAddress,
) {
unsafe {
self.SetComputeRootConstantBufferView(root_index, buffer_location);
}
}
pub fn set_compute_root_shader_resource_view(
&self,
root_index: RootIndex,
buffer_location: GpuAddress,
) {
unsafe {
self.SetComputeRootShaderResourceView(root_index, buffer_location);
}
}
pub fn set_compute_root_unordered_access_view(
&self,
root_index: RootIndex,
buffer_location: GpuAddress,
) {
unsafe {
self.SetComputeRootUnorderedAccessView(root_index, buffer_location);
}
}
pub fn set_compute_root_constant(
&self,
root_index: RootIndex,
value: u32,
dest_offset_words: u32,
) {
unsafe {
self.SetComputeRoot32BitConstant(root_index, value, dest_offset_words);
}
}
pub fn set_graphics_root_descriptor_table(
&self,
root_index: RootIndex,
base_descriptor: GpuDescriptor,
) {
unsafe {
self.SetGraphicsRootDescriptorTable(root_index, base_descriptor);
}
}
pub fn set_graphics_root_constant_buffer_view(
&self,
root_index: RootIndex,
buffer_location: GpuAddress,
) {
unsafe {
self.SetGraphicsRootConstantBufferView(root_index, buffer_location);
}
}
pub fn set_graphics_root_shader_resource_view(
&self,
root_index: RootIndex,
buffer_location: GpuAddress,
) {
unsafe {
self.SetGraphicsRootShaderResourceView(root_index, buffer_location);
}
}
pub fn set_graphics_root_unordered_access_view(
&self,
root_index: RootIndex,
buffer_location: GpuAddress,
) {
unsafe {
self.SetGraphicsRootUnorderedAccessView(root_index, buffer_location);
}
}
pub fn set_graphics_root_constant(
&self,
root_index: RootIndex,
value: u32,
dest_offset_words: u32,
) {
unsafe {
self.SetGraphicsRoot32BitConstant(root_index, value, dest_offset_words);
}
}
pub fn resource_barrier(&self, barriers: &[ResourceBarrier]) {
unsafe {
self.ResourceBarrier(barriers.len() as _, barriers.as_ptr() as _) // matches representation
}
}
}

View File

@ -1,56 +0,0 @@
use crate::com::ComPtr;
#[cfg(any(feature = "libloading", feature = "implicit-link"))]
use winapi::Interface as _;
use winapi::{
shared::{minwindef::TRUE, winerror::S_OK},
um::d3d12sdklayers,
};
pub type Debug = ComPtr<d3d12sdklayers::ID3D12Debug>;
#[cfg(feature = "libloading")]
impl crate::D3D12Lib {
pub fn get_debug_interface(&self) -> Result<crate::D3DResult<Debug>, libloading::Error> {
type Fun = extern "system" fn(
winapi::shared::guiddef::REFIID,
*mut *mut winapi::ctypes::c_void,
) -> crate::HRESULT;
let mut debug = Debug::null();
let hr = unsafe {
let func: libloading::Symbol<Fun> = self.lib.get(b"D3D12GetDebugInterface")?;
func(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void())
};
Ok((debug, hr))
}
}
impl Debug {
#[cfg(feature = "implicit-link")]
pub fn get_interface() -> crate::D3DResult<Self> {
let mut debug = Debug::null();
let hr = unsafe {
winapi::um::d3d12::D3D12GetDebugInterface(
&d3d12sdklayers::ID3D12Debug::uuidof(),
debug.mut_void(),
)
};
(debug, hr)
}
pub fn enable_layer(&self) {
unsafe { self.EnableDebugLayer() }
}
pub fn enable_gpu_based_validation(&self) -> bool {
let (ptr, hr) = unsafe { self.cast::<d3d12sdklayers::ID3D12Debug1>() };
if hr == S_OK {
unsafe { ptr.SetEnableGPUBasedValidation(TRUE) };
true
} else {
false
}
}
}

View File

@ -1,362 +0,0 @@
use crate::{com::ComPtr, Blob, D3DResult, Error, TextureAddressMode};
use std::{fmt, mem, ops::Range};
use winapi::{shared::dxgiformat, um::d3d12};
pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE;
pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE;
#[derive(Clone, Copy, Debug)]
pub struct Binding {
pub space: u32,
pub register: u32,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum DescriptorHeapType {
CbvSrvUav = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
Sampler = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
Rtv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
Dsv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DescriptorHeapFlags: u32 {
const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
}
}
pub type DescriptorHeap = ComPtr<d3d12::ID3D12DescriptorHeap>;
impl DescriptorHeap {
pub fn start_cpu_descriptor(&self) -> CpuDescriptor {
unsafe { self.GetCPUDescriptorHandleForHeapStart() }
}
pub fn start_gpu_descriptor(&self) -> GpuDescriptor {
unsafe { self.GetGPUDescriptorHandleForHeapStart() }
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum ShaderVisibility {
All = d3d12::D3D12_SHADER_VISIBILITY_ALL,
VS = d3d12::D3D12_SHADER_VISIBILITY_VERTEX,
HS = d3d12::D3D12_SHADER_VISIBILITY_HULL,
DS = d3d12::D3D12_SHADER_VISIBILITY_DOMAIN,
GS = d3d12::D3D12_SHADER_VISIBILITY_GEOMETRY,
PS = d3d12::D3D12_SHADER_VISIBILITY_PIXEL,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum DescriptorRangeType {
SRV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
UAV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
CBV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
Sampler = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
}
#[repr(transparent)]
pub struct DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE);
impl DescriptorRange {
pub fn new(ty: DescriptorRangeType, count: u32, base_binding: Binding, offset: u32) -> Self {
DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE {
RangeType: ty as _,
NumDescriptors: count,
BaseShaderRegister: base_binding.register,
RegisterSpace: base_binding.space,
OffsetInDescriptorsFromTableStart: offset,
})
}
}
impl fmt::Debug for DescriptorRange {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("DescriptorRange")
.field("range_type", &self.0.RangeType)
.field("num", &self.0.NumDescriptors)
.field("register_space", &self.0.RegisterSpace)
.field("base_register", &self.0.BaseShaderRegister)
.field("table_offset", &self.0.OffsetInDescriptorsFromTableStart)
.finish()
}
}
#[repr(transparent)]
pub struct RootParameter(d3d12::D3D12_ROOT_PARAMETER);
impl RootParameter {
// TODO: DescriptorRange must outlive Self
pub fn descriptor_table(visibility: ShaderVisibility, ranges: &[DescriptorRange]) -> Self {
let mut param = d3d12::D3D12_ROOT_PARAMETER {
ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
ShaderVisibility: visibility as _,
..unsafe { mem::zeroed() }
};
*unsafe { param.u.DescriptorTable_mut() } = d3d12::D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: ranges.len() as _,
pDescriptorRanges: ranges.as_ptr() as *const _,
};
RootParameter(param)
}
pub fn constants(visibility: ShaderVisibility, binding: Binding, num: u32) -> Self {
let mut param = d3d12::D3D12_ROOT_PARAMETER {
ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
ShaderVisibility: visibility as _,
..unsafe { mem::zeroed() }
};
*unsafe { param.u.Constants_mut() } = d3d12::D3D12_ROOT_CONSTANTS {
ShaderRegister: binding.register,
RegisterSpace: binding.space,
Num32BitValues: num,
};
RootParameter(param)
}
//TODO: should this be unsafe?
pub fn descriptor(
ty: d3d12::D3D12_ROOT_PARAMETER_TYPE,
visibility: ShaderVisibility,
binding: Binding,
) -> Self {
let mut param = d3d12::D3D12_ROOT_PARAMETER {
ParameterType: ty,
ShaderVisibility: visibility as _,
..unsafe { mem::zeroed() }
};
*unsafe { param.u.Descriptor_mut() } = d3d12::D3D12_ROOT_DESCRIPTOR {
ShaderRegister: binding.register,
RegisterSpace: binding.space,
};
RootParameter(param)
}
pub fn cbv_descriptor(visibility: ShaderVisibility, binding: Binding) -> Self {
Self::descriptor(d3d12::D3D12_ROOT_PARAMETER_TYPE_CBV, visibility, binding)
}
pub fn srv_descriptor(visibility: ShaderVisibility, binding: Binding) -> Self {
Self::descriptor(d3d12::D3D12_ROOT_PARAMETER_TYPE_SRV, visibility, binding)
}
pub fn uav_descriptor(visibility: ShaderVisibility, binding: Binding) -> Self {
Self::descriptor(d3d12::D3D12_ROOT_PARAMETER_TYPE_UAV, visibility, binding)
}
}
impl fmt::Debug for RootParameter {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
#[derive(Debug)]
#[allow(dead_code)] // False-positive
enum Inner<'a> {
Table(&'a [DescriptorRange]),
Constants { binding: Binding, num: u32 },
SingleCbv(Binding),
SingleSrv(Binding),
SingleUav(Binding),
}
let kind = match self.0.ParameterType {
d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE => unsafe {
let raw = self.0.u.DescriptorTable();
Inner::Table(std::slice::from_raw_parts(
raw.pDescriptorRanges as *const _,
raw.NumDescriptorRanges as usize,
))
},
d3d12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS => unsafe {
let raw = self.0.u.Constants();
Inner::Constants {
binding: Binding {
space: raw.RegisterSpace,
register: raw.ShaderRegister,
},
num: raw.Num32BitValues,
}
},
_ => unsafe {
let raw = self.0.u.Descriptor();
let binding = Binding {
space: raw.RegisterSpace,
register: raw.ShaderRegister,
};
match self.0.ParameterType {
d3d12::D3D12_ROOT_PARAMETER_TYPE_CBV => Inner::SingleCbv(binding),
d3d12::D3D12_ROOT_PARAMETER_TYPE_SRV => Inner::SingleSrv(binding),
d3d12::D3D12_ROOT_PARAMETER_TYPE_UAV => Inner::SingleUav(binding),
other => panic!("Unexpected type {:?}", other),
}
},
};
formatter
.debug_struct("RootParameter")
.field("visibility", &self.0.ShaderVisibility)
.field("kind", &kind)
.finish()
}
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum StaticBorderColor {
TransparentBlack = d3d12::D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK,
OpaqueBlack = d3d12::D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,
OpaqueWhite = d3d12::D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
}
#[repr(transparent)]
pub struct StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC);
impl StaticSampler {
pub fn new(
visibility: ShaderVisibility,
binding: Binding,
filter: d3d12::D3D12_FILTER,
address_mode: TextureAddressMode,
mip_lod_bias: f32,
max_anisotropy: u32,
comparison_op: d3d12::D3D12_COMPARISON_FUNC,
border_color: StaticBorderColor,
lod: Range<f32>,
) -> Self {
StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC {
Filter: filter,
AddressU: address_mode[0],
AddressV: address_mode[1],
AddressW: address_mode[2],
MipLODBias: mip_lod_bias,
MaxAnisotropy: max_anisotropy,
ComparisonFunc: comparison_op,
BorderColor: border_color as _,
MinLOD: lod.start,
MaxLOD: lod.end,
ShaderRegister: binding.register,
RegisterSpace: binding.space,
ShaderVisibility: visibility as _,
})
}
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum RootSignatureVersion {
V1_0 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_0,
V1_1 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_1,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct RootSignatureFlags: u32 {
const ALLOW_IA_INPUT_LAYOUT = d3d12::D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
const DENY_VS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS;
const DENY_HS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;
const DENY_DS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS;
const DENY_GS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
const DENY_PS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
}
}
pub type RootSignature = ComPtr<d3d12::ID3D12RootSignature>;
pub type BlobResult = D3DResult<(Blob, Error)>;
#[cfg(feature = "libloading")]
impl crate::D3D12Lib {
pub fn serialize_root_signature(
&self,
version: RootSignatureVersion,
parameters: &[RootParameter],
static_samplers: &[StaticSampler],
flags: RootSignatureFlags,
) -> Result<BlobResult, libloading::Error> {
use winapi::um::d3dcommon::ID3DBlob;
type Fun = extern "system" fn(
*const d3d12::D3D12_ROOT_SIGNATURE_DESC,
d3d12::D3D_ROOT_SIGNATURE_VERSION,
*mut *mut ID3DBlob,
*mut *mut ID3DBlob,
) -> crate::HRESULT;
let desc = d3d12::D3D12_ROOT_SIGNATURE_DESC {
NumParameters: parameters.len() as _,
pParameters: parameters.as_ptr() as *const _,
NumStaticSamplers: static_samplers.len() as _,
pStaticSamplers: static_samplers.as_ptr() as _,
Flags: flags.bits(),
};
let mut blob = Blob::null();
let mut error = Error::null();
let hr = unsafe {
let func: libloading::Symbol<Fun> = self.lib.get(b"D3D12SerializeRootSignature")?;
func(
&desc,
version as _,
blob.mut_void() as *mut *mut _,
error.mut_void() as *mut *mut _,
)
};
Ok(((blob, error), hr))
}
}
impl RootSignature {
#[cfg(feature = "implicit-link")]
pub fn serialize(
version: RootSignatureVersion,
parameters: &[RootParameter],
static_samplers: &[StaticSampler],
flags: RootSignatureFlags,
) -> BlobResult {
let mut blob = Blob::null();
let mut error = Error::null();
let desc = d3d12::D3D12_ROOT_SIGNATURE_DESC {
NumParameters: parameters.len() as _,
pParameters: parameters.as_ptr() as *const _,
NumStaticSamplers: static_samplers.len() as _,
pStaticSamplers: static_samplers.as_ptr() as _,
Flags: flags.bits(),
};
let hr = unsafe {
d3d12::D3D12SerializeRootSignature(
&desc,
version as _,
blob.mut_void() as *mut *mut _,
error.mut_void() as *mut *mut _,
)
};
((blob, error), hr)
}
}
#[repr(transparent)]
pub struct RenderTargetViewDesc(pub(crate) d3d12::D3D12_RENDER_TARGET_VIEW_DESC);
impl RenderTargetViewDesc {
pub fn texture_2d(format: dxgiformat::DXGI_FORMAT, mip_slice: u32, plane_slice: u32) -> Self {
let mut desc = d3d12::D3D12_RENDER_TARGET_VIEW_DESC {
Format: format,
ViewDimension: d3d12::D3D12_RTV_DIMENSION_TEXTURE2D,
..unsafe { mem::zeroed() }
};
*unsafe { desc.u.Texture2D_mut() } = d3d12::D3D12_TEX2D_RTV {
MipSlice: mip_slice,
PlaneSlice: plane_slice,
};
RenderTargetViewDesc(desc)
}
}

View File

@ -1,344 +0,0 @@
//! Device
use crate::{
com::ComPtr,
command_list::{CmdListType, CommandSignature, IndirectArgument},
descriptor::{CpuDescriptor, DescriptorHeapFlags, DescriptorHeapType, RenderTargetViewDesc},
heap::{Heap, HeapFlags, HeapProperties},
pso, query, queue, Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap,
Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature,
Shader, TextureAddressMode,
};
use std::ops::Range;
use winapi::{um::d3d12, Interface};
pub type Device = ComPtr<d3d12::ID3D12Device>;
#[cfg(feature = "libloading")]
impl crate::D3D12Lib {
pub fn create_device<I: Interface>(
&self,
adapter: &ComPtr<I>,
feature_level: crate::FeatureLevel,
) -> Result<D3DResult<Device>, libloading::Error> {
type Fun = extern "system" fn(
*mut winapi::um::unknwnbase::IUnknown,
winapi::um::d3dcommon::D3D_FEATURE_LEVEL,
winapi::shared::guiddef::REFGUID,
*mut *mut winapi::ctypes::c_void,
) -> crate::HRESULT;
let mut device = Device::null();
let hr = unsafe {
let func: libloading::Symbol<Fun> = self.lib.get(b"D3D12CreateDevice")?;
func(
adapter.as_unknown() as *const _ as *mut _,
feature_level as _,
&d3d12::ID3D12Device::uuidof(),
device.mut_void(),
)
};
Ok((device, hr))
}
}
impl Device {
#[cfg(feature = "implicit-link")]
pub fn create<I: Interface>(
adapter: ComPtr<I>,
feature_level: crate::FeatureLevel,
) -> D3DResult<Self> {
let mut device = Device::null();
let hr = unsafe {
d3d12::D3D12CreateDevice(
adapter.as_unknown() as *const _ as *mut _,
feature_level as _,
&d3d12::ID3D12Device::uuidof(),
device.mut_void(),
)
};
(device, hr)
}
pub fn create_heap(
&self,
size_in_bytes: u64,
properties: HeapProperties,
alignment: u64,
flags: HeapFlags,
) -> D3DResult<Heap> {
let mut heap = Heap::null();
let desc = d3d12::D3D12_HEAP_DESC {
SizeInBytes: size_in_bytes,
Properties: properties.0,
Alignment: alignment,
Flags: flags.bits(),
};
let hr = unsafe { self.CreateHeap(&desc, &d3d12::ID3D12Heap::uuidof(), heap.mut_void()) };
(heap, hr)
}
pub fn create_command_allocator(&self, list_type: CmdListType) -> D3DResult<CommandAllocator> {
let mut allocator = CommandAllocator::null();
let hr = unsafe {
self.CreateCommandAllocator(
list_type as _,
&d3d12::ID3D12CommandAllocator::uuidof(),
allocator.mut_void(),
)
};
(allocator, hr)
}
pub fn create_command_queue(
&self,
list_type: CmdListType,
priority: queue::Priority,
flags: queue::CommandQueueFlags,
node_mask: NodeMask,
) -> D3DResult<CommandQueue> {
let desc = d3d12::D3D12_COMMAND_QUEUE_DESC {
Type: list_type as _,
Priority: priority as _,
Flags: flags.bits(),
NodeMask: node_mask,
};
let mut queue = CommandQueue::null();
let hr = unsafe {
self.CreateCommandQueue(
&desc,
&d3d12::ID3D12CommandQueue::uuidof(),
queue.mut_void(),
)
};
(queue, hr)
}
pub fn create_descriptor_heap(
&self,
num_descriptors: u32,
heap_type: DescriptorHeapType,
flags: DescriptorHeapFlags,
node_mask: NodeMask,
) -> D3DResult<DescriptorHeap> {
let desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC {
Type: heap_type as _,
NumDescriptors: num_descriptors,
Flags: flags.bits(),
NodeMask: node_mask,
};
let mut heap = DescriptorHeap::null();
let hr = unsafe {
self.CreateDescriptorHeap(
&desc,
&d3d12::ID3D12DescriptorHeap::uuidof(),
heap.mut_void(),
)
};
(heap, hr)
}
pub fn get_descriptor_increment_size(&self, heap_type: DescriptorHeapType) -> u32 {
unsafe { self.GetDescriptorHandleIncrementSize(heap_type as _) }
}
pub fn create_graphics_command_list(
&self,
list_type: CmdListType,
allocator: &CommandAllocator,
initial: PipelineState,
node_mask: NodeMask,
) -> D3DResult<GraphicsCommandList> {
let mut command_list = GraphicsCommandList::null();
let hr = unsafe {
self.CreateCommandList(
node_mask,
list_type as _,
allocator.as_mut_ptr(),
initial.as_mut_ptr(),
&d3d12::ID3D12GraphicsCommandList::uuidof(),
command_list.mut_void(),
)
};
(command_list, hr)
}
pub fn create_query_heap(
&self,
heap_ty: query::QueryHeapType,
count: u32,
node_mask: NodeMask,
) -> D3DResult<QueryHeap> {
let desc = d3d12::D3D12_QUERY_HEAP_DESC {
Type: heap_ty as _,
Count: count,
NodeMask: node_mask,
};
let mut query_heap = QueryHeap::null();
let hr = unsafe {
self.CreateQueryHeap(
&desc,
&d3d12::ID3D12QueryHeap::uuidof(),
query_heap.mut_void(),
)
};
(query_heap, hr)
}
pub fn create_graphics_pipeline_state(
&self,
_root_signature: RootSignature,
_vs: Shader,
_ps: Shader,
_gs: Shader,
_hs: Shader,
_ds: Shader,
_node_mask: NodeMask,
_cached_pso: CachedPSO,
_flags: pso::PipelineStateFlags,
) -> D3DResult<PipelineState> {
unimplemented!()
}
pub fn create_compute_pipeline_state(
&self,
root_signature: &RootSignature,
cs: Shader,
node_mask: NodeMask,
cached_pso: CachedPSO,
flags: pso::PipelineStateFlags,
) -> D3DResult<PipelineState> {
let mut pipeline = PipelineState::null();
let desc = d3d12::D3D12_COMPUTE_PIPELINE_STATE_DESC {
pRootSignature: root_signature.as_mut_ptr(),
CS: *cs,
NodeMask: node_mask,
CachedPSO: *cached_pso,
Flags: flags.bits(),
};
let hr = unsafe {
self.CreateComputePipelineState(
&desc,
&d3d12::ID3D12PipelineState::uuidof(),
pipeline.mut_void(),
)
};
(pipeline, hr)
}
pub fn create_sampler(
&self,
sampler: CpuDescriptor,
filter: d3d12::D3D12_FILTER,
address_mode: TextureAddressMode,
mip_lod_bias: f32,
max_anisotropy: u32,
comparison_op: d3d12::D3D12_COMPARISON_FUNC,
border_color: [f32; 4],
lod: Range<f32>,
) {
let desc = d3d12::D3D12_SAMPLER_DESC {
Filter: filter,
AddressU: address_mode[0],
AddressV: address_mode[1],
AddressW: address_mode[2],
MipLODBias: mip_lod_bias,
MaxAnisotropy: max_anisotropy,
ComparisonFunc: comparison_op,
BorderColor: border_color,
MinLOD: lod.start,
MaxLOD: lod.end,
};
unsafe {
self.CreateSampler(&desc, sampler);
}
}
pub fn create_root_signature(
&self,
blob: Blob,
node_mask: NodeMask,
) -> D3DResult<RootSignature> {
let mut signature = RootSignature::null();
let hr = unsafe {
self.CreateRootSignature(
node_mask,
blob.GetBufferPointer(),
blob.GetBufferSize(),
&d3d12::ID3D12RootSignature::uuidof(),
signature.mut_void(),
)
};
(signature, hr)
}
pub fn create_command_signature(
&self,
root_signature: RootSignature,
arguments: &[IndirectArgument],
stride: u32,
node_mask: NodeMask,
) -> D3DResult<CommandSignature> {
let mut signature = CommandSignature::null();
let desc = d3d12::D3D12_COMMAND_SIGNATURE_DESC {
ByteStride: stride,
NumArgumentDescs: arguments.len() as _,
pArgumentDescs: arguments.as_ptr() as *const _,
NodeMask: node_mask,
};
let hr = unsafe {
self.CreateCommandSignature(
&desc,
root_signature.as_mut_ptr(),
&d3d12::ID3D12CommandSignature::uuidof(),
signature.mut_void(),
)
};
(signature, hr)
}
pub fn create_render_target_view(
&self,
resource: Resource,
desc: &RenderTargetViewDesc,
descriptor: CpuDescriptor,
) {
unsafe {
self.CreateRenderTargetView(resource.as_mut_ptr(), &desc.0 as *const _, descriptor);
}
}
// TODO: interface not complete
pub fn create_fence(&self, initial: u64) -> D3DResult<Fence> {
let mut fence = Fence::null();
let hr = unsafe {
self.CreateFence(
initial,
d3d12::D3D12_FENCE_FLAG_NONE,
&d3d12::ID3D12Fence::uuidof(),
fence.mut_void(),
)
};
(fence, hr)
}
}

View File

@ -1,377 +0,0 @@
use crate::{com::ComPtr, D3DResult, Resource, SampleDesc, HRESULT};
use std::ptr;
use winapi::{
shared::{
dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgi1_5, dxgi1_6, dxgiformat, dxgitype, minwindef::TRUE,
windef::HWND,
},
um::{d3d12, dxgidebug, unknwnbase::IUnknown, winnt::HANDLE},
Interface,
};
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FactoryCreationFlags: u32 {
const DEBUG = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum Scaling {
Stretch = dxgi1_2::DXGI_SCALING_STRETCH,
Identity = dxgi1_2::DXGI_SCALING_NONE,
Aspect = dxgi1_2::DXGI_SCALING_ASPECT_RATIO_STRETCH,
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum SwapEffect {
Discard = dxgi::DXGI_SWAP_EFFECT_DISCARD,
Sequential = dxgi::DXGI_SWAP_EFFECT_SEQUENTIAL,
FlipDiscard = dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
FlipSequential = dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum AlphaMode {
Unspecified = dxgi1_2::DXGI_ALPHA_MODE_UNSPECIFIED,
Premultiplied = dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
Straight = dxgi1_2::DXGI_ALPHA_MODE_STRAIGHT,
Ignore = dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
ForceDword = dxgi1_2::DXGI_ALPHA_MODE_FORCE_DWORD,
}
pub type InfoQueue = ComPtr<dxgidebug::IDXGIInfoQueue>;
pub type Adapter1 = ComPtr<dxgi::IDXGIAdapter1>;
pub type Adapter2 = ComPtr<dxgi1_2::IDXGIAdapter2>;
pub type Adapter3 = ComPtr<dxgi1_4::IDXGIAdapter3>;
pub type Adapter4 = ComPtr<dxgi1_6::IDXGIAdapter4>;
crate::weak_com_inheritance_chain! {
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum DxgiAdapter {
Adapter1(dxgi::IDXGIAdapter1), from_adapter1, as_adapter1, adapter1;
Adapter2(dxgi1_2::IDXGIAdapter2), from_adapter2, as_adapter2, unwrap_adapter2;
Adapter3(dxgi1_4::IDXGIAdapter3), from_adapter3, as_adapter3, unwrap_adapter3;
Adapter4(dxgi1_6::IDXGIAdapter4), from_adapter4, as_adapter4, unwrap_adapter4;
}
}
pub type Factory1 = ComPtr<dxgi::IDXGIFactory1>;
pub type Factory2 = ComPtr<dxgi1_2::IDXGIFactory2>;
pub type Factory3 = ComPtr<dxgi1_3::IDXGIFactory3>;
pub type Factory4 = ComPtr<dxgi1_4::IDXGIFactory4>;
pub type Factory5 = ComPtr<dxgi1_5::IDXGIFactory5>;
pub type Factory6 = ComPtr<dxgi1_6::IDXGIFactory6>;
crate::weak_com_inheritance_chain! {
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum DxgiFactory {
Factory1(dxgi::IDXGIFactory1), from_factory1, as_factory1, factory1;
Factory2(dxgi1_2::IDXGIFactory2), from_factory2, as_factory2, unwrap_factory2;
Factory3(dxgi1_3::IDXGIFactory3), from_factory3, as_factory3, unwrap_factory3;
Factory4(dxgi1_4::IDXGIFactory4), from_factory4, as_factory4, unwrap_factory4;
Factory5(dxgi1_5::IDXGIFactory5), from_factory5, as_factory5, unwrap_factory5;
Factory6(dxgi1_6::IDXGIFactory6), from_factory6, as_factory6, unwrap_factory6;
}
}
pub type FactoryMedia = ComPtr<dxgi1_3::IDXGIFactoryMedia>;
pub type SwapChain = ComPtr<dxgi::IDXGISwapChain>;
pub type SwapChain1 = ComPtr<dxgi1_2::IDXGISwapChain1>;
pub type SwapChain2 = ComPtr<dxgi1_3::IDXGISwapChain2>;
pub type SwapChain3 = ComPtr<dxgi1_4::IDXGISwapChain3>;
crate::weak_com_inheritance_chain! {
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum DxgiSwapchain {
SwapChain(dxgi::IDXGISwapChain), from_swap_chain, as_swap_chain, swap_chain;
SwapChain1(dxgi1_2::IDXGISwapChain1), from_swap_chain1, as_swap_chain1, unwrap_swap_chain1;
SwapChain2(dxgi1_3::IDXGISwapChain2), from_swap_chain2, as_swap_chain2, unwrap_swap_chain2;
SwapChain3(dxgi1_4::IDXGISwapChain3), from_swap_chain3, as_swap_chain3, unwrap_swap_chain3;
}
}
#[cfg(feature = "libloading")]
#[derive(Debug)]
pub struct DxgiLib {
lib: libloading::Library,
}
#[cfg(feature = "libloading")]
impl DxgiLib {
pub fn new() -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) }
}
pub fn create_factory2(
&self,
flags: FactoryCreationFlags,
) -> Result<D3DResult<Factory4>, libloading::Error> {
type Fun = extern "system" fn(
winapi::shared::minwindef::UINT,
winapi::shared::guiddef::REFIID,
*mut *mut winapi::ctypes::c_void,
) -> HRESULT;
let mut factory = Factory4::null();
let hr = unsafe {
let func: libloading::Symbol<Fun> = self.lib.get(b"CreateDXGIFactory2")?;
func(
flags.bits(),
&dxgi1_4::IDXGIFactory4::uuidof(),
factory.mut_void(),
)
};
Ok((factory, hr))
}
pub fn create_factory1(&self) -> Result<D3DResult<Factory1>, libloading::Error> {
type Fun = extern "system" fn(
winapi::shared::guiddef::REFIID,
*mut *mut winapi::ctypes::c_void,
) -> HRESULT;
let mut factory = Factory1::null();
let hr = unsafe {
let func: libloading::Symbol<Fun> = self.lib.get(b"CreateDXGIFactory1")?;
func(&dxgi::IDXGIFactory1::uuidof(), factory.mut_void())
};
Ok((factory, hr))
}
pub fn create_factory_media(&self) -> Result<D3DResult<FactoryMedia>, libloading::Error> {
type Fun = extern "system" fn(
winapi::shared::guiddef::REFIID,
*mut *mut winapi::ctypes::c_void,
) -> HRESULT;
let mut factory = FactoryMedia::null();
let hr = unsafe {
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nn-dxgi1_3-idxgifactorymedia
let func: libloading::Symbol<Fun> = self.lib.get(b"CreateDXGIFactory1")?;
func(&dxgi1_3::IDXGIFactoryMedia::uuidof(), factory.mut_void())
};
Ok((factory, hr))
}
pub fn get_debug_interface1(&self) -> Result<D3DResult<InfoQueue>, libloading::Error> {
type Fun = extern "system" fn(
winapi::shared::minwindef::UINT,
winapi::shared::guiddef::REFIID,
*mut *mut winapi::ctypes::c_void,
) -> HRESULT;
let mut queue = InfoQueue::null();
let hr = unsafe {
let func: libloading::Symbol<Fun> = self.lib.get(b"DXGIGetDebugInterface1")?;
func(0, &dxgidebug::IDXGIInfoQueue::uuidof(), queue.mut_void())
};
Ok((queue, hr))
}
}
// TODO: strong types
pub struct SwapchainDesc {
pub width: u32,
pub height: u32,
pub format: dxgiformat::DXGI_FORMAT,
pub stereo: bool,
pub sample: SampleDesc,
pub buffer_usage: dxgitype::DXGI_USAGE,
pub buffer_count: u32,
pub scaling: Scaling,
pub swap_effect: SwapEffect,
pub alpha_mode: AlphaMode,
pub flags: u32,
}
impl SwapchainDesc {
pub fn to_desc1(&self) -> dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
AlphaMode: self.alpha_mode as _,
BufferCount: self.buffer_count,
Width: self.width,
Height: self.height,
Format: self.format,
Flags: self.flags,
BufferUsage: self.buffer_usage,
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
Count: self.sample.count,
Quality: self.sample.quality,
},
Scaling: self.scaling as _,
Stereo: self.stereo as _,
SwapEffect: self.swap_effect as _,
}
}
}
impl Factory1 {
pub fn create_swapchain(
&self,
queue: *mut IUnknown,
hwnd: HWND,
desc: &SwapchainDesc,
) -> D3DResult<SwapChain> {
let mut desc = dxgi::DXGI_SWAP_CHAIN_DESC {
BufferDesc: dxgitype::DXGI_MODE_DESC {
Width: desc.width,
Height: desc.width,
RefreshRate: dxgitype::DXGI_RATIONAL {
Numerator: 1,
Denominator: 60,
},
Format: desc.format,
ScanlineOrdering: dxgitype::DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
Scaling: dxgitype::DXGI_MODE_SCALING_UNSPECIFIED,
},
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
Count: desc.sample.count,
Quality: desc.sample.quality,
},
BufferUsage: desc.buffer_usage,
BufferCount: desc.buffer_count,
OutputWindow: hwnd,
Windowed: TRUE,
SwapEffect: desc.swap_effect as _,
Flags: desc.flags,
};
let mut swapchain = SwapChain::null();
let hr =
unsafe { self.CreateSwapChain(queue, &mut desc, swapchain.mut_void() as *mut *mut _) };
(swapchain, hr)
}
}
impl Factory2 {
// TODO: interface not complete
pub fn create_swapchain_for_hwnd(
&self,
queue: *mut IUnknown,
hwnd: HWND,
desc: &SwapchainDesc,
) -> D3DResult<SwapChain1> {
let mut swap_chain = SwapChain1::null();
let hr = unsafe {
self.CreateSwapChainForHwnd(
queue,
hwnd,
&desc.to_desc1(),
ptr::null(),
ptr::null_mut(),
swap_chain.mut_void() as *mut *mut _,
)
};
(swap_chain, hr)
}
pub fn create_swapchain_for_composition(
&self,
queue: *mut IUnknown,
desc: &SwapchainDesc,
) -> D3DResult<SwapChain1> {
let mut swap_chain = SwapChain1::null();
let hr = unsafe {
self.CreateSwapChainForComposition(
queue,
&desc.to_desc1(),
ptr::null_mut(),
swap_chain.mut_void() as *mut *mut _,
)
};
(swap_chain, hr)
}
}
impl Factory4 {
#[cfg(feature = "implicit-link")]
pub fn create(flags: FactoryCreationFlags) -> D3DResult<Self> {
let mut factory = Factory4::null();
let hr = unsafe {
dxgi1_3::CreateDXGIFactory2(
flags.bits(),
&dxgi1_4::IDXGIFactory4::uuidof(),
factory.mut_void(),
)
};
(factory, hr)
}
pub fn enumerate_adapters(&self, id: u32) -> D3DResult<Adapter1> {
let mut adapter = Adapter1::null();
let hr = unsafe { self.EnumAdapters1(id, adapter.mut_void() as *mut *mut _) };
(adapter, hr)
}
}
impl FactoryMedia {
pub fn create_swapchain_for_composition_surface_handle(
&self,
queue: *mut IUnknown,
surface_handle: HANDLE,
desc: &SwapchainDesc,
) -> D3DResult<SwapChain1> {
let mut swap_chain = SwapChain1::null();
let hr = unsafe {
self.CreateSwapChainForCompositionSurfaceHandle(
queue,
surface_handle,
&desc.to_desc1(),
ptr::null_mut(),
swap_chain.mut_void() as *mut *mut _,
)
};
(swap_chain, hr)
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SwapChainPresentFlags: u32 {
const DXGI_PRESENT_DO_NOT_SEQUENCE = dxgi::DXGI_PRESENT_DO_NOT_SEQUENCE;
const DXGI_PRESENT_TEST = dxgi::DXGI_PRESENT_TEST;
const DXGI_PRESENT_RESTART = dxgi::DXGI_PRESENT_RESTART;
const DXGI_PRESENT_DO_NOT_WAIT = dxgi::DXGI_PRESENT_DO_NOT_WAIT;
const DXGI_PRESENT_RESTRICT_TO_OUTPUT = dxgi::DXGI_PRESENT_RESTRICT_TO_OUTPUT;
const DXGI_PRESENT_STEREO_PREFER_RIGHT = dxgi::DXGI_PRESENT_STEREO_PREFER_RIGHT;
const DXGI_PRESENT_STEREO_TEMPORARY_MONO = dxgi::DXGI_PRESENT_STEREO_TEMPORARY_MONO;
const DXGI_PRESENT_USE_DURATION = dxgi::DXGI_PRESENT_USE_DURATION;
const DXGI_PRESENT_ALLOW_TEARING = dxgi::DXGI_PRESENT_ALLOW_TEARING;
}
}
impl SwapChain {
pub fn get_buffer(&self, id: u32) -> D3DResult<Resource> {
let mut resource = Resource::null();
let hr =
unsafe { self.GetBuffer(id, &d3d12::ID3D12Resource::uuidof(), resource.mut_void()) };
(resource, hr)
}
//TODO: replace by present_flags
pub fn present(&self, interval: u32, flags: u32) -> HRESULT {
unsafe { self.Present(interval, flags) }
}
pub fn present_flags(&self, interval: u32, flags: SwapChainPresentFlags) -> HRESULT {
unsafe { self.Present(interval, flags.bits()) }
}
}
impl SwapChain3 {
pub fn get_current_back_buffer_index(&self) -> u32 {
unsafe { self.GetCurrentBackBufferIndex() }
}
}

View File

@ -1,87 +0,0 @@
use crate::com::ComPtr;
use winapi::um::d3d12;
pub type Heap = ComPtr<d3d12::ID3D12Heap>;
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum HeapType {
Default = d3d12::D3D12_HEAP_TYPE_DEFAULT,
Upload = d3d12::D3D12_HEAP_TYPE_UPLOAD,
Readback = d3d12::D3D12_HEAP_TYPE_READBACK,
Custom = d3d12::D3D12_HEAP_TYPE_CUSTOM,
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum CpuPageProperty {
Unknown = d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
NotAvailable = d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
WriteCombine = d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
WriteBack = d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum MemoryPool {
Unknown = d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
L0 = d3d12::D3D12_MEMORY_POOL_L0,
L1 = d3d12::D3D12_MEMORY_POOL_L1,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct HeapFlags: u32 {
const NONE = d3d12::D3D12_HEAP_FLAG_NONE;
const SHARED = d3d12::D3D12_HEAP_FLAG_SHARED;
const DENY_BUFFERS = d3d12::D3D12_HEAP_FLAG_DENY_BUFFERS;
const ALLOW_DISPLAY = d3d12::D3D12_HEAP_FLAG_ALLOW_DISPLAY;
const SHARED_CROSS_ADAPTER = d3d12::D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER;
const DENT_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
const DENY_NON_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
const HARDWARE_PROTECTED = d3d12::D3D12_HEAP_FLAG_HARDWARE_PROTECTED;
const ALLOW_WRITE_WATCH = d3d12::D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH;
const ALLOW_ALL_BUFFERS_AND_TEXTURES = d3d12::D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES;
const ALLOW_ONLY_BUFFERS = d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
const ALLOW_ONLY_NON_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
const ALLOW_ONLY_RT_DS_TEXTURES = d3d12::D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
}
}
#[repr(transparent)]
pub struct HeapProperties(pub d3d12::D3D12_HEAP_PROPERTIES);
impl HeapProperties {
pub fn new(
heap_type: HeapType,
cpu_page_property: CpuPageProperty,
memory_pool_preference: MemoryPool,
creation_node_mask: u32,
visible_node_mask: u32,
) -> Self {
HeapProperties(d3d12::D3D12_HEAP_PROPERTIES {
Type: heap_type as _,
CPUPageProperty: cpu_page_property as _,
MemoryPoolPreference: memory_pool_preference as _,
CreationNodeMask: creation_node_mask,
VisibleNodeMask: visible_node_mask,
})
}
}
#[repr(transparent)]
pub struct HeapDesc(d3d12::D3D12_HEAP_DESC);
impl HeapDesc {
pub fn new(
size_in_bytes: u64,
properties: HeapProperties,
alignment: u64,
flags: HeapFlags,
) -> Self {
HeapDesc(d3d12::D3D12_HEAP_DESC {
SizeInBytes: size_in_bytes,
Properties: properties.0,
Alignment: alignment,
Flags: flags.bits(),
})
}
}

View File

@ -1,125 +0,0 @@
#![cfg(windows)]
#![allow(
clippy::missing_safety_doc,
clippy::too_many_arguments,
clippy::not_unsafe_ptr_arg_deref
)]
use std::{convert::TryFrom, ffi::CStr};
use winapi::{
shared::dxgiformat,
um::{d3d12, d3dcommon},
};
mod com;
mod command_allocator;
mod command_list;
mod debug;
mod descriptor;
mod device;
mod dxgi;
mod heap;
mod pso;
mod query;
mod queue;
mod resource;
mod sync;
pub use crate::com::*;
pub use crate::command_allocator::*;
pub use crate::command_list::*;
pub use crate::debug::*;
pub use crate::descriptor::*;
pub use crate::device::*;
pub use crate::dxgi::*;
pub use crate::heap::*;
pub use crate::pso::*;
pub use crate::query::*;
pub use crate::queue::*;
pub use crate::resource::*;
pub use crate::sync::*;
pub use winapi::shared::winerror::HRESULT;
pub type D3DResult<T> = (T, HRESULT);
pub type GpuAddress = d3d12::D3D12_GPU_VIRTUAL_ADDRESS;
pub type Format = dxgiformat::DXGI_FORMAT;
pub type Rect = d3d12::D3D12_RECT;
pub type NodeMask = u32;
/// Index into the root signature.
pub type RootIndex = u32;
/// Draw vertex count.
pub type VertexCount = u32;
/// Draw vertex base offset.
pub type VertexOffset = i32;
/// Draw number of indices.
pub type IndexCount = u32;
/// Draw number of instances.
pub type InstanceCount = u32;
/// Number of work groups.
pub type WorkGroupCount = [u32; 3];
pub type TextureAddressMode = [d3d12::D3D12_TEXTURE_ADDRESS_MODE; 3];
pub struct SampleDesc {
pub count: u32,
pub quality: u32,
}
#[repr(u32)]
#[non_exhaustive]
pub enum FeatureLevel {
L9_1 = d3dcommon::D3D_FEATURE_LEVEL_9_1,
L9_2 = d3dcommon::D3D_FEATURE_LEVEL_9_2,
L9_3 = d3dcommon::D3D_FEATURE_LEVEL_9_3,
L10_0 = d3dcommon::D3D_FEATURE_LEVEL_10_0,
L10_1 = d3dcommon::D3D_FEATURE_LEVEL_10_1,
L11_0 = d3dcommon::D3D_FEATURE_LEVEL_11_0,
L11_1 = d3dcommon::D3D_FEATURE_LEVEL_11_1,
L12_0 = d3dcommon::D3D_FEATURE_LEVEL_12_0,
L12_1 = d3dcommon::D3D_FEATURE_LEVEL_12_1,
}
impl TryFrom<u32> for FeatureLevel {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
Ok(match value {
d3dcommon::D3D_FEATURE_LEVEL_9_1 => Self::L9_1,
d3dcommon::D3D_FEATURE_LEVEL_9_2 => Self::L9_2,
d3dcommon::D3D_FEATURE_LEVEL_9_3 => Self::L9_3,
d3dcommon::D3D_FEATURE_LEVEL_10_0 => Self::L10_0,
d3dcommon::D3D_FEATURE_LEVEL_10_1 => Self::L10_1,
d3dcommon::D3D_FEATURE_LEVEL_11_0 => Self::L11_0,
d3dcommon::D3D_FEATURE_LEVEL_11_1 => Self::L11_1,
d3dcommon::D3D_FEATURE_LEVEL_12_0 => Self::L12_0,
d3dcommon::D3D_FEATURE_LEVEL_12_1 => Self::L12_1,
_ => return Err(()),
})
}
}
pub type Blob = ComPtr<d3dcommon::ID3DBlob>;
pub type Error = ComPtr<d3dcommon::ID3DBlob>;
impl Error {
pub unsafe fn as_c_str(&self) -> &CStr {
debug_assert!(!self.is_null());
let data = self.GetBufferPointer();
CStr::from_ptr(data as *const _ as *const _)
}
}
#[cfg(feature = "libloading")]
#[derive(Debug)]
pub struct D3D12Lib {
lib: libloading::Library,
}
#[cfg(feature = "libloading")]
impl D3D12Lib {
pub fn new() -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) }
}
}

View File

@ -1,182 +0,0 @@
//! Pipeline state
use crate::{com::ComPtr, Blob, D3DResult, Error};
use std::{
ffi::{self, c_void},
marker::PhantomData,
ops::Deref,
ptr,
};
use winapi::um::{d3d12, d3dcompiler};
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct PipelineStateFlags: u32 {
const TOOL_DEBUG = d3d12::D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG;
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ShaderCompileFlags: u32 {
const DEBUG = d3dcompiler::D3DCOMPILE_DEBUG;
const SKIP_VALIDATION = d3dcompiler::D3DCOMPILE_SKIP_VALIDATION;
const SKIP_OPTIMIZATION = d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION;
const PACK_MATRIX_ROW_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
const PACK_MATRIX_COLUMN_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR;
const PARTIAL_PRECISION = d3dcompiler::D3DCOMPILE_PARTIAL_PRECISION;
// TODO: add missing flags
}
}
#[derive(Copy, Clone)]
pub struct Shader<'a>(d3d12::D3D12_SHADER_BYTECODE, PhantomData<&'a c_void>);
impl<'a> Shader<'a> {
pub fn null() -> Self {
Shader(
d3d12::D3D12_SHADER_BYTECODE {
BytecodeLength: 0,
pShaderBytecode: ptr::null(),
},
PhantomData,
)
}
pub fn from_raw(data: &'a [u8]) -> Self {
Shader(
d3d12::D3D12_SHADER_BYTECODE {
BytecodeLength: data.len() as _,
pShaderBytecode: data.as_ptr() as _,
},
PhantomData,
)
}
// `blob` may not be null.
pub fn from_blob(blob: &'a Blob) -> Self {
Shader(
d3d12::D3D12_SHADER_BYTECODE {
BytecodeLength: unsafe { blob.GetBufferSize() },
pShaderBytecode: unsafe { blob.GetBufferPointer() },
},
PhantomData,
)
}
/// Compile a shader from raw HLSL.
///
/// * `target`: example format: `ps_5_1`.
pub fn compile(
code: &[u8],
target: &ffi::CStr,
entry: &ffi::CStr,
flags: ShaderCompileFlags,
) -> D3DResult<(Blob, Error)> {
let mut shader = Blob::null();
let mut error = Error::null();
let hr = unsafe {
d3dcompiler::D3DCompile(
code.as_ptr() as *const _,
code.len(),
ptr::null(), // defines
ptr::null(), // include
ptr::null_mut(),
entry.as_ptr() as *const _,
target.as_ptr() as *const _,
flags.bits(),
0,
shader.mut_void() as *mut *mut _,
error.mut_void() as *mut *mut _,
)
};
((shader, error), hr)
}
}
impl<'a> Deref for Shader<'a> {
type Target = d3d12::D3D12_SHADER_BYTECODE;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Copy, Clone)]
pub struct CachedPSO<'a>(d3d12::D3D12_CACHED_PIPELINE_STATE, PhantomData<&'a c_void>);
impl<'a> CachedPSO<'a> {
pub fn null() -> Self {
CachedPSO(
d3d12::D3D12_CACHED_PIPELINE_STATE {
CachedBlobSizeInBytes: 0,
pCachedBlob: ptr::null(),
},
PhantomData,
)
}
// `blob` may not be null.
pub fn from_blob(blob: &'a Blob) -> Self {
CachedPSO(
d3d12::D3D12_CACHED_PIPELINE_STATE {
CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() },
pCachedBlob: unsafe { blob.GetBufferPointer() },
},
PhantomData,
)
}
}
impl<'a> Deref for CachedPSO<'a> {
type Target = d3d12::D3D12_CACHED_PIPELINE_STATE;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub type PipelineState = ComPtr<d3d12::ID3D12PipelineState>;
#[repr(u32)]
pub enum Subobject {
RootSignature = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE,
VS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS,
PS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS,
DS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS,
HS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS,
GS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS,
CS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS,
StreamOutput = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT,
Blend = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND,
SampleMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK,
Rasterizer = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER,
DepthStencil = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL,
InputLayout = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT,
IBStripCut = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE,
PrimitiveTopology = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY,
RTFormats = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS,
DSFormat = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT,
SampleDesc = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC,
NodeMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK,
CachedPSO = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO,
Flags = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS,
DepthStencil1 = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1,
// ViewInstancing = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING,
}
/// Subobject of a pipeline stream description
#[repr(C)]
pub struct PipelineStateSubobject<T> {
subobject_align: [usize; 0], // Subobjects must have the same alignment as pointers.
subobject_type: d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE,
subobject: T,
}
impl<T> PipelineStateSubobject<T> {
pub fn new(subobject_type: Subobject, subobject: T) -> Self {
PipelineStateSubobject {
subobject_align: [],
subobject_type: subobject_type as _,
subobject,
}
}
}

View File

@ -1,15 +0,0 @@
use crate::com::ComPtr;
use winapi::um::d3d12;
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum QueryHeapType {
Occlusion = d3d12::D3D12_QUERY_HEAP_TYPE_OCCLUSION,
Timestamp = d3d12::D3D12_QUERY_HEAP_TYPE_TIMESTAMP,
PipelineStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS,
SOStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_SO_STATISTICS,
// VideoDecodeStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_VIDEO_DECODE_STATISTICS,
// CopyQueueTimestamp = d3d12::D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP,
}
pub type QueryHeap = ComPtr<d3d12::ID3D12QueryHeap>;

View File

@ -1,32 +0,0 @@
use crate::{com::ComPtr, sync::Fence, CommandList, HRESULT};
use winapi::um::d3d12;
#[repr(u32)]
pub enum Priority {
Normal = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
High = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_HIGH,
GlobalRealtime = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CommandQueueFlags: u32 {
const DISABLE_GPU_TIMEOUT = d3d12::D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT;
}
}
pub type CommandQueue = ComPtr<d3d12::ID3D12CommandQueue>;
impl CommandQueue {
pub fn execute_command_lists(&self, command_lists: &[CommandList]) {
let command_lists = command_lists
.iter()
.map(CommandList::as_mut_ptr)
.collect::<Box<[_]>>();
unsafe { self.ExecuteCommandLists(command_lists.len() as _, command_lists.as_ptr()) }
}
pub fn signal(&self, fence: &Fence, value: u64) -> HRESULT {
unsafe { self.Signal(fence.as_mut_ptr(), value) }
}
}

View File

@ -1,52 +0,0 @@
//! GPU Resource
use crate::{com::ComPtr, D3DResult, Rect};
use std::{ops::Range, ptr};
use winapi::um::d3d12;
pub type Subresource = u32;
pub struct DiscardRegion<'a> {
pub rects: &'a [Rect],
pub subregions: Range<Subresource>,
}
pub type Resource = ComPtr<d3d12::ID3D12Resource>;
impl Resource {
pub fn map(
&self,
subresource: Subresource,
read_range: Option<Range<usize>>,
) -> D3DResult<*mut ()> {
let mut ptr = ptr::null_mut();
let read_range = read_range.map(|r| d3d12::D3D12_RANGE {
Begin: r.start,
End: r.end,
});
let read = match read_range {
Some(ref r) => r as *const _,
None => ptr::null(),
};
let hr = unsafe { self.Map(subresource, read, &mut ptr) };
(ptr as _, hr)
}
pub fn unmap(&self, subresource: Subresource, write_range: Option<Range<usize>>) {
let write_range = write_range.map(|r| d3d12::D3D12_RANGE {
Begin: r.start,
End: r.end,
});
let write = match write_range {
Some(ref r) => r as *const _,
None => ptr::null(),
};
unsafe { self.Unmap(subresource, write) };
}
pub fn gpu_virtual_address(&self) -> u64 {
unsafe { self.GetGPUVirtualAddress() }
}
}

View File

@ -1,39 +0,0 @@
use crate::{com::ComPtr, HRESULT};
use std::ptr;
use winapi::um::{d3d12, synchapi, winnt};
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Event(pub winnt::HANDLE);
impl Event {
pub fn create(manual_reset: bool, initial_state: bool) -> Self {
Event(unsafe {
synchapi::CreateEventA(
ptr::null_mut(),
manual_reset as _,
initial_state as _,
ptr::null(),
)
})
}
// TODO: return value
pub fn wait(&self, timeout_ms: u32) -> u32 {
unsafe { synchapi::WaitForSingleObject(self.0, timeout_ms) }
}
}
pub type Fence = ComPtr<d3d12::ID3D12Fence>;
impl Fence {
pub fn set_event_on_completion(&self, event: Event, value: u64) -> HRESULT {
unsafe { self.SetEventOnCompletion(value, event.0) }
}
pub fn get_value(&self) -> u64 {
unsafe { self.GetCompletedValue() }
}
pub fn signal(&self, value: u64) -> HRESULT {
unsafe { self.Signal(value) }
}
}

View File

@ -585,7 +585,7 @@ impl Global {
) -> Result<SurfaceId, CreateSurfaceError> {
profiling::scope!("Instance::instance_create_surface_from_visual");
self.instance_create_surface_dx12(id_in, |inst| unsafe {
inst.create_surface_from_visual(visual.cast())
inst.create_surface_from_visual(visual)
})
}
@ -615,7 +615,7 @@ impl Global {
) -> Result<SurfaceId, CreateSurfaceError> {
profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
self.instance_create_surface_dx12(id_in, |inst| unsafe {
inst.create_surface_from_swap_chain_panel(swap_chain_panel.cast())
inst.create_surface_from_swap_chain_panel(swap_chain_panel)
})
}

View File

@ -71,21 +71,24 @@ gles = [
## Has no effect if not targeting Windows.
dx12 = [
# DX12 is only available on Windows, therefore request HLSL output also only if we target Windows.
"naga/hlsl-out-if-target-windows",
"dep:d3d12",
"dep:bit-set",
"dep:libloading",
"dep:range-alloc",
"winapi/std",
"winapi/winbase",
"winapi/d3d12",
"winapi/d3d12shader",
"winapi/d3d12sdklayers",
"winapi/dxgi1_6",
"winapi/errhandlingapi",
"dep:windows-core",
"gpu-allocator/d3d12",
"naga/hlsl-out-if-target-windows",
"windows/Win32_Graphics_Direct3D_Fxc",
"windows/Win32_Graphics_Direct3D",
"windows/Win32_Graphics_Direct3D12",
"windows/Win32_Graphics_DirectComposition",
"windows/Win32_Graphics_Dxgi_Common",
"windows/Win32_Security",
"windows/Win32_System_Diagnostics_Debug",
"windows/Win32_System_Kernel",
"windows/Win32_System_Performance",
"windows/Win32_System_Threading",
"windows/Win32_UI_WindowsAndMessaging",
]
# TODO: This is a separate feature until Mozilla okays windows-rs, see https://github.com/gfx-rs/wgpu/issues/3207 for the tracking issue.
windows_rs = ["dep:gpu-allocator"]
dxc_shader_compiler = ["dep:hassle-rs"]
renderdoc = ["dep:libloading", "dep:renderdoc-sys"]
fragile-send-sync-non-atomic-wasm = ["wgt/fragile-send-sync-non-atomic-wasm"]
@ -154,20 +157,12 @@ bit-set = { workspace = true, optional = true }
range-alloc = { workspace = true, optional = true }
gpu-allocator = { workspace = true, optional = true }
hassle-rs = { workspace = true, optional = true }
# For core macros. This crate is also reexported as windows::core.
windows-core = { workspace = true, optional = true }
# backend: Gles
glutin_wgl_sys = { workspace = true, optional = true }
winapi = { version = "0.3", features = [
"profileapi",
"windef",
"winuser",
"dcomp",
] }
d3d12 = { path = "../d3d12/", version = "22.0.0", optional = true, features = [
"libloading",
] }
[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
# backend: Metal
block = { workspace = true, optional = true }

View File

@ -1,5 +1,6 @@
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
use winapi::shared::dxgiformat;
use windows::Win32::Graphics::Dxgi;
// Helper to convert DXGI adapter name to a normal string
pub fn map_adapter_name(name: [u16; 128]) -> String {
@ -8,9 +9,11 @@ pub fn map_adapter_name(name: [u16; 128]) -> String {
name.to_string_lossy().into_owned()
}
pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option<dxgiformat::DXGI_FORMAT> {
pub fn map_texture_format_failable(
format: wgt::TextureFormat,
) -> Option<Dxgi::Common::DXGI_FORMAT> {
use wgt::TextureFormat as Tf;
use winapi::shared::dxgiformat::*;
use Dxgi::Common::*;
Some(match format {
Tf::R8Unorm => DXGI_FORMAT_R8_UNORM,
@ -94,7 +97,7 @@ pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option<dxgifor
})
}
pub fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
pub fn map_texture_format(format: wgt::TextureFormat) -> Dxgi::Common::DXGI_FORMAT {
match map_texture_format_failable(format) {
Some(f) => f,
None => unreachable!(),
@ -103,10 +106,10 @@ pub fn map_texture_format(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT
// Note: DXGI doesn't allow sRGB format on the swapchain,
// but creating RTV of swapchain buffers with sRGB works.
pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI_FORMAT {
pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> Dxgi::Common::DXGI_FORMAT {
match format {
wgt::TextureFormat::Bgra8UnormSrgb => dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
wgt::TextureFormat::Rgba8UnormSrgb => dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
wgt::TextureFormat::Bgra8UnormSrgb => Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
wgt::TextureFormat::Rgba8UnormSrgb => Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM,
_ => map_texture_format(format),
}
}
@ -116,29 +119,29 @@ pub fn map_texture_format_nosrgb(format: wgt::TextureFormat) -> dxgiformat::DXGI
pub fn map_texture_format_for_srv_uav(
format: wgt::TextureFormat,
aspect: crate::FormatAspects,
) -> Option<dxgiformat::DXGI_FORMAT> {
) -> Option<Dxgi::Common::DXGI_FORMAT> {
Some(match (format, aspect) {
(wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => {
dxgiformat::DXGI_FORMAT_R16_UNORM
Dxgi::Common::DXGI_FORMAT_R16_UNORM
}
(wgt::TextureFormat::Depth32Float, crate::FormatAspects::DEPTH) => {
dxgiformat::DXGI_FORMAT_R32_FLOAT
Dxgi::Common::DXGI_FORMAT_R32_FLOAT
}
(wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::DEPTH) => {
dxgiformat::DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
Dxgi::Common::DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
}
(
wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8,
crate::FormatAspects::DEPTH,
) => dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
) => Dxgi::Common::DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
(wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::STENCIL) => {
dxgiformat::DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
Dxgi::Common::DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
}
(
wgt::TextureFormat::Stencil8 | wgt::TextureFormat::Depth24PlusStencil8,
crate::FormatAspects::STENCIL,
) => dxgiformat::DXGI_FORMAT_X24_TYPELESS_G8_UINT,
) => Dxgi::Common::DXGI_FORMAT_X24_TYPELESS_G8_UINT,
(_, crate::FormatAspects::DEPTH)
| (_, crate::FormatAspects::STENCIL)
@ -152,22 +155,22 @@ pub fn map_texture_format_for_srv_uav(
pub fn map_texture_format_for_copy(
format: wgt::TextureFormat,
aspect: crate::FormatAspects,
) -> Option<dxgiformat::DXGI_FORMAT> {
) -> Option<Dxgi::Common::DXGI_FORMAT> {
Some(match (format, aspect) {
(wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => {
dxgiformat::DXGI_FORMAT_R16_UNORM
Dxgi::Common::DXGI_FORMAT_R16_UNORM
}
(
wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth32FloatStencil8,
crate::FormatAspects::DEPTH,
) => dxgiformat::DXGI_FORMAT_R32_FLOAT,
) => Dxgi::Common::DXGI_FORMAT_R32_FLOAT,
(
wgt::TextureFormat::Stencil8
| wgt::TextureFormat::Depth24PlusStencil8
| wgt::TextureFormat::Depth32FloatStencil8,
crate::FormatAspects::STENCIL,
) => dxgiformat::DXGI_FORMAT_R8_UINT,
) => Dxgi::Common::DXGI_FORMAT_R8_UINT,
(format, crate::FormatAspects::COLOR) => map_texture_format(format),
@ -180,9 +183,9 @@ pub fn map_texture_format_for_resource(
usage: crate::TextureUses,
has_view_formats: bool,
casting_fully_typed_format_supported: bool,
) -> dxgiformat::DXGI_FORMAT {
) -> Dxgi::Common::DXGI_FORMAT {
use wgt::TextureFormat as Tf;
use winapi::shared::dxgiformat::*;
use Dxgi::Common::*;
if casting_fully_typed_format_supported {
map_texture_format(format)
@ -219,16 +222,16 @@ pub fn map_texture_format_for_resource(
}
}
pub fn map_index_format(format: wgt::IndexFormat) -> dxgiformat::DXGI_FORMAT {
pub fn map_index_format(format: wgt::IndexFormat) -> Dxgi::Common::DXGI_FORMAT {
match format {
wgt::IndexFormat::Uint16 => dxgiformat::DXGI_FORMAT_R16_UINT,
wgt::IndexFormat::Uint32 => dxgiformat::DXGI_FORMAT_R32_UINT,
wgt::IndexFormat::Uint16 => Dxgi::Common::DXGI_FORMAT_R16_UINT,
wgt::IndexFormat::Uint32 => Dxgi::Common::DXGI_FORMAT_R32_UINT,
}
}
pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT {
pub fn map_vertex_format(format: wgt::VertexFormat) -> Dxgi::Common::DXGI_FORMAT {
use wgt::VertexFormat as Vf;
use winapi::shared::dxgiformat::*;
use Dxgi::Common::*;
match format {
Vf::Unorm8x2 => DXGI_FORMAT_R8G8_UNORM,
@ -266,6 +269,6 @@ pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT {
}
}
pub fn map_acomposite_alpha_mode(_mode: wgt::CompositeAlphaMode) -> d3d12::AlphaMode {
d3d12::AlphaMode::Ignore
pub fn map_acomposite_alpha_mode(_mode: wgt::CompositeAlphaMode) -> Dxgi::Common::DXGI_ALPHA_MODE {
Dxgi::Common::DXGI_ALPHA_MODE_IGNORE
}

View File

@ -1,10 +1,7 @@
use std::{borrow::Cow, slice};
use parking_lot::{lock_api::RawMutex, Mutex};
use winapi::{
um::{errhandlingapi, winnt},
vc::excpt,
};
use windows::Win32::{Foundation, System::Diagnostics::Debug};
// This is a mutex as opposed to an atomic as we need to completely
// lock everyone out until we have registered or unregistered the
@ -17,9 +14,7 @@ static EXCEPTION_HANDLER_COUNT: Mutex<usize> = Mutex::const_new(parking_lot::Raw
pub fn register_exception_handler() {
let mut count_guard = EXCEPTION_HANDLER_COUNT.lock();
if *count_guard == 0 {
unsafe {
errhandlingapi::AddVectoredExceptionHandler(0, Some(output_debug_string_handler))
};
unsafe { Debug::AddVectoredExceptionHandler(0, Some(output_debug_string_handler)) };
}
*count_guard += 1;
}
@ -27,9 +22,7 @@ pub fn register_exception_handler() {
pub fn unregister_exception_handler() {
let mut count_guard = EXCEPTION_HANDLER_COUNT.lock();
if *count_guard == 1 {
unsafe {
errhandlingapi::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _)
};
unsafe { Debug::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _) };
}
*count_guard -= 1;
}
@ -43,34 +36,34 @@ const MESSAGE_PREFIXES: &[(&str, log::Level)] = &[
];
unsafe extern "system" fn output_debug_string_handler(
exception_info: *mut winnt::EXCEPTION_POINTERS,
exception_info: *mut Debug::EXCEPTION_POINTERS,
) -> i32 {
// See https://stackoverflow.com/a/41480827
let record = unsafe { &*(*exception_info).ExceptionRecord };
if record.NumberParameters != 2 {
return excpt::EXCEPTION_CONTINUE_SEARCH;
return Debug::EXCEPTION_CONTINUE_SEARCH;
}
let message = match record.ExceptionCode {
winnt::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(unsafe {
Foundation::DBG_PRINTEXCEPTION_C => String::from_utf8_lossy(unsafe {
slice::from_raw_parts(
record.ExceptionInformation[1] as *const u8,
record.ExceptionInformation[0],
)
}),
winnt::DBG_PRINTEXCEPTION_WIDE_C => Cow::Owned(String::from_utf16_lossy(unsafe {
Foundation::DBG_PRINTEXCEPTION_WIDE_C => Cow::Owned(String::from_utf16_lossy(unsafe {
slice::from_raw_parts(
record.ExceptionInformation[1] as *const u16,
record.ExceptionInformation[0],
)
})),
_ => return excpt::EXCEPTION_CONTINUE_SEARCH,
_ => return Debug::EXCEPTION_CONTINUE_SEARCH,
};
let message = match message.strip_prefix("D3D12 ") {
Some(msg) => msg
.trim_end_matches("\n\0")
.trim_end_matches("[ STATE_CREATION WARNING #0: UNKNOWN]"),
None => return excpt::EXCEPTION_CONTINUE_SEARCH,
None => return Debug::EXCEPTION_CONTINUE_SEARCH,
};
let (message, level) = match MESSAGE_PREFIXES
@ -84,12 +77,12 @@ unsafe extern "system" fn output_debug_string_handler(
if level == log::Level::Warn && message.contains("#82") {
// This is are useless spammy warnings (#820, #821):
// "The application did not pass any clear value to resource creation"
return excpt::EXCEPTION_CONTINUE_SEARCH;
return Debug::EXCEPTION_CONTINUE_SEARCH;
}
if level == log::Level::Warn && message.contains("DRAW_EMPTY_SCISSOR_RECTANGLE") {
// This is normal, WebGPU allows passing empty scissor rectangles.
return excpt::EXCEPTION_CONTINUE_SEARCH;
return Debug::EXCEPTION_CONTINUE_SEARCH;
}
let _ = std::panic::catch_unwind(|| {
@ -101,5 +94,5 @@ unsafe extern "system" fn output_debug_string_handler(
crate::VALIDATION_CANARY.add(message.to_string());
}
excpt::EXCEPTION_CONTINUE_EXECUTION
Debug::EXCEPTION_CONTINUE_EXECUTION
}

View File

@ -1,9 +1,8 @@
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, winerror},
Interface,
};
use std::ops::Deref;
use super::result::HResult as _;
use windows::{core::Interface as _, Win32::Graphics::Dxgi};
use crate::dx12::DxgiLib;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum DxgiFactoryType {
@ -12,9 +11,8 @@ pub enum DxgiFactoryType {
Factory6,
}
fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool {
let mut desc = unsafe { std::mem::zeroed() };
unsafe { adapter.GetDesc1(&mut desc) };
fn should_keep_adapter(adapter: &Dxgi::IDXGIAdapter1) -> bool {
let desc = unsafe { adapter.GetDesc1() }.unwrap();
// The Intel Haswell family of iGPUs had support for the D3D12 API but it was later
// removed due to a security vulnerability.
@ -40,8 +38,10 @@ fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool {
// which is lying about being an integrated card. This is so that programs
// that ignore software adapters will actually run on headless/gpu-less machines.
//
// We don't want that and discorage that kind of filtering anyway, so we skip the integrated WARP.
if desc.VendorId == 5140 && (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) == 0 {
// We don't want that and discourage that kind of filtering anyway, so we skip the integrated WARP.
if desc.VendorId == 5140
&& Dxgi::DXGI_ADAPTER_FLAG(desc.Flags as i32).contains(Dxgi::DXGI_ADAPTER_FLAG_SOFTWARE)
{
let adapter_name = super::conv::map_adapter_name(desc.Description);
if adapter_name.contains("Microsoft Basic Render Driver") {
return false;
@ -51,50 +51,85 @@ fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool {
true
}
pub fn enumerate_adapters(factory: d3d12::DxgiFactory) -> Vec<d3d12::DxgiAdapter> {
pub enum DxgiAdapter {
Adapter1(Dxgi::IDXGIAdapter1),
Adapter2(Dxgi::IDXGIAdapter2),
Adapter3(Dxgi::IDXGIAdapter3),
Adapter4(Dxgi::IDXGIAdapter4),
}
impl windows::core::Param<Dxgi::IDXGIAdapter> for &DxgiAdapter {
unsafe fn param(self) -> windows::core::ParamValue<Dxgi::IDXGIAdapter> {
unsafe { self.deref().param() }
}
}
impl Deref for DxgiAdapter {
type Target = Dxgi::IDXGIAdapter;
fn deref(&self) -> &Self::Target {
match self {
DxgiAdapter::Adapter1(a) => a,
DxgiAdapter::Adapter2(a) => a,
DxgiAdapter::Adapter3(a) => a,
DxgiAdapter::Adapter4(a) => a,
}
}
}
impl DxgiAdapter {
pub fn as_adapter2(&self) -> Option<&Dxgi::IDXGIAdapter2> {
match self {
Self::Adapter1(_) => None,
Self::Adapter2(f) => Some(f),
Self::Adapter3(f) => Some(f),
Self::Adapter4(f) => Some(f),
}
}
pub fn unwrap_adapter2(&self) -> &Dxgi::IDXGIAdapter2 {
self.as_adapter2().unwrap()
}
}
pub fn enumerate_adapters(factory: DxgiFactory) -> Vec<DxgiAdapter> {
let mut adapters = Vec::with_capacity(8);
for cur_index in 0.. {
if let Some(factory6) = factory.as_factory6() {
if let DxgiFactory::Factory6(ref factory6) = factory {
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
// We're already at dxgi1.6, we can grab IDXGIAdapter4 directly
let mut adapter4 = d3d12::ComPtr::<dxgi1_6::IDXGIAdapter4>::null();
let hr = unsafe {
let adapter4: Dxgi::IDXGIAdapter4 = match unsafe {
factory6.EnumAdapterByGpuPreference(
cur_index,
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&dxgi1_6::IDXGIAdapter4::uuidof(),
adapter4.mut_void(),
Dxgi::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
)
} {
Ok(a) => a,
Err(e) if e.code() == Dxgi::DXGI_ERROR_NOT_FOUND => break,
Err(e) => {
log::error!("Failed enumerating adapters: {}", e);
break;
}
};
if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
if !should_keep_adapter(&adapter4) {
continue;
}
adapters.push(d3d12::DxgiAdapter::Adapter4(adapter4));
adapters.push(DxgiAdapter::Adapter4(adapter4));
continue;
}
profiling::scope!("IDXGIFactory1::EnumAdapters1");
let mut adapter1 = d3d12::ComPtr::<dxgi::IDXGIAdapter1>::null();
let hr = unsafe { factory.EnumAdapters1(cur_index, adapter1.mut_self()) };
if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
let adapter1: Dxgi::IDXGIAdapter1 = match unsafe { factory.EnumAdapters1(cur_index) } {
Ok(a) => a,
Err(e) if e.code() == Dxgi::DXGI_ERROR_NOT_FOUND => break,
Err(e) => {
log::error!("Failed enumerating adapters: {}", e);
break;
}
};
if !should_keep_adapter(&adapter1) {
continue;
@ -103,58 +138,97 @@ pub fn enumerate_adapters(factory: d3d12::DxgiFactory) -> Vec<d3d12::DxgiAdapter
// Do the most aggressive casts first, skipping Adapter4 as we definitely don't have dxgi1_6.
// Adapter1 -> Adapter3
unsafe {
match adapter1.cast::<dxgi1_4::IDXGIAdapter3>().into_result() {
Ok(adapter3) => {
adapters.push(d3d12::DxgiAdapter::Adapter3(adapter3));
continue;
}
Err(err) => {
log::warn!("Failed casting Adapter1 to Adapter3: {}", err);
}
match adapter1.cast::<Dxgi::IDXGIAdapter3>() {
Ok(adapter3) => {
adapters.push(DxgiAdapter::Adapter3(adapter3));
continue;
}
Err(err) => {
log::warn!("Failed casting Adapter1 to Adapter3: {}", err);
}
}
// Adapter1 -> Adapter2
unsafe {
match adapter1.cast::<dxgi1_2::IDXGIAdapter2>().into_result() {
Ok(adapter2) => {
adapters.push(d3d12::DxgiAdapter::Adapter2(adapter2));
continue;
}
Err(err) => {
log::warn!("Failed casting Adapter1 to Adapter2: {}", err);
}
match adapter1.cast::<Dxgi::IDXGIAdapter2>() {
Ok(adapter2) => {
adapters.push(DxgiAdapter::Adapter2(adapter2));
continue;
}
Err(err) => {
log::warn!("Failed casting Adapter1 to Adapter2: {}", err);
}
}
adapters.push(d3d12::DxgiAdapter::Adapter1(adapter1));
adapters.push(DxgiAdapter::Adapter1(adapter1));
}
adapters
}
/// Tries to create a IDXGIFactory6, then a IDXGIFactory4, then a IDXGIFactory2, then a IDXGIFactory1,
#[derive(Clone, Debug)]
pub enum DxgiFactory {
Factory1(Dxgi::IDXGIFactory1),
Factory2(Dxgi::IDXGIFactory2),
Factory4(Dxgi::IDXGIFactory4),
Factory6(Dxgi::IDXGIFactory6),
}
impl Deref for DxgiFactory {
type Target = Dxgi::IDXGIFactory1;
fn deref(&self) -> &Self::Target {
match self {
DxgiFactory::Factory1(f) => f,
DxgiFactory::Factory2(f) => f,
DxgiFactory::Factory4(f) => f,
DxgiFactory::Factory6(f) => f,
}
}
}
impl DxgiFactory {
pub fn as_factory2(&self) -> Option<&Dxgi::IDXGIFactory2> {
match self {
Self::Factory1(_) => None,
Self::Factory2(f) => Some(f),
Self::Factory4(f) => Some(f),
Self::Factory6(f) => Some(f),
}
}
pub fn unwrap_factory2(&self) -> &Dxgi::IDXGIFactory2 {
self.as_factory2().unwrap()
}
pub fn as_factory5(&self) -> Option<&Dxgi::IDXGIFactory5> {
match self {
Self::Factory1(_) | Self::Factory2(_) | Self::Factory4(_) => None,
Self::Factory6(f) => Some(f),
}
}
}
/// Tries to create a [`Dxgi::IDXGIFactory6`], then a [`Dxgi::IDXGIFactory4`], then a [`Dxgi::IDXGIFactory2`], then a [`Dxgi::IDXGIFactory1`],
/// returning the one that succeeds, or if the required_factory_type fails to be
/// created.
pub fn create_factory(
required_factory_type: DxgiFactoryType,
instance_flags: wgt::InstanceFlags,
) -> Result<(d3d12::DxgiLib, d3d12::DxgiFactory), crate::InstanceError> {
let lib_dxgi = d3d12::DxgiLib::new().map_err(|e| {
) -> Result<(DxgiLib, DxgiFactory), crate::InstanceError> {
let lib_dxgi = DxgiLib::new().map_err(|e| {
crate::InstanceError::with_source(String::from("failed to load dxgi.dll"), e)
})?;
let mut factory_flags = d3d12::FactoryCreationFlags::empty();
let mut factory_flags = Dxgi::DXGI_CREATE_FACTORY_FLAGS::default();
if instance_flags.contains(wgt::InstanceFlags::VALIDATION) {
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
// `CreateDXGIFactory2` if the debug interface is actually available. So
// we check for whether it exists first.
match lib_dxgi.get_debug_interface1() {
Ok(pair) => match pair.into_result() {
match lib_dxgi.debug_interface1() {
Ok(pair) => match pair {
Ok(_debug_controller) => {
factory_flags |= d3d12::FactoryCreationFlags::DEBUG;
factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG;
}
Err(err) => {
log::warn!("Unable to enable DXGI debug interface: {}", err);
@ -171,7 +245,7 @@ pub fn create_factory(
// Try to create IDXGIFactory4
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
Ok(pair) => match pair.into_result() {
Ok(pair) => match pair {
Ok(factory) => Some(factory),
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
Err(err) => {
@ -197,10 +271,10 @@ pub fn create_factory(
if let Some(factory4) = factory4 {
// Try to cast the IDXGIFactory4 into IDXGIFactory6
let factory6 = unsafe { factory4.cast::<dxgi1_6::IDXGIFactory6>().into_result() };
let factory6 = factory4.cast::<Dxgi::IDXGIFactory6>();
match factory6 {
Ok(factory6) => {
return Ok((lib_dxgi, d3d12::DxgiFactory::Factory6(factory6)));
return Ok((lib_dxgi, DxgiFactory::Factory6(factory6)));
}
// If we require factory6, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory6 => {
@ -212,14 +286,14 @@ pub fn create_factory(
// If we don't print it to warn.
Err(err) => {
log::warn!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err);
return Ok((lib_dxgi, d3d12::DxgiFactory::Factory4(factory4)));
return Ok((lib_dxgi, DxgiFactory::Factory4(factory4)));
}
}
}
// Try to create IDXGIFactory1
let factory1 = match lib_dxgi.create_factory1() {
Ok(pair) => match pair.into_result() {
Ok(pair) => match pair {
Ok(factory) => factory,
Err(err) => {
// err is a Cow<str>, not an Error implementor
@ -238,10 +312,10 @@ pub fn create_factory(
};
// Try to cast the IDXGIFactory1 into IDXGIFactory2
let factory2 = unsafe { factory1.cast::<dxgi1_2::IDXGIFactory2>().into_result() };
let factory2 = factory1.cast::<Dxgi::IDXGIFactory2>();
match factory2 {
Ok(factory2) => {
return Ok((lib_dxgi, d3d12::DxgiFactory::Factory2(factory2)));
return Ok((lib_dxgi, DxgiFactory::Factory2(factory2)));
}
// If we require factory2, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory2 => {
@ -257,5 +331,5 @@ pub fn create_factory(
}
// We tried to create 4 and 2, but only succeeded with 1.
Ok((lib_dxgi, d3d12::DxgiFactory::Factory1(factory1)))
Ok((lib_dxgi, DxgiFactory::Factory1(factory1)))
}

View File

@ -1,37 +1,46 @@
use std::borrow::Cow;
use winapi::shared::winerror;
use windows::Win32::{Foundation, Graphics::Dxgi};
pub(crate) trait HResult<O> {
fn into_result(self) -> Result<O, Cow<'static, str>>;
fn into_device_result(self, description: &str) -> Result<O, crate::DeviceError>;
}
impl HResult<()> for i32 {
fn into_result(self) -> Result<(), Cow<'static, str>> {
if self >= 0 {
return Ok(());
}
impl<T> HResult<T> for windows::core::Result<T> {
fn into_result(self) -> Result<T, Cow<'static, str>> {
// TODO: use windows-rs built-in error formatting?
let description = match self {
winerror::E_UNEXPECTED => "unexpected",
winerror::E_NOTIMPL => "not implemented",
winerror::E_OUTOFMEMORY => "out of memory",
winerror::E_INVALIDARG => "invalid argument",
_ => return Err(Cow::Owned(format!("0x{:X}", self as u32))),
Ok(t) => return Ok(t),
Err(e) if e.code() == Foundation::E_UNEXPECTED => "unexpected",
Err(e) if e.code() == Foundation::E_NOTIMPL => "not implemented",
Err(e) if e.code() == Foundation::E_OUTOFMEMORY => "out of memory",
Err(e) if e.code() == Foundation::E_INVALIDARG => "invalid argument",
Err(e) => return Err(Cow::Owned(format!("{e:?}"))),
};
Err(Cow::Borrowed(description))
}
fn into_device_result(self, description: &str) -> Result<(), crate::DeviceError> {
fn into_device_result(self, description: &str) -> Result<T, crate::DeviceError> {
#![allow(unreachable_code)]
let err_code = if let Err(err) = &self {
Some(err.code())
} else {
None
};
self.into_result().map_err(|err| {
log::error!("{} failed: {}", description, err);
match self {
winerror::E_OUTOFMEMORY => {
let Some(err_code) = err_code else {
unreachable!()
};
match err_code {
Foundation::E_OUTOFMEMORY => {
#[cfg(feature = "oom_panic")]
panic!("{description} failed: Out of memory");
return crate::DeviceError::OutOfMemory;
}
winerror::DXGI_ERROR_DEVICE_RESET | winerror::DXGI_ERROR_DEVICE_REMOVED => {
Dxgi::DXGI_ERROR_DEVICE_RESET | Dxgi::DXGI_ERROR_DEVICE_REMOVED => {
#[cfg(feature = "device_lost_panic")]
panic!("{description} failed: Device lost ({err})");
}
@ -41,20 +50,7 @@ impl HResult<()> for i32 {
}
}
if self == winerror::E_OUTOFMEMORY {
crate::DeviceError::OutOfMemory
} else {
crate::DeviceError::Lost
}
crate::DeviceError::Lost
})
}
}
impl<T> HResult<T> for (T, i32) {
fn into_result(self) -> Result<T, Cow<'static, str>> {
self.1.into_result().map(|()| self.0)
}
fn into_device_result(self, description: &str) -> Result<T, crate::DeviceError> {
self.1.into_device_result(description).map(|()| self.0)
}
}

View File

@ -1,22 +1,20 @@
#![allow(dead_code)] // IPresentationManager is unused currently
use std::mem;
use winapi::um::{
profileapi::{QueryPerformanceCounter, QueryPerformanceFrequency},
winnt::LARGE_INTEGER,
};
use windows::Win32::System::Performance::{QueryPerformanceCounter, QueryPerformanceFrequency};
pub enum PresentationTimer {
/// DXGI uses QueryPerformanceCounter
/// DXGI uses [`QueryPerformanceCounter()`]
Dxgi {
/// How many ticks of QPC per second
frequency: u64,
},
/// IPresentationManager uses QueryInterruptTimePrecise
/// [`IPresentationManager`] uses [`QueryInterruptTimePrecise()`]
///
/// [`IPresentationManager`]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Graphics/CompositionSwapchain/struct.IPresentationManager.html
/// [`QueryInterruptTimePrecise()`]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/WindowsProgramming/fn.QueryInterruptTimePrecise.html
#[allow(non_snake_case)]
IPresentationManager {
fnQueryInterruptTimePrecise: unsafe extern "system" fn(*mut winapi::ctypes::c_ulonglong),
fnQueryInterruptTimePrecise: unsafe extern "system" fn(*mut u64),
},
}
@ -43,12 +41,13 @@ impl std::fmt::Debug for PresentationTimer {
impl PresentationTimer {
/// Create a presentation timer using QueryPerformanceFrequency (what DXGI uses for presentation times)
pub fn new_dxgi() -> Self {
let mut frequency: LARGE_INTEGER = unsafe { mem::zeroed() };
let success = unsafe { QueryPerformanceFrequency(&mut frequency) };
assert_ne!(success, 0);
let mut frequency = 0;
unsafe { QueryPerformanceFrequency(&mut frequency) }.unwrap();
Self::Dxgi {
frequency: unsafe { *frequency.QuadPart() } as u64,
frequency: frequency
.try_into()
.expect("Frequency should not be negative"),
}
}
@ -59,6 +58,7 @@ impl PresentationTimer {
// We need to load this explicitly, as QueryInterruptTimePrecise is only available on Windows 10+
//
// Docs say it's in kernel32.dll, but it's actually in kernelbase.dll.
// api-ms-win-core-realtime-l1-1-1.dll
let kernelbase =
libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap();
// No concerns about lifetimes here as kernelbase is always there.
@ -73,12 +73,11 @@ impl PresentationTimer {
// Always do u128 math _after_ hitting the timing function.
match *self {
PresentationTimer::Dxgi { frequency } => {
let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() };
let success = unsafe { QueryPerformanceCounter(&mut counter) };
assert_ne!(success, 0);
let mut counter = 0;
unsafe { QueryPerformanceCounter(&mut counter) }.unwrap();
// counter * (1_000_000_000 / freq) but re-ordered to make more precise
(unsafe { *counter.QuadPart() } as u128 * 1_000_000_000) / frequency as u128
(counter as u128 * 1_000_000_000) / frequency as u128
}
PresentationTimer::IPresentationManager {
fnQueryInterruptTimePrecise,

View File

@ -106,7 +106,7 @@ impl Default for RenderDoc {
unsafe { Self::new() }
}
}
/// A implementation specific handle
/// An implementation specific handle
pub type Handle = *mut os::raw::c_void;
impl RenderDoc {

View File

@ -1,15 +1,21 @@
use crate::{
auxil::{self, dxgi::result::HResult as _},
dx12::{shader_compilation, SurfaceTarget},
};
use parking_lot::Mutex;
use std::{mem, ptr, sync::Arc, thread};
use winapi::{
shared::{
dxgi, dxgi1_2, dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, minwindef::DWORD, windef, winerror,
use parking_lot::Mutex;
use windows::{
core::Interface as _,
Win32::{
Graphics::{Direct3D, Direct3D12, Dxgi},
UI::WindowsAndMessaging,
},
um::{d3d12 as d3d12_ty, d3d12sdklayers, winnt, winuser},
Interface,
};
use super::D3D12Lib;
use crate::{
auxil::{
self,
dxgi::{factory::DxgiAdapter, result::HResult},
},
dx12::{shader_compilation, SurfaceTarget},
};
impl Drop for super::Adapter {
@ -30,34 +36,31 @@ impl Drop for super::Adapter {
impl super::Adapter {
pub unsafe fn report_live_objects(&self) {
if let Ok(debug_device) = unsafe {
self.raw
.cast::<d3d12sdklayers::ID3D12DebugDevice>()
.into_result()
} {
if let Ok(debug_device) = self.raw.cast::<Direct3D12::ID3D12DebugDevice>() {
unsafe {
debug_device.ReportLiveDeviceObjects(
d3d12sdklayers::D3D12_RLDO_SUMMARY | d3d12sdklayers::D3D12_RLDO_IGNORE_INTERNAL,
Direct3D12::D3D12_RLDO_SUMMARY | Direct3D12::D3D12_RLDO_IGNORE_INTERNAL,
)
};
}
.unwrap()
}
}
pub fn raw_adapter(&self) -> &d3d12::DxgiAdapter {
pub fn raw_adapter(&self) -> &DxgiAdapter {
&self.raw
}
pub(super) fn expose(
adapter: d3d12::DxgiAdapter,
library: &Arc<d3d12::D3D12Lib>,
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");
match library.create_device(&adapter, d3d12::FeatureLevel::L11_0) {
Ok(pair) => match pair.into_result() {
match library.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) {
Ok(pair) => match pair {
Ok(device) => device,
Err(err) => {
log::warn!("Device creation failed: {}", err);
@ -75,45 +78,42 @@ impl super::Adapter {
// Detect the highest supported feature level.
let d3d_feature_level = [
d3d12::FeatureLevel::L12_1,
d3d12::FeatureLevel::L12_0,
d3d12::FeatureLevel::L11_1,
d3d12::FeatureLevel::L11_0,
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: d3d12_ty::D3D12_FEATURE_DATA_FEATURE_LEVELS =
unsafe { mem::zeroed() };
device_levels.NumFeatureLevels = d3d_feature_level.len() as u32;
device_levels.pFeatureLevelsRequested = d3d_feature_level.as_ptr().cast();
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(
d3d12_ty::D3D12_FEATURE_FEATURE_LEVELS,
ptr::from_mut(&mut device_levels).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FEATURE_LEVELS>() as _,
Direct3D12::D3D12_FEATURE_FEATURE_LEVELS,
<*mut _>::cast(&mut device_levels),
mem::size_of_val(&device_levels) as u32,
)
};
// This cast should never fail because we only requested feature levels that are already in the enum.
let max_feature_level =
d3d12::FeatureLevel::try_from(device_levels.MaxSupportedFeatureLevel)
.expect("Unexpected feature level");
}
.unwrap();
let max_feature_level = device_levels.MaxSupportedFeatureLevel;
// We have found a possible adapter.
// Acquire the device information.
let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
unsafe {
adapter.unwrap_adapter2().GetDesc2(&mut desc);
}
let desc = unsafe { adapter.unwrap_adapter2().GetDesc2() }.unwrap();
let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description);
let mut features_architecture: d3d12_ty::D3D12_FEATURE_DATA_ARCHITECTURE =
unsafe { mem::zeroed() };
assert_eq!(0, unsafe {
let mut features_architecture = Direct3D12::D3D12_FEATURE_DATA_ARCHITECTURE::default();
unsafe {
device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_ARCHITECTURE,
ptr::from_mut(&mut features_architecture).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_ARCHITECTURE>() as _,
Direct3D12::D3D12_FEATURE_ARCHITECTURE,
<*mut _>::cast(&mut features_architecture),
mem::size_of_val(&features_architecture) as u32,
)
});
}
.unwrap();
let mut workarounds = super::Workarounds::default();
@ -122,27 +122,25 @@ impl super::Adapter {
name: device_name,
vendor: desc.VendorId,
device: desc.DeviceId,
device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 {
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 != 0 {
} else if features_architecture.UMA.as_bool() {
wgt::DeviceType::IntegratedGpu
} else {
wgt::DeviceType::DiscreteGpu
},
driver: {
let mut i: winnt::LARGE_INTEGER = unsafe { mem::zeroed() };
if 0 == unsafe {
adapter.CheckInterfaceSupport(&dxgi::IDXGIDevice::uuidof(), &mut i)
} {
let quad_part = unsafe { *i.QuadPart() };
if let Ok(i) = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } {
const MASK: i64 = 0xFFFF;
format!(
"{}.{}.{}.{}",
quad_part >> 48,
(quad_part >> 32) & MASK,
(quad_part >> 16) & MASK,
quad_part & MASK
i >> 48,
(i >> 32) & MASK,
(i >> 16) & MASK,
i & MASK
)
} else {
String::new()
@ -151,84 +149,101 @@ impl super::Adapter {
driver_info: String::new(),
};
let mut options: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS = unsafe { mem::zeroed() };
assert_eq!(0, unsafe {
let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default();
unsafe {
device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS,
ptr::from_mut(&mut options).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS>() as _,
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS,
<*mut _>::cast(&mut options),
mem::size_of_val(&options) as u32,
)
});
}
.unwrap();
let _depth_bounds_test_supported = {
let mut features2: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS2 =
unsafe { mem::zeroed() };
let hr = unsafe {
let mut features2 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS2::default();
unsafe {
device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS2,
ptr::from_mut(&mut features2).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS2>() as _,
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS2,
<*mut _>::cast(&mut features2),
mem::size_of_val(&features2) as u32,
)
};
hr == 0 && features2.DepthBoundsTestSupported != 0
}
.is_ok()
&& features2.DepthBoundsTestSupported.as_bool()
};
let casting_fully_typed_format_supported = {
let mut features3: crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS3 =
unsafe { mem::zeroed() };
let hr = unsafe {
let mut features3 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS3::default();
unsafe {
device.CheckFeatureSupport(
21, // D3D12_FEATURE_D3D12_OPTIONS3
ptr::from_mut(&mut features3).cast(),
mem::size_of::<crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS3>() as _,
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3,
<*mut _>::cast(&mut features3),
mem::size_of_val(&features3) as u32,
)
};
hr == 0 && features3.CastingFullyTypedFormatSupported != 0
}
.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),
mem::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 = [
crate::dx12::types::D3D_SHADER_MODEL_6_7,
crate::dx12::types::D3D_SHADER_MODEL_6_6,
crate::dx12::types::D3D_SHADER_MODEL_6_5,
crate::dx12::types::D3D_SHADER_MODEL_6_4,
crate::dx12::types::D3D_SHADER_MODEL_6_3,
crate::dx12::types::D3D_SHADER_MODEL_6_2,
crate::dx12::types::D3D_SHADER_MODEL_6_1,
crate::dx12::types::D3D_SHADER_MODEL_6_0,
crate::dx12::types::D3D_SHADER_MODEL_5_1,
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,
Direct3D12::D3D_SHADER_MODEL_5_1,
]
.iter();
match loop {
if let Some(&sm) = versions.next() {
let mut sm = crate::dx12::types::D3D12_FEATURE_DATA_SHADER_MODEL {
let mut sm = Direct3D12::D3D12_FEATURE_DATA_SHADER_MODEL {
HighestShaderModel: sm,
};
if 0 == unsafe {
if unsafe {
device.CheckFeatureSupport(
7, // D3D12_FEATURE_SHADER_MODEL
ptr::from_mut(&mut sm).cast(),
mem::size_of::<crate::dx12::types::D3D12_FEATURE_DATA_SHADER_MODEL>()
as _,
Direct3D12::D3D12_FEATURE_SHADER_MODEL,
<*mut _>::cast(&mut sm),
mem::size_of_val(&sm) as u32,
)
} {
}
.is_ok()
{
break sm.HighestShaderModel;
}
} else {
break crate::dx12::types::D3D_SHADER_MODEL_5_1;
break Direct3D12::D3D_SHADER_MODEL_5_1;
}
} {
crate::dx12::types::D3D_SHADER_MODEL_5_1 => naga::back::hlsl::ShaderModel::V5_1,
crate::dx12::types::D3D_SHADER_MODEL_6_0 => naga::back::hlsl::ShaderModel::V6_0,
crate::dx12::types::D3D_SHADER_MODEL_6_1 => naga::back::hlsl::ShaderModel::V6_1,
crate::dx12::types::D3D_SHADER_MODEL_6_2 => naga::back::hlsl::ShaderModel::V6_2,
crate::dx12::types::D3D_SHADER_MODEL_6_3 => naga::back::hlsl::ShaderModel::V6_3,
crate::dx12::types::D3D_SHADER_MODEL_6_4 => naga::back::hlsl::ShaderModel::V6_4,
crate::dx12::types::D3D_SHADER_MODEL_6_5 => naga::back::hlsl::ShaderModel::V6_5,
crate::dx12::types::D3D_SHADER_MODEL_6_6 => naga::back::hlsl::ShaderModel::V6_6,
crate::dx12::types::D3D_SHADER_MODEL_6_7 => naga::back::hlsl::ShaderModel::V6_7,
Direct3D12::D3D_SHADER_MODEL_5_1 => naga::back::hlsl::ShaderModel::V5_1,
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!(),
}
};
@ -236,15 +251,15 @@ impl super::Adapter {
let private_caps = super::PrivateCapabilities {
instance_flags,
heterogeneous_resource_heaps: options.ResourceHeapTier
!= d3d12_ty::D3D12_RESOURCE_HEAP_TIER_1,
memory_architecture: if features_architecture.UMA != 0 {
!= Direct3D12::D3D12_RESOURCE_HEAP_TIER_1,
memory_architecture: if features_architecture.UMA.as_bool() {
super::MemoryArchitecture::Unified {
cache_coherent: features_architecture.CacheCoherentUMA != 0,
cache_coherent: features_architecture.CacheCoherentUMA.as_bool(),
}
} else {
super::MemoryArchitecture::NonUnified
},
heap_create_not_zeroed: false, //TODO: winapi support for Options7
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"),
@ -255,29 +270,29 @@ impl super::Adapter {
let tier3_practical_descriptor_limit = 1 << 20;
let (full_heap_count, uav_count) = match options.ResourceBindingTier {
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => {
Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => {
let uav_count = match max_feature_level {
d3d12::FeatureLevel::L11_0 => 8,
Direct3D::D3D_FEATURE_LEVEL_11_0 => 8,
_ => 64,
};
(
d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
uav_count,
)
}
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_2 => (
d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2,
Direct3D12::D3D12_RESOURCE_BINDING_TIER_2 => (
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2,
64,
),
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_3 => (
Direct3D12::D3D12_RESOURCE_BINDING_TIER_3 => (
tier3_practical_descriptor_limit,
tier3_practical_descriptor_limit,
),
other => {
log::warn!("Unknown resource binding tier {}", other);
log::warn!("Unknown resource binding tier {:?}", other);
(
d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
8,
)
}
@ -313,14 +328,14 @@ impl super::Adapter {
// write the results there, and issue a bunch of copy commands.
//| wgt::Features::PIPELINE_STATISTICS_QUERY
if max_feature_level as u32 >= d3d12::FeatureLevel::L11_1 as u32 {
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
!= d3d12_ty::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
!= Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
);
features.set(
@ -331,60 +346,62 @@ impl super::Adapter {
);
let bgra8unorm_storage_supported = {
let mut bgra8unorm_info: d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT =
unsafe { mem::zeroed() };
bgra8unorm_info.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
let mut bgra8unorm_info = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
..Default::default()
};
let hr = unsafe {
device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT,
ptr::from_mut(&mut bgra8unorm_info).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
<*mut _>::cast(&mut bgra8unorm_info),
mem::size_of_val(&bgra8unorm_info) as u32,
)
};
hr == 0
&& (bgra8unorm_info.Support2 & d3d12_ty::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE != 0)
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: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS1 = unsafe { mem::zeroed() };
let mut features1 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS1::default();
let hr = unsafe {
device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS1,
ptr::from_mut(&mut features1).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS1>() as _,
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS1,
<*mut _>::cast(&mut features1),
mem::size_of_val(&features1) as u32,
)
};
features.set(
wgt::Features::SHADER_INT64,
shader_model >= naga::back::hlsl::ShaderModel::V6_0
&& hr == 0
&& features1.Int64ShaderOps != 0,
&& hr.is_ok()
&& features1.Int64ShaderOps.as_bool(),
);
features.set(
wgt::Features::SUBGROUP,
shader_model >= naga::back::hlsl::ShaderModel::V6_0
&& hr == 0
&& features1.WaveOps != 0,
&& hr.is_ok()
&& features1.WaveOps.as_bool(),
);
let atomic_int64_on_typed_resource_supported = {
let mut features9: crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS9 =
unsafe { mem::zeroed() };
let hr = unsafe {
let mut features9 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS9::default();
unsafe {
device.CheckFeatureSupport(
37, // D3D12_FEATURE_D3D12_OPTIONS9
ptr::from_mut(&mut features9).cast(),
mem::size_of::<crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS9>() as _,
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS9,
<*mut _>::cast(&mut features9),
mem::size_of_val(&features9) as u32,
)
};
hr == 0
&& features9.AtomicInt64OnGroupSharedSupported != 0
&& features9.AtomicInt64OnTypedResourceSupported != 0
}
.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,
@ -424,11 +441,11 @@ impl super::Adapter {
features,
capabilities: crate::Capabilities {
limits: wgt::Limits {
max_texture_dimension_1d: d3d12_ty::D3D12_REQ_TEXTURE1D_U_DIMENSION,
max_texture_dimension_2d: d3d12_ty::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
.min(d3d12_ty::D3D12_REQ_TEXTURECUBE_DIMENSION),
max_texture_dimension_3d: d3d12_ty::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
max_texture_array_layers: d3d12_ty::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
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
@ -437,12 +454,12 @@ impl super::Adapter {
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_ty::D3D12_RESOURCE_BINDING_TIER_1 => 128,
Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => 128,
_ => full_heap_count,
},
max_samplers_per_shader_stage: match options.ResourceBindingTier {
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 16,
_ => d3d12_ty::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE,
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
@ -451,12 +468,12 @@ impl super::Adapter {
max_storage_textures_per_shader_stage: uav_count / 4,
max_uniform_buffers_per_shader_stage: full_heap_count,
max_uniform_buffer_binding_size:
d3d12_ty::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16,
Direct3D12::D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16,
max_storage_buffer_binding_size: auxil::MAX_I32_BINDING_SIZE,
max_vertex_buffers: d3d12_ty::D3D12_VS_INPUT_REGISTER_COUNT
max_vertex_buffers: Direct3D12::D3D12_VS_INPUT_REGISTER_COUNT
.min(crate::MAX_VERTEX_BUFFERS as u32),
max_vertex_attributes: d3d12_ty::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
max_vertex_buffer_array_stride: d3d12_ty::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES,
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
@ -479,19 +496,19 @@ impl super::Adapter {
// 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:
d3d12_ty::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_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:
d3d12_ty::D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP,
max_compute_workgroup_size_x: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_X,
max_compute_workgroup_size_y: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_Y,
max_compute_workgroup_size_z: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_Z,
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:
d3d12_ty::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_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).
@ -500,11 +517,11 @@ impl super::Adapter {
},
alignments: crate::Alignments {
buffer_copy_offset: wgt::BufferSize::new(
d3d12_ty::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64,
Direct3D12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64,
)
.unwrap(),
buffer_copy_pitch: wgt::BufferSize::new(
d3d12_ty::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
)
.unwrap(),
},
@ -523,16 +540,18 @@ impl crate::Adapter for super::Adapter {
limits: &wgt::Limits,
memory_hints: &wgt::MemoryHints,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
let queue = {
let queue: Direct3D12::ID3D12CommandQueue = {
profiling::scope!("ID3D12Device::CreateCommandQueue");
self.device
.create_command_queue(
d3d12::CmdListType::Direct,
d3d12::Priority::Normal,
d3d12::CommandQueueFlags::empty(),
0,
)
.into_device_result("Queue creation")?
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(
@ -577,99 +596,118 @@ impl crate::Adapter for super::Adapter {
}
.unwrap();
let mut data = d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
let mut data = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: raw_format,
Support1: unsafe { mem::zeroed() },
Support2: unsafe { mem::zeroed() },
..Default::default()
};
assert_eq!(winerror::S_OK, unsafe {
unsafe {
self.device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT,
ptr::from_mut(&mut data).cast(),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
<*mut _>::cast(&mut data),
mem::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 = d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
let mut data_srv_uav = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: srv_uav_format,
Support1: d3d12_ty::D3D12_FORMAT_SUPPORT1_NONE,
Support2: d3d12_ty::D3D12_FORMAT_SUPPORT2_NONE,
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
assert_eq!(winerror::S_OK, unsafe {
unsafe {
self.device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT,
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
ptr::addr_of_mut!(data_srv_uav).cast(),
DWORD::try_from(mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT>())
.unwrap(),
mem::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;
let is_texture = data.Support1
& (d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE1D
| d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE2D
| d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE3D
| d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURECUBE)
// 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 & d3d12_ty::D3D12_FORMAT_SUPPORT1_SHADER_LOAD != 0,
is_texture
&& data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD),
);
caps.set(
Tfc::SAMPLED_LINEAR,
data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE != 0,
data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE),
);
caps.set(
Tfc::COLOR_ATTACHMENT,
data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_RENDER_TARGET != 0,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET),
);
caps.set(
Tfc::COLOR_ATTACHMENT_BLEND,
data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_BLENDABLE != 0,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_BLENDABLE),
);
caps.set(
Tfc::DEPTH_STENCIL_ATTACHMENT,
data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL != 0,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL),
);
// UAVs use srv_uav_format
caps.set(
Tfc::STORAGE,
data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW
!= 0,
data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW),
);
caps.set(
Tfc::STORAGE_READ_WRITE,
data_srv_uav.Support2 & d3d12_ty::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD != 0,
data_srv_uav
.Support2
.contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD),
);
// We load via UAV/SRV so use srv_uav_format
let no_msaa_load = caps.contains(Tfc::SAMPLED)
&& data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD == 0;
&& !data_srv_uav
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD);
let no_msaa_target = data.Support1
& (d3d12_ty::D3D12_FORMAT_SUPPORT1_RENDER_TARGET
| d3d12_ty::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)
let no_msaa_target = (data.Support1
& (Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET
| Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL))
.0
!= 0
&& data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET == 0;
&& !data
.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET);
caps.set(
Tfc::MULTISAMPLE_RESOLVE,
data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE != 0,
data.Support1
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE),
);
let mut ms_levels = d3d12_ty::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
let mut ms_levels = Direct3D12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
Format: raw_format,
SampleCount: 0,
Flags: d3d12_ty::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE,
Flags: Direct3D12::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE,
NumQualityLevels: 0,
};
@ -678,11 +716,12 @@ impl crate::Adapter for super::Adapter {
if unsafe {
self.device.CheckFeatureSupport(
d3d12_ty::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
Direct3D12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
<*mut _>::cast(&mut ms_levels),
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS>() as _,
mem::size_of_val(&ms_levels) as u32,
)
} == winerror::S_OK
}
.is_ok()
&& ms_levels.NumQualityLevels != 0
{
caps.set(tfc, !no_msaa_load && !no_msaa_target);
@ -704,8 +743,9 @@ impl crate::Adapter for super::Adapter {
let current_extent = {
match surface.target {
SurfaceTarget::WndHandle(wnd_handle) => {
let mut rect: windef::RECT = unsafe { mem::zeroed() };
if unsafe { winuser::GetClientRect(wnd_handle, &mut rect) } != 0 {
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,

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +1,75 @@
use std::iter;
use winapi::{
shared::minwindef::BOOL,
um::{d3d12 as d3d12_ty, d3dcommon},
};
use windows::Win32::Graphics::{Direct3D, Direct3D12};
pub fn map_buffer_usage_to_resource_flags(
usage: crate::BufferUses,
) -> d3d12_ty::D3D12_RESOURCE_FLAGS {
let mut flags = 0;
) -> Direct3D12::D3D12_RESOURCE_FLAGS {
let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE;
if usage.contains(crate::BufferUses::STORAGE_READ_WRITE) {
flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
flags
}
pub fn map_texture_dimension(dim: wgt::TextureDimension) -> d3d12_ty::D3D12_RESOURCE_DIMENSION {
pub fn map_texture_dimension(dim: wgt::TextureDimension) -> Direct3D12::D3D12_RESOURCE_DIMENSION {
match dim {
wgt::TextureDimension::D1 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE1D,
wgt::TextureDimension::D2 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
wgt::TextureDimension::D3 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE3D,
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,
) -> d3d12_ty::D3D12_RESOURCE_FLAGS {
let mut flags = 0;
) -> Direct3D12::D3D12_RESOURCE_FLAGS {
let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE;
if usage.contains(crate::TextureUses::COLOR_TARGET) {
flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
}
if usage.intersects(
crate::TextureUses::DEPTH_STENCIL_READ | crate::TextureUses::DEPTH_STENCIL_WRITE,
) {
flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
if !usage.contains(crate::TextureUses::RESOURCE) {
flags |= d3d12_ty::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
flags |= Direct3D12::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
}
}
if usage.contains(crate::TextureUses::STORAGE_READ_WRITE) {
flags |= d3d12_ty::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
flags
}
pub fn map_address_mode(mode: wgt::AddressMode) -> d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE {
pub fn map_address_mode(mode: wgt::AddressMode) -> Direct3D12::D3D12_TEXTURE_ADDRESS_MODE {
use wgt::AddressMode as Am;
match mode {
Am::Repeat => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_WRAP,
Am::MirrorRepeat => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
Am::ClampToEdge => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
Am::ClampToBorder => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_BORDER,
//Am::MirrorClamp => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
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) -> d3d12_ty::D3D12_FILTER_TYPE {
pub fn map_filter_mode(mode: wgt::FilterMode) -> Direct3D12::D3D12_FILTER_TYPE {
match mode {
wgt::FilterMode::Nearest => d3d12_ty::D3D12_FILTER_TYPE_POINT,
wgt::FilterMode::Linear => d3d12_ty::D3D12_FILTER_TYPE_LINEAR,
wgt::FilterMode::Nearest => Direct3D12::D3D12_FILTER_TYPE_POINT,
wgt::FilterMode::Linear => Direct3D12::D3D12_FILTER_TYPE_LINEAR,
}
}
pub fn map_comparison(func: wgt::CompareFunction) -> d3d12_ty::D3D12_COMPARISON_FUNC {
pub fn map_comparison(func: wgt::CompareFunction) -> Direct3D12::D3D12_COMPARISON_FUNC {
use wgt::CompareFunction as Cf;
match func {
Cf::Never => d3d12_ty::D3D12_COMPARISON_FUNC_NEVER,
Cf::Less => d3d12_ty::D3D12_COMPARISON_FUNC_LESS,
Cf::LessEqual => d3d12_ty::D3D12_COMPARISON_FUNC_LESS_EQUAL,
Cf::Equal => d3d12_ty::D3D12_COMPARISON_FUNC_EQUAL,
Cf::GreaterEqual => d3d12_ty::D3D12_COMPARISON_FUNC_GREATER_EQUAL,
Cf::Greater => d3d12_ty::D3D12_COMPARISON_FUNC_GREATER,
Cf::NotEqual => d3d12_ty::D3D12_COMPARISON_FUNC_NOT_EQUAL,
Cf::Always => d3d12_ty::D3D12_COMPARISON_FUNC_ALWAYS,
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,
}
}
@ -86,71 +82,67 @@ pub fn map_border_color(border_color: Option<wgt::SamplerBorderColor>) -> [f32;
}
}
pub fn map_visibility(visibility: wgt::ShaderStages) -> d3d12::ShaderVisibility {
pub fn map_visibility(visibility: wgt::ShaderStages) -> Direct3D12::D3D12_SHADER_VISIBILITY {
match visibility {
wgt::ShaderStages::VERTEX => d3d12::ShaderVisibility::VS,
wgt::ShaderStages::FRAGMENT => d3d12::ShaderVisibility::PS,
_ => d3d12::ShaderVisibility::All,
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) -> d3d12::DescriptorRangeType {
pub fn map_binding_type(ty: &wgt::BindingType) -> Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE {
use wgt::BindingType as Bt;
match *ty {
Bt::Sampler { .. } => d3d12::DescriptorRangeType::Sampler,
Bt::Sampler { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
Bt::Buffer {
ty: wgt::BufferBindingType::Uniform,
..
} => d3d12::DescriptorRangeType::CBV,
} => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { read_only: true },
..
}
| Bt::Texture { .. } => d3d12::DescriptorRangeType::SRV,
| Bt::Texture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { read_only: false },
..
}
| Bt::StorageTexture { .. } => d3d12::DescriptorRangeType::UAV,
| Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
Bt::AccelerationStructure => todo!(),
}
}
pub fn map_label(name: &str) -> Vec<u16> {
name.encode_utf16().chain(iter::once(0)).collect()
}
pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> d3d12_ty::D3D12_RESOURCE_STATES {
pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> Direct3D12::D3D12_RESOURCE_STATES {
use crate::BufferUses as Bu;
let mut state = d3d12_ty::D3D12_RESOURCE_STATE_COMMON;
let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON;
if usage.intersects(Bu::COPY_SRC) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_SOURCE;
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE;
}
if usage.intersects(Bu::COPY_DST) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_DEST;
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST;
}
if usage.intersects(Bu::INDEX) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_INDEX_BUFFER;
state |= Direct3D12::D3D12_RESOURCE_STATE_INDEX_BUFFER;
}
if usage.intersects(Bu::VERTEX | Bu::UNIFORM) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
state |= Direct3D12::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
}
if usage.intersects(Bu::STORAGE_READ_WRITE) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
} else if usage.intersects(Bu::STORAGE_READ) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| d3d12_ty::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}
if usage.intersects(Bu::INDIRECT) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
state |= Direct3D12::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
}
state
}
pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_RESOURCE_STATES {
pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> Direct3D12::D3D12_RESOURCE_STATES {
use crate::TextureUses as Tu;
let mut state = d3d12_ty::D3D12_RESOURCE_STATE_COMMON;
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 {
@ -158,26 +150,26 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_
}
if usage.intersects(Tu::COPY_SRC) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_SOURCE;
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE;
}
if usage.intersects(Tu::COPY_DST) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_COPY_DEST;
state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST;
}
if usage.intersects(Tu::RESOURCE) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| d3d12_ty::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}
if usage.intersects(Tu::COLOR_TARGET) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_RENDER_TARGET;
state |= Direct3D12::D3D12_RESOURCE_STATE_RENDER_TARGET;
}
if usage.intersects(Tu::DEPTH_STENCIL_READ) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_DEPTH_READ;
state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_READ;
}
if usage.intersects(Tu::DEPTH_STENCIL_WRITE) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_DEPTH_WRITE;
state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
if usage.intersects(Tu::STORAGE_READ | Tu::STORAGE_READ_WRITE) {
state |= d3d12_ty::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
state
}
@ -185,37 +177,37 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_
pub fn map_topology(
topology: wgt::PrimitiveTopology,
) -> (
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE,
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY,
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY,
) {
match topology {
wgt::PrimitiveTopology::PointList => (
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
),
wgt::PrimitiveTopology::LineList => (
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_LINELIST,
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINELIST,
),
wgt::PrimitiveTopology::LineStrip => (
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
),
wgt::PrimitiveTopology::TriangleList => (
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
),
wgt::PrimitiveTopology::TriangleStrip => (
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
),
}
}
pub fn map_polygon_mode(mode: wgt::PolygonMode) -> d3d12_ty::D3D12_FILL_MODE {
pub fn map_polygon_mode(mode: wgt::PolygonMode) -> Direct3D12::D3D12_FILL_MODE {
match mode {
wgt::PolygonMode::Fill => d3d12_ty::D3D12_FILL_MODE_SOLID,
wgt::PolygonMode::Line => d3d12_ty::D3D12_FILL_MODE_WIREFRAME,
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
@ -227,32 +219,32 @@ pub fn map_polygon_mode(mode: wgt::PolygonMode) -> d3d12_ty::D3D12_FILL_MODE {
/// (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) -> d3d12_ty::D3D12_BLEND {
fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> Direct3D12::D3D12_BLEND {
use wgt::BlendFactor as Bf;
match factor {
Bf::Zero => d3d12_ty::D3D12_BLEND_ZERO,
Bf::One => d3d12_ty::D3D12_BLEND_ONE,
Bf::Src if is_alpha => d3d12_ty::D3D12_BLEND_SRC_ALPHA,
Bf::Src => d3d12_ty::D3D12_BLEND_SRC_COLOR,
Bf::OneMinusSrc if is_alpha => d3d12_ty::D3D12_BLEND_INV_SRC_ALPHA,
Bf::OneMinusSrc => d3d12_ty::D3D12_BLEND_INV_SRC_COLOR,
Bf::Dst if is_alpha => d3d12_ty::D3D12_BLEND_DEST_ALPHA,
Bf::Dst => d3d12_ty::D3D12_BLEND_DEST_COLOR,
Bf::OneMinusDst if is_alpha => d3d12_ty::D3D12_BLEND_INV_DEST_ALPHA,
Bf::OneMinusDst => d3d12_ty::D3D12_BLEND_INV_DEST_COLOR,
Bf::SrcAlpha => d3d12_ty::D3D12_BLEND_SRC_ALPHA,
Bf::OneMinusSrcAlpha => d3d12_ty::D3D12_BLEND_INV_SRC_ALPHA,
Bf::DstAlpha => d3d12_ty::D3D12_BLEND_DEST_ALPHA,
Bf::OneMinusDstAlpha => d3d12_ty::D3D12_BLEND_INV_DEST_ALPHA,
Bf::Constant => d3d12_ty::D3D12_BLEND_BLEND_FACTOR,
Bf::OneMinusConstant => d3d12_ty::D3D12_BLEND_INV_BLEND_FACTOR,
Bf::SrcAlphaSaturated => d3d12_ty::D3D12_BLEND_SRC_ALPHA_SAT,
Bf::Src1 if is_alpha => d3d12_ty::D3D12_BLEND_SRC1_ALPHA,
Bf::Src1 => d3d12_ty::D3D12_BLEND_SRC1_COLOR,
Bf::OneMinusSrc1 if is_alpha => d3d12_ty::D3D12_BLEND_INV_SRC1_ALPHA,
Bf::OneMinusSrc1 => d3d12_ty::D3D12_BLEND_INV_SRC1_COLOR,
Bf::Src1Alpha => d3d12_ty::D3D12_BLEND_SRC1_ALPHA,
Bf::OneMinusSrc1Alpha => d3d12_ty::D3D12_BLEND_INV_SRC1_ALPHA,
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,
}
}
@ -260,16 +252,16 @@ fn map_blend_component(
component: &wgt::BlendComponent,
is_alpha: bool,
) -> (
d3d12_ty::D3D12_BLEND_OP,
d3d12_ty::D3D12_BLEND,
d3d12_ty::D3D12_BLEND,
Direct3D12::D3D12_BLEND_OP,
Direct3D12::D3D12_BLEND,
Direct3D12::D3D12_BLEND,
) {
let raw_op = match component.operation {
wgt::BlendOperation::Add => d3d12_ty::D3D12_BLEND_OP_ADD,
wgt::BlendOperation::Subtract => d3d12_ty::D3D12_BLEND_OP_SUBTRACT,
wgt::BlendOperation::ReverseSubtract => d3d12_ty::D3D12_BLEND_OP_REV_SUBTRACT,
wgt::BlendOperation::Min => d3d12_ty::D3D12_BLEND_OP_MIN,
wgt::BlendOperation::Max => d3d12_ty::D3D12_BLEND_OP_MAX,
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);
@ -278,21 +270,22 @@ fn map_blend_component(
pub fn map_render_targets(
color_targets: &[Option<wgt::ColorTargetState>],
) -> [d3d12_ty::D3D12_RENDER_TARGET_BLEND_DESC;
d3d12_ty::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] {
let dummy_target = d3d12_ty::D3D12_RENDER_TARGET_BLEND_DESC {
BlendEnable: 0,
LogicOpEnable: 0,
SrcBlend: d3d12_ty::D3D12_BLEND_ZERO,
DestBlend: d3d12_ty::D3D12_BLEND_ZERO,
BlendOp: d3d12_ty::D3D12_BLEND_OP_ADD,
SrcBlendAlpha: d3d12_ty::D3D12_BLEND_ZERO,
DestBlendAlpha: d3d12_ty::D3D12_BLEND_ZERO,
BlendOpAlpha: d3d12_ty::D3D12_BLEND_OP_ADD,
LogicOp: d3d12_ty::D3D12_LOGIC_OP_CLEAR,
) -> [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; d3d12_ty::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
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() {
@ -300,7 +293,7 @@ pub fn map_render_targets(
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 = 1;
raw.BlendEnable = true.into();
raw.BlendOp = color_op;
raw.SrcBlend = color_src;
raw.DestBlend = color_dst;
@ -314,22 +307,22 @@ pub fn map_render_targets(
raw_targets
}
fn map_stencil_op(op: wgt::StencilOperation) -> d3d12_ty::D3D12_STENCIL_OP {
fn map_stencil_op(op: wgt::StencilOperation) -> Direct3D12::D3D12_STENCIL_OP {
use wgt::StencilOperation as So;
match op {
So::Keep => d3d12_ty::D3D12_STENCIL_OP_KEEP,
So::Zero => d3d12_ty::D3D12_STENCIL_OP_ZERO,
So::Replace => d3d12_ty::D3D12_STENCIL_OP_REPLACE,
So::IncrementClamp => d3d12_ty::D3D12_STENCIL_OP_INCR_SAT,
So::IncrementWrap => d3d12_ty::D3D12_STENCIL_OP_INCR,
So::DecrementClamp => d3d12_ty::D3D12_STENCIL_OP_DECR_SAT,
So::DecrementWrap => d3d12_ty::D3D12_STENCIL_OP_DECR,
So::Invert => d3d12_ty::D3D12_STENCIL_OP_INVERT,
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) -> d3d12_ty::D3D12_DEPTH_STENCILOP_DESC {
d3d12_ty::D3D12_DEPTH_STENCILOP_DESC {
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),
@ -337,16 +330,16 @@ fn map_stencil_face(face: &wgt::StencilFaceState) -> d3d12_ty::D3D12_DEPTH_STENC
}
}
pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> d3d12_ty::D3D12_DEPTH_STENCIL_DESC {
d3d12_ty::D3D12_DEPTH_STENCIL_DESC {
DepthEnable: BOOL::from(ds.is_depth_enabled()),
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 {
d3d12_ty::D3D12_DEPTH_WRITE_MASK_ALL
Direct3D12::D3D12_DEPTH_WRITE_MASK_ALL
} else {
d3d12_ty::D3D12_DEPTH_WRITE_MASK_ZERO
Direct3D12::D3D12_DEPTH_WRITE_MASK_ZERO
},
DepthFunc: map_comparison(ds.depth_compare),
StencilEnable: BOOL::from(ds.stencil.is_enabled()),
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),

View File

@ -1,16 +1,18 @@
use super::null_comptr_check;
use crate::auxil::dxgi::result::HResult as _;
use std::fmt;
use bit_set::BitSet;
use parking_lot::Mutex;
use range_alloc::RangeAllocator;
use std::fmt;
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: d3d12::CpuDescriptor,
pub gpu: d3d12::GpuDescriptor,
cpu: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
pub gpu: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE,
/// How large the block allocated to this handle is.
count: u64,
}
@ -28,8 +30,8 @@ impl fmt::Debug for DualHandle {
type DescriptorIndex = u64;
pub(super) struct GeneralHeap {
pub raw: d3d12::DescriptorHeap,
ty: d3d12::DescriptorHeapType,
pub raw: Direct3D12::ID3D12DescriptorHeap,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
handle_size: u64,
total_handles: u64,
start: DualHandle,
@ -38,32 +40,30 @@ pub(super) struct GeneralHeap {
impl GeneralHeap {
pub(super) fn new(
device: d3d12::Device,
ty: d3d12::DescriptorHeapType,
device: &Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
total_handles: u64,
) -> Result<Self, crate::DeviceError> {
let raw = {
profiling::scope!("ID3D12Device::CreateDescriptorHeap");
device
.create_descriptor_heap(
total_handles as u32,
ty,
d3d12::DescriptorHeapFlags::SHADER_VISIBLE,
0,
)
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")?
};
null_comptr_check(&raw)?;
Ok(Self {
raw: raw.clone(),
ty,
handle_size: device.get_descriptor_increment_size(ty) as u64,
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as u64,
total_handles,
start: DualHandle {
cpu: raw.start_cpu_descriptor(),
gpu: raw.start_gpu_descriptor(),
cpu: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
gpu: unsafe { raw.GetGPUDescriptorHandleForHeapStart() },
count: 0,
},
ranges: Mutex::new(RangeAllocator::new(0..total_handles)),
@ -79,14 +79,14 @@ impl GeneralHeap {
}
}
fn cpu_descriptor_at(&self, index: u64) -> d3d12::CpuDescriptor {
d3d12::CpuDescriptor {
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) -> d3d12::GpuDescriptor {
d3d12::GpuDescriptor {
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,
}
}
@ -109,41 +109,42 @@ impl GeneralHeap {
/// Fixed-size free-list allocator for CPU descriptors.
struct FixedSizeHeap {
_raw: d3d12::DescriptorHeap,
_raw: Direct3D12::ID3D12DescriptorHeap,
/// Bit flag representation of available handles in the heap.
///
/// 0 - Occupied
/// 1 - free
availability: u64,
handle_size: usize,
start: d3d12::CpuDescriptor,
start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
}
impl FixedSizeHeap {
fn new(
device: &d3d12::Device,
ty: d3d12::DescriptorHeapType,
device: &Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
) -> Result<Self, crate::DeviceError> {
let heap = device
.create_descriptor_heap(
HEAP_SIZE_FIXED as _,
ty,
d3d12::DescriptorHeapFlags::empty(),
0,
)
.into_device_result("Descriptor heap creation")?;
null_comptr_check(&heap)?;
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: device.get_descriptor_increment_size(ty) as _,
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as usize,
availability: !0, // all free!
start: heap.start_cpu_descriptor(),
start: unsafe { heap.GetCPUDescriptorHandleForHeapStart() },
_raw: heap,
})
}
fn alloc_handle(&mut self) -> Result<d3d12::CpuDescriptor, crate::DeviceError> {
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 {
@ -153,12 +154,12 @@ impl FixedSizeHeap {
// Set the slot as occupied.
self.availability ^= 1 << slot;
Ok(d3d12::CpuDescriptor {
Ok(Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: self.start.ptr + self.handle_size * slot,
})
}
fn free_handle(&mut self, handle: d3d12::CpuDescriptor) {
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);
@ -172,7 +173,7 @@ impl FixedSizeHeap {
#[derive(Clone, Copy)]
pub(super) struct Handle {
pub raw: d3d12::CpuDescriptor,
pub raw: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
heap_index: usize,
}
@ -186,14 +187,17 @@ impl fmt::Debug for Handle {
}
pub(super) struct CpuPool {
device: d3d12::Device,
ty: d3d12::DescriptorHeapType,
device: Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
heaps: Vec<FixedSizeHeap>,
available_heap_indices: BitSet,
}
impl CpuPool {
pub(super) fn new(device: d3d12::Device, ty: d3d12::DescriptorHeapType) -> Self {
pub(super) fn new(
device: Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
) -> Self {
Self {
device,
ty,
@ -234,13 +238,13 @@ impl CpuPool {
}
pub(super) struct CpuHeapInner {
pub _raw: d3d12::DescriptorHeap,
pub stage: Vec<d3d12::CpuDescriptor>,
pub _raw: Direct3D12::ID3D12DescriptorHeap,
pub stage: Vec<Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE>,
}
pub(super) struct CpuHeap {
pub inner: Mutex<CpuHeapInner>,
start: d3d12::CpuDescriptor,
start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
handle_size: u32,
total: u32,
}
@ -250,30 +254,33 @@ unsafe impl Sync for CpuHeap {}
impl CpuHeap {
pub(super) fn new(
device: d3d12::Device,
ty: d3d12::DescriptorHeapType,
device: &Direct3D12::ID3D12Device,
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
total: u32,
) -> Result<Self, crate::DeviceError> {
let handle_size = device.get_descriptor_increment_size(ty);
let raw = device
.create_descriptor_heap(total, ty, d3d12::DescriptorHeapFlags::empty(), 0)
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")?;
null_comptr_check(&raw)?;
Ok(Self {
inner: Mutex::new(CpuHeapInner {
_raw: raw.clone(),
stage: Vec::new(),
}),
start: raw.start_cpu_descriptor(),
start: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
handle_size,
total,
})
}
pub(super) fn at(&self, index: u32) -> d3d12::CpuDescriptor {
d3d12::CpuDescriptor {
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,
}
}
@ -290,7 +297,7 @@ impl fmt::Debug for CpuHeap {
}
pub(super) unsafe fn upload(
device: d3d12::Device,
device: Direct3D12::ID3D12Device,
src: &CpuHeapInner,
dst: &GeneralHeap,
dummy_copy_counts: &[u32],
@ -301,11 +308,11 @@ pub(super) unsafe fn upload(
device.CopyDescriptors(
1,
&dst.cpu_descriptor_at(index),
&count,
Some(&count),
count,
src.stage.as_ptr(),
dummy_copy_counts.as_ptr(),
dst.ty as u32,
Some(dummy_copy_counts.as_ptr()),
dst.ty,
)
};
Ok(dst.at(index, count as u64))

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,19 @@
use std::sync::Arc;
use parking_lot::RwLock;
use winapi::shared::{dxgi1_5, minwindef};
use windows::{
core::Interface as _,
Win32::{
Foundation,
Graphics::{Direct3D12, Dxgi},
},
};
use super::SurfaceTarget;
use crate::auxil::{self, dxgi::result::HResult as _};
use std::{mem, sync::Arc};
use crate::{
auxil::{self, dxgi::result::HResult as _},
dx12::D3D12Lib,
};
impl Drop for super::Instance {
fn drop(&mut self) {
@ -18,7 +28,7 @@ impl crate::Instance for super::Instance {
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
profiling::scope!("Init DX12 Backend");
let lib_main = d3d12::D3D12Lib::new().map_err(|e| {
let lib_main = D3D12Lib::new().map_err(|e| {
crate::InstanceError::with_source(String::from("failed to load d3d12.dll"), e)
})?;
@ -27,18 +37,21 @@ impl crate::Instance for super::Instance {
.intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
// Enable debug layer
match lib_main.get_debug_interface() {
Ok(pair) => match pair.into_result() {
match lib_main.debug_interface() {
Ok(pair) => match pair {
Ok(debug_controller) => {
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
debug_controller.enable_layer();
unsafe { debug_controller.EnableDebugLayer() }
}
if desc
.flags
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
#[allow(clippy::collapsible_if)]
if !debug_controller.enable_gpu_based_validation() {
if let Ok(debug1) = debug_controller.cast::<Direct3D12::ID3D12Debug1>()
{
unsafe { debug1.SetEnableGPUBasedValidation(true) }
} else {
log::warn!("Failed to enable GPU-based validation");
}
}
@ -61,7 +74,7 @@ impl crate::Instance for super::Instance {
// Create IDXGIFactoryMedia
let factory_media = match lib_dxgi.create_factory_media() {
Ok(pair) => match pair.into_result() {
Ok(pair) => match pair {
Ok(factory_media) => Some(factory_media),
Err(err) => {
log::error!("Failed to create IDXGIFactoryMedia: {}", err);
@ -76,12 +89,12 @@ impl crate::Instance for super::Instance {
let mut supports_allow_tearing = false;
if let Some(factory5) = factory.as_factory5() {
let mut allow_tearing: minwindef::BOOL = minwindef::FALSE;
let mut allow_tearing = Foundation::FALSE;
let hr = unsafe {
factory5.CheckFeatureSupport(
dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
std::ptr::from_mut(&mut allow_tearing).cast(),
mem::size_of::<minwindef::BOOL>() as _,
Dxgi::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
<*mut _>::cast(&mut allow_tearing),
std::mem::size_of_val(&allow_tearing) as u32,
)
};
@ -133,7 +146,8 @@ impl crate::Instance for super::Instance {
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
target: SurfaceTarget::WndHandle(handle.hwnd.get() as *mut _),
// 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),
}),

View File

@ -44,16 +44,258 @@ mod suballocation;
mod types;
mod view;
use crate::auxil::{self, dxgi::result::HResult as _};
use std::{ffi, fmt, mem, num::NonZeroU32, ops::Deref, sync::Arc};
use arrayvec::ArrayVec;
use parking_lot::{Mutex, RwLock};
use std::{ffi, fmt, mem, num::NonZeroU32, sync::Arc};
use winapi::{
shared::{dxgi, dxgi1_4, dxgitype, windef, winerror},
um::{d3d12 as d3d12_ty, dcomp, synchapi, winbase, winnt},
Interface as _,
use windows::{
core::{Interface, Param as _},
Win32::{
Foundation,
Graphics::{Direct3D, Direct3D12, DirectComposition, Dxgi},
System::Threading,
},
};
use windows_core::Free;
use crate::auxil::{
self,
dxgi::{
factory::{DxgiAdapter, DxgiFactory},
result::HResult,
},
};
#[derive(Debug)]
struct D3D12Lib {
lib: libloading::Library,
}
impl D3D12Lib {
fn new() -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) }
}
fn create_device(
&self,
adapter: &DxgiAdapter,
feature_level: Direct3D::D3D_FEATURE_LEVEL,
) -> Result<windows_core::Result<Direct3D12::ID3D12Device>, libloading::Error> {
// Calls windows::Win32::Graphics::Direct3D12::D3D12CreateDevice on d3d12.dll
type Fun = extern "system" fn(
padapter: *mut core::ffi::c_void,
minimumfeaturelevel: Direct3D::D3D_FEATURE_LEVEL,
riid: *const windows_core::GUID,
ppdevice: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12CreateDevice") }?;
let mut result__ = None;
Ok((func)(
unsafe { adapter.param().abi() },
feature_level,
// TODO: Generic?
&Direct3D12::ID3D12Device::IID,
<*mut _>::cast(&mut result__),
)
.map(|| result__.expect("D3D12CreateDevice succeeded but result is NULL?")))
}
fn serialize_root_signature(
&self,
version: Direct3D12::D3D_ROOT_SIGNATURE_VERSION,
parameters: &[Direct3D12::D3D12_ROOT_PARAMETER],
static_samplers: &[Direct3D12::D3D12_STATIC_SAMPLER_DESC],
flags: Direct3D12::D3D12_ROOT_SIGNATURE_FLAGS,
) -> Result<D3DBlob, crate::DeviceError> {
// Calls windows::Win32::Graphics::Direct3D12::D3D12SerializeRootSignature on d3d12.dll
type Fun = extern "system" fn(
prootsignature: *const Direct3D12::D3D12_ROOT_SIGNATURE_DESC,
version: Direct3D12::D3D_ROOT_SIGNATURE_VERSION,
ppblob: *mut *mut core::ffi::c_void,
pperrorblob: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12SerializeRootSignature") }
.map_err(|e| {
log::error!("Unable to find serialization function: {:?}", e);
crate::DeviceError::Lost
})?;
let desc = Direct3D12::D3D12_ROOT_SIGNATURE_DESC {
NumParameters: parameters.len() as _,
pParameters: parameters.as_ptr(),
NumStaticSamplers: static_samplers.len() as _,
pStaticSamplers: static_samplers.as_ptr(),
Flags: flags,
};
let mut blob = None;
let mut error = None::<Direct3D::ID3DBlob>;
(func)(
&desc,
version,
<*mut _>::cast(&mut blob),
<*mut _>::cast(&mut error),
)
.ok()
// TODO: If there's a HRESULT, error may still be non-null and
// contain info.
.into_device_result("Root signature serialization")?;
if let Some(error) = error {
let error = D3DBlob(error);
log::error!(
"Root signature serialization error: {:?}",
unsafe { error.as_c_str() }.unwrap().to_str().unwrap()
);
return Err(crate::DeviceError::Lost);
}
Ok(D3DBlob(blob.expect(
"D3D12SerializeRootSignature succeeded but result is NULL?",
)))
}
fn debug_interface(
&self,
) -> Result<windows::core::Result<Direct3D12::ID3D12Debug>, libloading::Error> {
// Calls windows::Win32::Graphics::Direct3D12::D3D12GetDebugInterface on d3d12.dll
type Fun = extern "system" fn(
riid: *const windows_core::GUID,
ppvdebug: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12GetDebugInterface") }?;
let mut result__ = core::ptr::null_mut();
Ok((func)(&Direct3D12::ID3D12Debug::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
}
}
#[derive(Debug)]
pub(super) struct DxgiLib {
lib: libloading::Library,
}
impl DxgiLib {
pub fn new() -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) }
}
pub fn debug_interface1(
&self,
) -> Result<windows::core::Result<Dxgi::IDXGIInfoQueue>, libloading::Error> {
// Calls windows::Win32::Graphics::Dxgi::DXGIGetDebugInterface1 on dxgi.dll
type Fun = extern "system" fn(
flags: u32,
riid: *const windows_core::GUID,
pdebug: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"DXGIGetDebugInterface1") }?;
let mut result__ = core::ptr::null_mut();
Ok((func)(0, &Dxgi::IDXGIInfoQueue::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
}
pub fn create_factory1(
&self,
) -> Result<windows::core::Result<Dxgi::IDXGIFactory1>, libloading::Error> {
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll
type Fun = extern "system" fn(
riid: *const windows_core::GUID,
ppfactory: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1") }?;
let mut result__ = core::ptr::null_mut();
Ok((func)(&Dxgi::IDXGIFactory1::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
}
pub fn create_factory2(
&self,
factory_flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS,
) -> Result<windows::core::Result<Dxgi::IDXGIFactory4>, libloading::Error> {
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory2 on dxgi.dll
type Fun = extern "system" fn(
flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS,
riid: *const windows_core::GUID,
ppfactory: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory2") }?;
let mut result__ = core::ptr::null_mut();
Ok(
(func)(factory_flags, &Dxgi::IDXGIFactory4::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }),
)
}
pub fn create_factory_media(
&self,
) -> Result<windows::core::Result<Dxgi::IDXGIFactoryMedia>, libloading::Error> {
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll
type Fun = extern "system" fn(
riid: *const windows_core::GUID,
ppfactory: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1") }?;
let mut result__ = core::ptr::null_mut();
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nn-dxgi1_3-idxgifactorymedia
Ok((func)(&Dxgi::IDXGIFactoryMedia::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
}
}
/// Create a temporary "owned" copy inside a [`mem::ManuallyDrop`] without increasing the refcount or
/// moving away the source variable.
///
/// This is a common pattern when needing to pass interface pointers ("borrows") into Windows
/// structs. Moving/cloning ownership is impossible/inconvenient because:
///
/// - The caller does _not_ assume ownership (and decrement the refcount at a later time);
/// - Unnecessarily increasing and decrementing the refcount;
/// - [`Drop`] destructors cannot run inside `union` structures (when the created structure is
/// implicitly dropped after a call).
///
/// See also <https://github.com/microsoft/windows-rs/pull/2361#discussion_r1150799401> and
/// <https://github.com/microsoft/windows-rs/issues/2386>.
///
/// # Safety
/// Performs a [`mem::transmute_copy()`] on a refcounted [`Interface`] type. The returned
/// [`mem::ManuallyDrop`] should _not_ be dropped.
pub unsafe fn borrow_interface_temporarily<I: Interface>(src: &I) -> mem::ManuallyDrop<Option<I>> {
unsafe { mem::transmute_copy(src) }
}
/// See [`borrow_interface_temporarily()`]
pub unsafe fn borrow_optional_interface_temporarily<I: Interface>(
src: &Option<I>,
) -> mem::ManuallyDrop<Option<I>> {
unsafe { mem::transmute_copy(src) }
}
struct D3DBlob(Direct3D::ID3DBlob);
impl Deref for D3DBlob {
type Target = Direct3D::ID3DBlob;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl D3DBlob {
unsafe fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.GetBufferPointer().cast(), self.GetBufferSize()) }
}
unsafe fn as_c_str(&self) -> Result<&ffi::CStr, ffi::FromBytesUntilNulError> {
ffi::CStr::from_bytes_until_nul(unsafe { self.as_slice() })
}
}
#[derive(Clone, Debug)]
pub struct Api;
@ -116,24 +358,23 @@ const MAX_ROOT_ELEMENTS: usize = 64;
const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10;
pub struct Instance {
factory: d3d12::DxgiFactory,
factory_media: Option<d3d12::FactoryMedia>,
library: Arc<d3d12::D3D12Lib>,
factory: DxgiFactory,
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
library: Arc<D3D12Lib>,
supports_allow_tearing: bool,
_lib_dxgi: d3d12::DxgiLib,
_lib_dxgi: DxgiLib,
flags: wgt::InstanceFlags,
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
}
impl Instance {
pub unsafe fn create_surface_from_visual(
&self,
visual: *mut dcomp::IDCompositionVisual,
) -> Surface {
pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface {
let visual = unsafe { DirectComposition::IDCompositionVisual::from_raw_borrowed(&visual) }
.expect("COM pointer should not be NULL");
Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
target: SurfaceTarget::Visual(unsafe { d3d12::ComPtr::from_raw(visual) }),
target: SurfaceTarget::Visual(visual.to_owned()),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: RwLock::new(None),
}
@ -141,8 +382,12 @@ impl Instance {
pub unsafe fn create_surface_from_surface_handle(
&self,
surface_handle: winnt::HANDLE,
surface_handle: *mut std::ffi::c_void,
) -> Surface {
// TODO: We're not given ownership, so we shouldn't call HANDLE::free(). This puts an extra burden on the caller to keep it alive.
// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle could help us, even though DirectComposition is not in the list?
// Or we make all these types owned, require an ownership transition, and replace SurfaceTargetUnsafe with SurfaceTarget.
let surface_handle = Foundation::HANDLE(surface_handle);
Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
@ -154,14 +399,15 @@ impl Instance {
pub unsafe fn create_surface_from_swap_chain_panel(
&self,
swap_chain_panel: *mut types::ISwapChainPanelNative,
swap_chain_panel: *mut std::ffi::c_void,
) -> Surface {
let swap_chain_panel =
unsafe { types::ISwapChainPanelNative::from_raw_borrowed(&swap_chain_panel) }
.expect("COM pointer should not be NULL");
Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
target: SurfaceTarget::SwapChainPanel(unsafe {
d3d12::ComPtr::from_raw(swap_chain_panel)
}),
target: SurfaceTarget::SwapChainPanel(swap_chain_panel.to_owned()),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: RwLock::new(None),
}
@ -172,11 +418,13 @@ unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}
struct SwapChain {
raw: d3d12::ComPtr<dxgi1_4::IDXGISwapChain3>,
// TODO: Drop order frees the SWC before the raw image pointers...?
raw: Dxgi::IDXGISwapChain3,
// need to associate raw image pointers with the swapchain so they can be properly released
// when the swapchain is destroyed
resources: Vec<d3d12::Resource>,
waitable: winnt::HANDLE,
resources: Vec<Direct3D12::ID3D12Resource>,
/// Handle is freed in [`Self::release_resources()`]
waitable: Foundation::HANDLE,
acquired_count: usize,
present_mode: wgt::PresentMode,
format: wgt::TextureFormat,
@ -184,15 +432,17 @@ struct SwapChain {
}
enum SurfaceTarget {
WndHandle(windef::HWND),
Visual(d3d12::ComPtr<dcomp::IDCompositionVisual>),
SurfaceHandle(winnt::HANDLE),
SwapChainPanel(d3d12::ComPtr<types::ISwapChainPanelNative>),
/// Borrowed, lifetime externally managed
WndHandle(Foundation::HWND),
Visual(DirectComposition::IDCompositionVisual),
/// Borrowed, lifetime externally managed
SurfaceHandle(Foundation::HANDLE),
SwapChainPanel(types::ISwapChainPanelNative),
}
pub struct Surface {
factory: d3d12::DxgiFactory,
factory_media: Option<d3d12::FactoryMedia>,
factory: DxgiFactory,
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
target: SurfaceTarget,
supports_allow_tearing: bool,
swap_chain: RwLock<Option<SwapChain>>,
@ -216,7 +466,6 @@ struct PrivateCapabilities {
#[allow(unused)]
heterogeneous_resource_heaps: bool,
memory_architecture: MemoryArchitecture,
#[allow(unused)] // TODO: Exists until windows-rs is standard, then it can probably be removed?
heap_create_not_zeroed: bool,
casting_fully_typed_format_supported: bool,
suballocation_supported: bool,
@ -231,12 +480,12 @@ struct Workarounds {
}
pub struct Adapter {
raw: d3d12::DxgiAdapter,
device: d3d12::Device,
library: Arc<d3d12::D3D12Lib>,
raw: DxgiAdapter,
device: Direct3D12::ID3D12Device,
library: Arc<D3D12Lib>,
private_caps: PrivateCapabilities,
presentation_timer: auxil::dxgi::time::PresentationTimer,
//Note: this isn't used right now, but we'll need it later.
// Note: this isn't used right now, but we'll need it later.
#[allow(unused)]
workarounds: Workarounds,
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
@ -245,20 +494,36 @@ pub struct Adapter {
unsafe impl Send for Adapter {}
unsafe impl Sync for Adapter {}
struct Event(pub Foundation::HANDLE);
impl Event {
pub fn create(manual_reset: bool, initial_state: bool) -> Result<Self, crate::DeviceError> {
Ok(Self(
unsafe { Threading::CreateEventA(None, manual_reset, initial_state, None) }
.into_device_result("CreateEventA")?,
))
}
}
impl Drop for Event {
fn drop(&mut self) {
unsafe { Foundation::HANDLE::free(&mut self.0) }
}
}
/// Helper structure for waiting for GPU.
struct Idler {
fence: d3d12::Fence,
event: d3d12::Event,
fence: Direct3D12::ID3D12Fence,
event: Event,
}
struct CommandSignatures {
draw: d3d12::CommandSignature,
draw_indexed: d3d12::CommandSignature,
dispatch: d3d12::CommandSignature,
draw: Direct3D12::ID3D12CommandSignature,
draw_indexed: Direct3D12::ID3D12CommandSignature,
dispatch: Direct3D12::ID3D12CommandSignature,
}
struct DeviceShared {
zero_buffer: d3d12::Resource,
zero_buffer: Direct3D12::ID3D12Resource,
cmd_signatures: CommandSignatures,
heap_views: descriptor::GeneralHeap,
heap_samplers: descriptor::GeneralHeap,
@ -268,8 +533,8 @@ unsafe impl Send for DeviceShared {}
unsafe impl Sync for DeviceShared {}
pub struct Device {
raw: d3d12::Device,
present_queue: d3d12::CommandQueue,
raw: Direct3D12::ID3D12Device,
present_queue: Direct3D12::ID3D12CommandQueue,
idler: Idler,
private_caps: PrivateCapabilities,
shared: Arc<DeviceShared>,
@ -279,11 +544,11 @@ pub struct Device {
srv_uav_pool: Mutex<descriptor::CpuPool>,
sampler_pool: Mutex<descriptor::CpuPool>,
// library
library: Arc<d3d12::D3D12Lib>,
library: Arc<D3D12Lib>,
#[cfg(feature = "renderdoc")]
render_doc: auxil::renderdoc::RenderDoc,
null_rtv_handle: descriptor::Handle,
mem_allocator: Option<Mutex<suballocation::GpuAllocatorWrapper>>,
mem_allocator: Mutex<suballocation::GpuAllocatorWrapper>,
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
counters: wgt::HalCounters,
}
@ -292,8 +557,8 @@ unsafe impl Send for Device {}
unsafe impl Sync for Device {}
pub struct Queue {
raw: d3d12::CommandQueue,
temp_lists: Mutex<Vec<d3d12::CommandList>>,
raw: Direct3D12::ID3D12CommandQueue,
temp_lists: Mutex<Vec<Option<Direct3D12::ID3D12CommandList>>>,
}
unsafe impl Send for Queue {}
@ -302,7 +567,7 @@ unsafe impl Sync for Queue {}
#[derive(Default)]
struct Temp {
marker: Vec<u16>,
barriers: Vec<d3d12_ty::D3D12_RESOURCE_BARRIER>,
barriers: Vec<Direct3D12::D3D12_RESOURCE_BARRIER>,
}
impl Temp {
@ -313,9 +578,9 @@ impl Temp {
}
struct PassResolve {
src: (d3d12::Resource, u32),
dst: (d3d12::Resource, u32),
format: d3d12::Format,
src: (Direct3D12::ID3D12Resource, u32),
dst: (Direct3D12::ID3D12Resource, u32),
format: Dxgi::Common::DXGI_FORMAT,
}
#[derive(Clone, Copy)]
@ -328,11 +593,11 @@ enum RootElement {
other: u32,
},
/// Descriptor table.
Table(d3d12::GpuDescriptor),
Table(Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE),
/// Descriptor for a buffer that has dynamic offset.
DynamicOffsetBuffer {
kind: BufferViewKind,
address: d3d12::GpuAddress,
address: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE,
},
}
@ -350,7 +615,7 @@ struct PassState {
root_elements: [RootElement; MAX_ROOT_ELEMENTS],
constant_data: [u32; MAX_ROOT_ELEMENTS],
dirty_root_elements: u64,
vertex_buffers: [d3d12_ty::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS],
vertex_buffers: [Direct3D12::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS],
dirty_vertex_buffers: usize,
kind: PassKind,
}
@ -366,7 +631,7 @@ impl PassState {
has_label: false,
resolves: ArrayVec::new(),
layout: PipelineLayoutShared {
signature: d3d12::RootSignature::null(),
signature: None,
total_root_elements: 0,
special_constants_root_index: None,
root_constant_info: None,
@ -374,7 +639,7 @@ impl PassState {
root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS],
constant_data: [0; MAX_ROOT_ELEMENTS],
dirty_root_elements: 0,
vertex_buffers: [unsafe { mem::zeroed() }; crate::MAX_VERTEX_BUFFERS],
vertex_buffers: [Default::default(); crate::MAX_VERTEX_BUFFERS],
dirty_vertex_buffers: 0,
kind: PassKind::Transfer,
}
@ -387,18 +652,18 @@ impl PassState {
}
pub struct CommandEncoder {
allocator: d3d12::CommandAllocator,
device: d3d12::Device,
allocator: Direct3D12::ID3D12CommandAllocator,
device: Direct3D12::ID3D12Device,
shared: Arc<DeviceShared>,
null_rtv_handle: descriptor::Handle,
list: Option<d3d12::GraphicsCommandList>,
free_lists: Vec<d3d12::GraphicsCommandList>,
list: Option<Direct3D12::ID3D12GraphicsCommandList>,
free_lists: Vec<Direct3D12::ID3D12GraphicsCommandList>,
pass: PassState,
temp: Temp,
/// If set, the end of the next render/compute pass will write a timestamp at
/// the given pool & location.
end_of_pass_timer_query: Option<(d3d12::QueryHeap, u32)>,
end_of_pass_timer_query: Option<(Direct3D12::ID3D12QueryHeap, u32)>,
}
unsafe impl Send for CommandEncoder {}
@ -415,7 +680,7 @@ impl fmt::Debug for CommandEncoder {
#[derive(Debug)]
pub struct CommandBuffer {
raw: d3d12::GraphicsCommandList,
raw: Direct3D12::ID3D12GraphicsCommandList,
}
impl crate::DynCommandBuffer for CommandBuffer {}
@ -425,7 +690,7 @@ unsafe impl Sync for CommandBuffer {}
#[derive(Debug)]
pub struct Buffer {
resource: d3d12::Resource,
resource: Direct3D12::ID3D12Resource,
size: wgt::BufferAddress,
allocation: Option<suballocation::AllocationWrapper>,
}
@ -443,14 +708,15 @@ impl crate::BufferBinding<'_, Buffer> {
}
}
// TODO: Return GPU handle directly?
fn resolve_address(&self) -> wgt::BufferAddress {
self.buffer.resource.gpu_virtual_address() + self.offset
(unsafe { self.buffer.resource.GetGPUVirtualAddress() }) + self.offset
}
}
#[derive(Debug)]
pub struct Texture {
resource: d3d12::Resource,
resource: Direct3D12::ID3D12Resource,
format: wgt::TextureFormat,
dimension: wgt::TextureDimension,
size: wgt::Extent3d,
@ -496,10 +762,10 @@ impl Texture {
#[derive(Debug)]
pub struct TextureView {
raw_format: d3d12::Format,
raw_format: Dxgi::Common::DXGI_FORMAT,
aspects: crate::FormatAspects,
/// only used by resolve
target_base: (d3d12::Resource, u32),
target_base: (Direct3D12::ID3D12Resource, u32),
handle_srv: Option<descriptor::Handle>,
handle_uav: Option<descriptor::Handle>,
handle_rtv: Option<descriptor::Handle>,
@ -524,8 +790,8 @@ unsafe impl Sync for Sampler {}
#[derive(Debug)]
pub struct QuerySet {
raw: d3d12::QueryHeap,
raw_ty: d3d12_ty::D3D12_QUERY_TYPE,
raw: Direct3D12::ID3D12QueryHeap,
raw_ty: Direct3D12::D3D12_QUERY_TYPE,
}
impl crate::DynQuerySet for QuerySet {}
@ -535,7 +801,7 @@ unsafe impl Sync for QuerySet {}
#[derive(Debug)]
pub struct Fence {
raw: d3d12::Fence,
raw: Direct3D12::ID3D12Fence,
}
impl crate::DynFence for Fence {}
@ -544,7 +810,7 @@ unsafe impl Send for Fence {}
unsafe impl Sync for Fence {}
impl Fence {
pub fn raw_fence(&self) -> &d3d12::Fence {
pub fn raw_fence(&self) -> &Direct3D12::ID3D12Fence {
&self.raw
}
}
@ -571,7 +837,7 @@ enum BufferViewKind {
pub struct BindGroup {
handle_views: Option<descriptor::DualHandle>,
handle_samplers: Option<descriptor::DualHandle>,
dynamic_buffers: Vec<d3d12::GpuAddress>,
dynamic_buffers: Vec<Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE>,
}
impl crate::DynBindGroup for BindGroup {}
@ -602,7 +868,7 @@ struct RootConstantInfo {
#[derive(Debug, Clone)]
struct PipelineLayoutShared {
signature: d3d12::RootSignature,
signature: Option<Direct3D12::ID3D12RootSignature>,
total_root_elements: RootIndex,
special_constants_root_index: Option<RootIndex>,
root_constant_info: Option<RootConstantInfo>,
@ -633,14 +899,20 @@ impl crate::DynShaderModule for ShaderModule {}
pub(super) enum CompiledShader {
#[allow(unused)]
Dxc(Vec<u8>),
Fxc(d3d12::Blob),
Fxc(Direct3D::ID3DBlob),
}
impl CompiledShader {
fn create_native_shader(&self) -> d3d12::Shader {
match *self {
CompiledShader::Dxc(ref shader) => d3d12::Shader::from_raw(shader),
CompiledShader::Fxc(ref shader) => d3d12::Shader::from_blob(shader),
fn create_native_shader(&self) -> Direct3D12::D3D12_SHADER_BYTECODE {
match self {
CompiledShader::Dxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE {
pShaderBytecode: shader.as_ptr().cast(),
BytecodeLength: shader.len(),
},
CompiledShader::Fxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE {
pShaderBytecode: unsafe { shader.GetBufferPointer() },
BytecodeLength: unsafe { shader.GetBufferSize() },
},
}
}
@ -649,9 +921,9 @@ impl CompiledShader {
#[derive(Debug)]
pub struct RenderPipeline {
raw: d3d12::PipelineState,
raw: Direct3D12::ID3D12PipelineState,
layout: PipelineLayoutShared,
topology: d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY,
topology: Direct3D::D3D_PRIMITIVE_TOPOLOGY,
vertex_strides: [Option<NonZeroU32>; crate::MAX_VERTEX_BUFFERS],
}
@ -662,7 +934,7 @@ unsafe impl Sync for RenderPipeline {}
#[derive(Debug)]
pub struct ComputePipeline {
raw: d3d12::PipelineState,
raw: Direct3D12::ID3D12PipelineState,
layout: PipelineLayoutShared,
}
@ -682,7 +954,8 @@ pub struct AccelerationStructure {}
impl crate::DynAccelerationStructure for AccelerationStructure {}
impl SwapChain {
unsafe fn release_resources(self) -> d3d12::ComPtr<dxgi1_4::IDXGISwapChain3> {
unsafe fn release_resources(mut self) -> Dxgi::IDXGISwapChain3 {
unsafe { Foundation::HANDLE::free(&mut self.waitable) };
self.raw
}
@ -692,14 +965,14 @@ impl SwapChain {
) -> Result<bool, crate::SurfaceError> {
let timeout_ms = match timeout {
Some(duration) => duration.as_millis() as u32,
None => winbase::INFINITE,
None => Threading::INFINITE,
};
match unsafe { synchapi::WaitForSingleObject(self.waitable, timeout_ms) } {
winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => Err(crate::SurfaceError::Lost),
winbase::WAIT_OBJECT_0 => Ok(true),
winerror::WAIT_TIMEOUT => Ok(false),
match unsafe { Threading::WaitForSingleObject(self.waitable, timeout_ms) } {
Foundation::WAIT_ABANDONED | Foundation::WAIT_FAILED => Err(crate::SurfaceError::Lost),
Foundation::WAIT_OBJECT_0 => Ok(true),
Foundation::WAIT_TIMEOUT => Ok(false),
other => {
log::error!("Unexpected wait status: 0x{:x}", other);
log::error!("Unexpected wait status: 0x{:x?}", other);
Err(crate::SurfaceError::Lost)
}
}
@ -714,7 +987,7 @@ impl crate::Surface for Surface {
device: &Device,
config: &crate::SurfaceConfiguration,
) -> Result<(), crate::SurfaceError> {
let mut flags = dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
let mut flags = Dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
// We always set ALLOW_TEARING on the swapchain no matter
// what kind of swapchain we want because ResizeBuffers
// cannot change the swapchain's ALLOW_TEARING flag.
@ -722,7 +995,7 @@ impl crate::Surface for Surface {
// This does not change the behavior of the swapchain, just
// allow present calls to use tearing.
if self.supports_allow_tearing {
flags |= dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
flags |= Dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
// While `configure`s contract ensures that no work on the GPU's main queues
@ -760,77 +1033,72 @@ impl crate::Surface for Surface {
raw
}
None => {
let desc = d3d12::SwapchainDesc {
alpha_mode: auxil::dxgi::conv::map_acomposite_alpha_mode(
let desc = Dxgi::DXGI_SWAP_CHAIN_DESC1 {
AlphaMode: auxil::dxgi::conv::map_acomposite_alpha_mode(
config.composite_alpha_mode,
),
width: config.extent.width,
height: config.extent.height,
format: non_srgb_format,
stereo: false,
sample: d3d12::SampleDesc {
count: 1,
quality: 0,
Width: config.extent.width,
Height: config.extent.height,
Format: non_srgb_format,
Stereo: false.into(),
SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
buffer_usage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
buffer_count: swap_chain_buffer,
scaling: d3d12::Scaling::Stretch,
swap_effect: d3d12::SwapEffect::FlipDiscard,
flags,
BufferUsage: Dxgi::DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: swap_chain_buffer,
Scaling: Dxgi::DXGI_SCALING_STRETCH,
SwapEffect: Dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
Flags: flags.0 as u32,
};
let swap_chain1 = match self.target {
SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
self.factory
.unwrap_factory2()
.create_swapchain_for_composition(
device.present_queue.as_mut_ptr().cast(),
&desc,
)
.into_result()
unsafe {
self.factory
.unwrap_factory2()
.CreateSwapChainForComposition(&device.present_queue, &desc, None)
}
}
SurfaceTarget::SurfaceHandle(handle) => {
profiling::scope!(
"IDXGIFactoryMedia::CreateSwapChainForCompositionSurfaceHandle"
);
self.factory_media
.clone()
.ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))?
.create_swapchain_for_composition_surface_handle(
device.present_queue.as_mut_ptr().cast(),
handle,
&desc,
)
.into_result()
unsafe {
self.factory_media
.as_ref()
.ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))?
.CreateSwapChainForCompositionSurfaceHandle(
&device.present_queue,
handle,
&desc,
None,
)
}
}
SurfaceTarget::WndHandle(hwnd) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
self.factory
.as_factory2()
.unwrap()
.create_swapchain_for_hwnd(
device.present_queue.as_mut_ptr().cast(),
unsafe {
self.factory.unwrap_factory2().CreateSwapChainForHwnd(
&device.present_queue,
hwnd,
&desc,
None,
None,
)
.into_result()
}
}
};
let swap_chain1 = match swap_chain1 {
Ok(s) => s,
Err(err) => {
log::error!("SwapChain creation error: {}", err);
return Err(crate::SurfaceError::Other("swap chain creation"));
}
};
let swap_chain1 = swap_chain1.map_err(|err| {
log::error!("SwapChain creation error: {}", err);
crate::SurfaceError::Other("swap chain creation")
})?;
match &self.target {
SurfaceTarget::WndHandle(_) | &SurfaceTarget::SurfaceHandle(_) => {}
SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {}
SurfaceTarget::Visual(visual) => {
if let Err(err) =
unsafe { visual.SetContent(swap_chain1.as_unknown()) }.into_result()
{
if let Err(err) = unsafe { visual.SetContent(&swap_chain1) }.into_result() {
log::error!("Unable to SetContent: {}", err);
return Err(crate::SurfaceError::Other(
"IDCompositionVisual::SetContent",
@ -839,8 +1107,7 @@ impl crate::Surface for Surface {
}
SurfaceTarget::SwapChainPanel(swap_chain_panel) => {
if let Err(err) =
unsafe { swap_chain_panel.SetSwapChain(swap_chain1.as_ptr()) }
.into_result()
unsafe { swap_chain_panel.SetSwapChain(&swap_chain1) }.into_result()
{
log::error!("Unable to SetSwapChain: {}", err);
return Err(crate::SurfaceError::Other(
@ -850,7 +1117,7 @@ impl crate::Surface for Surface {
}
}
match unsafe { swap_chain1.cast::<dxgi1_4::IDXGISwapChain3>() }.into_result() {
match swap_chain1.cast::<Dxgi::IDXGISwapChain3>() {
Ok(swap_chain3) => swap_chain3,
Err(err) => {
log::error!("Unable to cast swap chain: {}", err);
@ -863,29 +1130,27 @@ impl crate::Surface for Surface {
match self.target {
SurfaceTarget::WndHandle(wnd_handle) => {
// Disable automatic Alt+Enter handling by DXGI.
const DXGI_MWA_NO_WINDOW_CHANGES: u32 = 1;
const DXGI_MWA_NO_ALT_ENTER: u32 = 2;
unsafe {
self.factory.MakeWindowAssociation(
wnd_handle,
DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER,
Dxgi::DXGI_MWA_NO_WINDOW_CHANGES | Dxgi::DXGI_MWA_NO_ALT_ENTER,
)
};
}
.into_device_result("MakeWindowAssociation")?;
}
SurfaceTarget::Visual(_)
| SurfaceTarget::SurfaceHandle(_)
| SurfaceTarget::SwapChainPanel(_) => {}
}
unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) };
unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) }
.into_device_result("SetMaximumFrameLatency")?;
let waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() };
let mut resources = Vec::with_capacity(swap_chain_buffer as usize);
for i in 0..swap_chain_buffer {
let mut resource = d3d12::Resource::null();
unsafe {
swap_chain.GetBuffer(i, &d3d12_ty::ID3D12Resource::uuidof(), resource.mut_void())
};
let resource = unsafe { swap_chain.GetBuffer(i) }
.into_device_result("Failed to get swapchain buffer")?;
resources.push(resource);
}
@ -966,16 +1231,15 @@ impl crate::Queue for Queue {
let mut temp_lists = self.temp_lists.lock();
temp_lists.clear();
for cmd_buf in command_buffers {
temp_lists.push(cmd_buf.raw.as_list());
temp_lists.push(Some(cmd_buf.raw.clone().into()));
}
{
profiling::scope!("ID3D12CommandQueue::ExecuteCommandLists");
self.raw.execute_command_lists(&temp_lists);
unsafe { self.raw.ExecuteCommandLists(&temp_lists) }
}
self.raw
.signal(&signal_fence.raw, signal_value)
unsafe { self.raw.Signal(&signal_fence.raw, signal_value) }
.into_device_result("Signal fence")?;
// Note the lack of synchronization here between the main Direct queue
@ -997,33 +1261,22 @@ impl crate::Queue for Queue {
let (interval, flags) = match sc.present_mode {
// We only allow immediate if ALLOW_TEARING is valid.
wgt::PresentMode::Immediate => (0, dxgi::DXGI_PRESENT_ALLOW_TEARING),
wgt::PresentMode::Mailbox => (0, 0),
wgt::PresentMode::Fifo => (1, 0),
wgt::PresentMode::Immediate => (0, Dxgi::DXGI_PRESENT_ALLOW_TEARING),
wgt::PresentMode::Mailbox => (0, Dxgi::DXGI_PRESENT::default()),
wgt::PresentMode::Fifo => (1, Dxgi::DXGI_PRESENT::default()),
m => unreachable!("Cannot make surface with present mode {m:?}"),
};
profiling::scope!("IDXGISwapchain3::Present");
unsafe { sc.raw.Present(interval, flags) };
unsafe { sc.raw.Present(interval, flags) }
.ok()
.into_device_result("Present")?;
Ok(())
}
unsafe fn get_timestamp_period(&self) -> f32 {
let mut frequency = 0u64;
unsafe { self.raw.GetTimestampFrequency(&mut frequency) };
let frequency = unsafe { self.raw.GetTimestampFrequency() }.expect("GetTimestampFrequency");
(1_000_000_000.0 / frequency as f64) as f32
}
}
/// A shorthand for producing a `ResourceCreationFailed` error if a ComPtr is null.
#[inline]
pub fn null_comptr_check<T: winapi::Interface>(
ptr: &d3d12::ComPtr<T>,
) -> Result<(), crate::DeviceError> {
if d3d12::ComPtr::is_null(ptr) {
return Err(crate::DeviceError::ResourceCreationFailed);
}
Ok(())
}

View File

@ -2,7 +2,7 @@ use std::ffi::CStr;
use std::ptr;
pub(super) use dxc::{compile_dxc, get_dxc_container, DxcContainer};
use winapi::um::d3dcompiler;
use windows::Win32::Graphics::Direct3D;
use crate::auxil::dxgi::result::HResult;
@ -16,7 +16,7 @@ pub(super) fn compile_fxc(
device: &super::Device,
source: &str,
source_name: Option<&CStr>,
raw_ep: &std::ffi::CString,
raw_ep: &CStr,
stage_bit: wgt::ShaderStages,
full_stage: &CStr,
) -> (
@ -24,49 +24,54 @@ pub(super) fn compile_fxc(
log::Level,
) {
profiling::scope!("compile_fxc");
let mut shader_data = d3d12::Blob::null();
let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS;
let mut shader_data = None;
let mut compile_flags = Direct3D::Fxc::D3DCOMPILE_ENABLE_STRICTNESS;
if device
.private_caps
.instance_flags
.contains(wgt::InstanceFlags::DEBUG)
{
compile_flags |= d3dcompiler::D3DCOMPILE_DEBUG | d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION;
compile_flags |=
Direct3D::Fxc::D3DCOMPILE_DEBUG | Direct3D::Fxc::D3DCOMPILE_SKIP_OPTIMIZATION;
}
// If no name has been set, D3DCompile wants the null pointer.
let source_name = source_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null());
let mut error = d3d12::Blob::null();
let mut error = None;
let hr = unsafe {
profiling::scope!("d3dcompiler::D3DCompile");
d3dcompiler::D3DCompile(
profiling::scope!("Direct3D::Fxc::D3DCompile");
Direct3D::Fxc::D3DCompile(
// TODO: Update low-level bindings to accept a slice here
source.as_ptr().cast(),
source.len(),
source_name.cast(),
ptr::null(),
ptr::null_mut(),
raw_ep.as_ptr(),
full_stage.as_ptr().cast(),
windows::core::PCSTR(source_name.cast()),
None,
None,
windows::core::PCSTR(raw_ep.as_ptr().cast()),
windows::core::PCSTR(full_stage.as_ptr().cast()),
compile_flags,
0,
shader_data.mut_void().cast(),
error.mut_void().cast(),
&mut shader_data,
Some(&mut error),
)
};
match hr.into_result() {
Ok(()) => (
Ok(super::CompiledShader::Fxc(shader_data)),
log::Level::Info,
),
Ok(()) => {
let shader_data = shader_data.unwrap();
(
Ok(super::CompiledShader::Fxc(shader_data)),
log::Level::Info,
)
}
Err(e) => {
let mut full_msg = format!("FXC D3DCompile error ({e})");
if !error.is_null() {
if let Some(error) = error {
use std::fmt::Write as _;
let message = unsafe {
std::slice::from_raw_parts(
error.GetBufferPointer() as *const u8,
error.GetBufferPointer().cast(),
error.GetBufferSize(),
)
};
@ -149,7 +154,7 @@ mod dxc {
) {
profiling::scope!("compile_dxc");
let mut compile_flags = arrayvec::ArrayVec::<&str, 6>::new_const();
compile_flags.push("-Ges"); // d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS
compile_flags.push("-Ges"); // Direct3D::Fxc::D3DCOMPILE_ENABLE_STRICTNESS
compile_flags.push("-Vd"); // Disable implicit validation to work around bugs when dxil.dll isn't in the local directory.
compile_flags.push("-HV"); // Use HLSL 2018, Naga doesn't supported 2021 yet.
compile_flags.push("2018");
@ -159,8 +164,8 @@ mod dxc {
.instance_flags
.contains(wgt::InstanceFlags::DEBUG)
{
compile_flags.push("-Zi"); // d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION
compile_flags.push("-Od"); // d3dcompiler::D3DCOMPILE_DEBUG
compile_flags.push("-Zi"); // Direct3D::Fxc::D3DCOMPILE_SKIP_OPTIMIZATION
compile_flags.push("-Od"); // Direct3D::Fxc::D3DCOMPILE_DEBUG
}
let blob = match dxc_container

View File

@ -1,409 +1,314 @@
pub(crate) use allocation::{
create_allocator_wrapper, create_buffer_resource, create_texture_resource,
free_buffer_allocation, free_texture_allocation, AllocationWrapper, GpuAllocatorWrapper,
};
use gpu_allocator::{d3d12::AllocationCreateDesc, MemoryLocation};
use parking_lot::Mutex;
use windows::Win32::Graphics::Direct3D12;
#[cfg(not(feature = "windows_rs"))]
use committed as allocation;
#[cfg(feature = "windows_rs")]
use placed as allocation;
use crate::auxil::dxgi::result::HResult as _;
// This exists to work around https://github.com/gfx-rs/wgpu/issues/3207
// Currently this will work the older, slower way if the windows_rs feature is disabled,
// and will use the fast path of suballocating buffers and textures using gpu_allocator if
// the windows_rs feature is enabled.
#[derive(Debug)]
pub(crate) struct GpuAllocatorWrapper {
pub(crate) allocator: gpu_allocator::d3d12::Allocator,
}
// This is the fast path using gpu_allocator to suballocate buffers and textures.
#[cfg(feature = "windows_rs")]
mod placed {
use crate::dx12::null_comptr_check;
use d3d12::ComPtr;
use parking_lot::Mutex;
use std::ptr;
use wgt::assertions::StrictAssertUnwrapExt;
use winapi::{
um::{
d3d12::{self as d3d12_ty, ID3D12Resource},
winnt::HRESULT,
},
Interface,
#[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)
}
};
use gpu_allocator::{
d3d12::{AllocationCreateDesc, ToWinapi, ToWindows},
MemoryLocation,
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,
resource: &mut Option<Direct3D12::ID3D12Resource>,
) -> Result<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, resource).map(|()| 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,
};
#[derive(Debug)]
pub(crate) struct GpuAllocatorWrapper {
pub(crate) allocator: gpu_allocator::d3d12::Allocator,
}
let name = desc.label.unwrap_or("Unlabeled buffer");
#[derive(Debug)]
pub(crate) struct AllocationWrapper {
pub(crate) allocation: gpu_allocator::d3d12::Allocation,
}
let mut allocator = device.mem_allocator.lock();
pub(crate) fn create_allocator_wrapper(
raw: &d3d12::Device,
memory_hints: &wgt::MemoryHints,
) -> Result<Option<Mutex<GpuAllocatorWrapper>>, crate::DeviceError> {
let device = raw.as_ptr();
let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc(
allocator.allocator.device(),
&raw_desc,
name,
location,
);
let allocation = allocator.allocator.allocate(&allocation_desc)?;
// 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(device.as_windows().clone()),
debug_settings: Default::default(),
allocation_sizes,
}) {
Ok(allocator) => Ok(Some(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: d3d12_ty::D3D12_RESOURCE_DESC,
resource: &mut ComPtr<ID3D12Resource>,
) -> Result<(HRESULT, 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);
// It's a workaround for Intel Xe drivers.
if !device.private_caps.suballocation_supported {
return super::committed::create_buffer_resource(device, desc, raw_desc, resource)
.map(|(hr, _)| (hr, 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");
// SAFETY: allocator exists when the windows_rs feature is enabled
let mut allocator = unsafe {
device
.mem_allocator
.as_ref()
.strict_unwrap_unchecked()
.lock()
};
// let mut allocator = unsafe { device.mem_allocator.as_ref().unwrap_unchecked().lock() };
let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc(
allocator.allocator.device().as_winapi(),
unsafe {
device.raw.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
&raw_desc,
name,
location,
);
let allocation = allocator.allocator.allocate(&allocation_desc)?;
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None,
resource,
)
}
.into_device_result("Placed buffer creation")?;
let hr = unsafe {
device.raw.CreatePlacedResource(
allocation.heap().as_winapi() as *mut _,
allocation.offset(),
&raw_desc,
d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
ptr::null(),
&ID3D12Resource::uuidof(),
resource.mut_void(),
)
};
null_comptr_check(resource)?;
device
.counters
.buffer_memory
.add(allocation.size() as isize);
Ok((hr, Some(AllocationWrapper { allocation })))
if resource.is_none() {
return Err(crate::DeviceError::ResourceCreationFailed);
}
pub(crate) fn create_texture_resource(
device: &crate::dx12::Device,
desc: &crate::TextureDescriptor,
raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
resource: &mut ComPtr<ID3D12Resource>,
) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
// It's a workaround for Intel Xe drivers.
if !device.private_caps.suballocation_supported {
return super::committed::create_texture_resource(device, desc, raw_desc, resource)
.map(|(hr, _)| (hr, None));
}
device
.counters
.buffer_memory
.add(allocation.size() as isize);
let location = MemoryLocation::GpuOnly;
Ok(Some(AllocationWrapper { allocation }))
}
let name = desc.label.unwrap_or("Unlabeled texture");
pub(crate) fn create_texture_resource(
device: &crate::dx12::Device,
desc: &crate::TextureDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
resource: &mut Option<Direct3D12::ID3D12Resource>,
) -> Result<Option<AllocationWrapper>, crate::DeviceError> {
// Workaround for Intel Xe drivers
if !device.private_caps.suballocation_supported {
return create_committed_texture_resource(device, desc, raw_desc, resource).map(|()| None);
}
// SAFETY: allocator exists when the windows_rs feature is enabled
let mut allocator = unsafe {
device
.mem_allocator
.as_ref()
.strict_unwrap_unchecked()
.lock()
};
let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc(
allocator.allocator.device().as_winapi(),
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)?;
unsafe {
device.raw.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
&raw_desc,
name,
location,
);
let allocation = allocator.allocator.allocate(&allocation_desc)?;
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None, // clear value
resource,
)
}
.into_device_result("Placed texture creation")?;
let hr = unsafe {
device.raw.CreatePlacedResource(
allocation.heap().as_winapi() as *mut _,
allocation.offset(),
&raw_desc,
d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
ptr::null(), // clear value
&ID3D12Resource::uuidof(),
resource.mut_void(),
)
};
null_comptr_check(resource)?;
device
.counters
.texture_memory
.add(allocation.size() as isize);
Ok((hr, Some(AllocationWrapper { allocation })))
if resource.is_none() {
return Err(crate::DeviceError::ResourceCreationFailed);
}
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}"),
};
}
device
.counters
.texture_memory
.add(allocation.size() as isize);
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}"),
};
}
Ok(Some(AllocationWrapper { allocation }))
}
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
}
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}"),
};
}
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 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}"),
};
}
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!()
}
}
}
}
// This is the older, slower path where it doesn't suballocate buffers.
// Tracking issue for when it can be removed: https://github.com/gfx-rs/wgpu/issues/3207
mod committed {
use crate::dx12::null_comptr_check;
use d3d12::ComPtr;
use parking_lot::Mutex;
use std::ptr;
use winapi::{
um::{
d3d12::{self as d3d12_ty, ID3D12Resource},
winnt::HRESULT,
pub(crate) fn create_committed_buffer_resource(
device: &crate::dx12::Device,
desc: &crate::BufferDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
resource: &mut Option<Direct3D12::ID3D12Resource>,
) -> Result<(), 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
},
Interface,
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,
};
// https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_heap_flags
const D3D12_HEAP_FLAG_CREATE_NOT_ZEROED: d3d12_ty::D3D12_HEAP_FLAGS = 0x1000;
// Allocator isn't needed when not suballocating with gpu_allocator
#[derive(Debug)]
pub(crate) struct GpuAllocatorWrapper {}
// Allocations aren't needed when not suballocating with gpu_allocator
#[derive(Debug)]
pub(crate) struct AllocationWrapper {}
#[allow(unused)]
pub(crate) fn create_allocator_wrapper(
_raw: &d3d12::Device,
_memory_hints: &wgt::MemoryHints,
) -> Result<Option<Mutex<GpuAllocatorWrapper>>, crate::DeviceError> {
Ok(None)
}
pub(crate) fn create_buffer_resource(
device: &crate::dx12::Device,
desc: &crate::BufferDescriptor,
raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
resource: &mut ComPtr<ID3D12Resource>,
) -> Result<(HRESULT, 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);
let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES {
Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM,
CPUPageProperty: if is_cpu_read {
d3d12_ty::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK
} else if is_cpu_write {
d3d12_ty::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE
unsafe {
device.raw.CreateCommittedResource(
&heap_properties,
if device.private_caps.heap_create_not_zeroed {
Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
} else {
d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE
Direct3D12::D3D12_HEAP_FLAG_NONE
},
MemoryPoolPreference: match device.private_caps.memory_architecture {
crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => {
d3d12_ty::D3D12_MEMORY_POOL_L1
}
_ => d3d12_ty::D3D12_MEMORY_POOL_L0,
},
CreationNodeMask: 0,
VisibleNodeMask: 0,
};
&raw_desc,
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
None,
resource,
)
}
.into_device_result("Committed buffer creation")?;
let hr = unsafe {
device.raw.CreateCommittedResource(
&heap_properties,
if device.private_caps.heap_create_not_zeroed {
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
} else {
d3d12_ty::D3D12_HEAP_FLAG_NONE
},
&raw_desc,
d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
ptr::null(),
&ID3D12Resource::uuidof(),
resource.mut_void(),
)
};
null_comptr_check(resource)?;
Ok((hr, None))
if resource.is_none() {
return Err(crate::DeviceError::ResourceCreationFailed);
}
pub(crate) fn create_texture_resource(
device: &crate::dx12::Device,
_desc: &crate::TextureDescriptor,
raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
resource: &mut ComPtr<ID3D12Resource>,
) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES {
Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM,
CPUPageProperty: d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
MemoryPoolPreference: match device.private_caps.memory_architecture {
crate::dx12::MemoryArchitecture::NonUnified => d3d12_ty::D3D12_MEMORY_POOL_L1,
crate::dx12::MemoryArchitecture::Unified { .. } => d3d12_ty::D3D12_MEMORY_POOL_L0,
},
CreationNodeMask: 0,
VisibleNodeMask: 0,
};
let hr = unsafe {
device.raw.CreateCommittedResource(
&heap_properties,
if device.private_caps.heap_create_not_zeroed {
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
} else {
d3d12_ty::D3D12_HEAP_FLAG_NONE
},
&raw_desc,
d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
ptr::null(), // clear value
&ID3D12Resource::uuidof(),
resource.mut_void(),
)
};
null_comptr_check(resource)?;
Ok((hr, None))
}
#[allow(unused)]
pub(crate) fn free_buffer_allocation(
_device: &crate::dx12::Device,
_allocation: AllocationWrapper,
_allocator: &Mutex<GpuAllocatorWrapper>,
) {
// No-op when not using gpu-allocator
}
#[allow(unused)]
pub(crate) fn free_texture_allocation(
_device: &crate::dx12::Device,
_allocation: AllocationWrapper,
_allocator: &Mutex<GpuAllocatorWrapper>,
) {
// No-op when not using gpu-allocator
}
Ok(())
}
pub(crate) fn create_committed_texture_resource(
device: &crate::dx12::Device,
_desc: &crate::TextureDescriptor,
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
resource: &mut Option<Direct3D12::ID3D12Resource>,
) -> Result<(), 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,
};
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
resource,
)
}
.into_device_result("Committed texture creation")?;
if resource.is_none() {
return Err(crate::DeviceError::ResourceCreationFailed);
}
Ok(())
}

View File

@ -1,83 +1,39 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
// use here so that the recursive RIDL macro can find the crate
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
use winapi::RIDL;
use windows::Win32::Graphics::Dxgi;
RIDL! {#[uuid(0x63aad0b8, 0x7c24, 0x40ff, 0x85, 0xa8, 0x64, 0x0d, 0x94, 0x4c, 0xc3, 0x25)]
interface ISwapChainPanelNative(ISwapChainPanelNativeVtbl): IUnknown(IUnknownVtbl) {
fn SetSwapChain(swapChain: *const winapi::shared::dxgi1_2::IDXGISwapChain1,) -> winapi::um::winnt::HRESULT,
}}
winapi::ENUM! {
enum D3D12_VIEW_INSTANCING_TIER {
D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0,
D3D12_VIEW_INSTANCING_TIER_1 = 1,
D3D12_VIEW_INSTANCING_TIER_2 = 2,
D3D12_VIEW_INSTANCING_TIER_3 = 3,
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) }
}
}
winapi::ENUM! {
enum D3D12_COMMAND_LIST_SUPPORT_FLAGS {
D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE = 0,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_BUNDLE,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_COMPUTE,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_COPY,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_DECODE,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_PROCESS,
// D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_ENCODE,
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()
}
}
winapi::STRUCT! {
struct D3D12_FEATURE_DATA_D3D12_OPTIONS3 {
CopyQueueTimestampQueriesSupported: winapi::shared::minwindef::BOOL,
CastingFullyTypedFormatSupported: winapi::shared::minwindef::BOOL,
WriteBufferImmediateSupportFlags: D3D12_COMMAND_LIST_SUPPORT_FLAGS,
ViewInstancingTier: D3D12_VIEW_INSTANCING_TIER,
BarycentricsSupported: winapi::shared::minwindef::BOOL,
}
}
winapi::ENUM! {
enum D3D12_WAVE_MMA_TIER {
D3D12_WAVE_MMA_TIER_NOT_SUPPORTED = 0,
D3D12_WAVE_MMA_TIER_1_0 = 10,
}
}
winapi::STRUCT! {
struct D3D12_FEATURE_DATA_D3D12_OPTIONS9 {
MeshShaderPipelineStatsSupported: winapi::shared::minwindef::BOOL,
MeshShaderSupportsFullRangeRenderTargetArrayIndex: winapi::shared::minwindef::BOOL,
AtomicInt64OnTypedResourceSupported: winapi::shared::minwindef::BOOL,
AtomicInt64OnGroupSharedSupported: winapi::shared::minwindef::BOOL,
DerivativesInMeshAndAmplificationShadersSupported: winapi::shared::minwindef::BOOL,
WaveMMATier: D3D12_WAVE_MMA_TIER,
}
}
winapi::ENUM! {
enum D3D_SHADER_MODEL {
D3D_SHADER_MODEL_NONE = 0,
D3D_SHADER_MODEL_5_1 = 0x51,
D3D_SHADER_MODEL_6_0 = 0x60,
D3D_SHADER_MODEL_6_1 = 0x61,
D3D_SHADER_MODEL_6_2 = 0x62,
D3D_SHADER_MODEL_6_3 = 0x63,
D3D_SHADER_MODEL_6_4 = 0x64,
D3D_SHADER_MODEL_6_5 = 0x65,
D3D_SHADER_MODEL_6_6 = 0x66,
D3D_SHADER_MODEL_6_7 = 0x67,
D3D_HIGHEST_SHADER_MODEL = 0x67,
}
}
winapi::STRUCT! {
struct D3D12_FEATURE_DATA_SHADER_MODEL {
HighestShaderModel: D3D_SHADER_MODEL,
}
#[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,
}

View File

@ -1,14 +1,12 @@
use crate::auxil;
use std::mem;
use winapi::um::d3d12 as d3d12_ty;
use windows::Win32::Graphics::{Direct3D12, Dxgi};
pub(crate) const D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING: u32 = 0x1688;
use crate::auxil;
pub(super) struct ViewDescriptor {
dimension: wgt::TextureViewDimension,
pub aspects: crate::FormatAspects,
pub rtv_dsv_format: d3d12::Format,
srv_uav_format: Option<d3d12::Format>,
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,
@ -44,113 +42,98 @@ fn aspects_to_plane(aspects: crate::FormatAspects) -> u32 {
}
impl ViewDescriptor {
pub(crate) unsafe fn to_srv(&self) -> Option<d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC> {
let mut desc = d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC {
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: 0,
Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
u: unsafe { mem::zeroed() },
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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE1D;
unsafe {
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
ResourceMinLODClamp: 0.0,
}
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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_SRV {
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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DMS;
unsafe {
*desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_SRV {
UnusedField_NothingToDefine: 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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2D;
unsafe {
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
PlaneSlice: aspects_to_plane(self.aspects),
ResourceMinLODClamp: 0.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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
unsafe {
*desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_SRV {
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
unsafe {
*desc.u.Texture2DArray_mut() = d3d12_ty::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,
}
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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE3D;
unsafe {
*desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
ResourceMinLODClamp: 0.0,
}
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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURECUBE;
unsafe {
*desc.u.TextureCube_mut() = d3d12_ty::D3D12_TEXCUBE_SRV {
MostDetailedMip: self.mip_level_base,
MipLevels: self.mip_level_count,
ResourceMinLODClamp: 0.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 = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
unsafe {
*desc.u.TextureCubeArray_mut() = d3d12_ty::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,
}
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,
}
}
}
@ -158,59 +141,51 @@ impl ViewDescriptor {
Some(desc)
}
pub(crate) unsafe fn to_uav(&self) -> Option<d3d12_ty::D3D12_UNORDERED_ACCESS_VIEW_DESC> {
let mut desc = d3d12_ty::D3D12_UNORDERED_ACCESS_VIEW_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: 0,
u: unsafe { mem::zeroed() },
ViewDimension: Direct3D12::D3D12_UAV_DIMENSION_UNKNOWN,
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE1D;
unsafe {
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_UAV {
MipSlice: self.mip_level_base,
}
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_UAV {
MipSlice: self.mip_level_base,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_UAV {
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 = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE2D;
unsafe {
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_UAV {
MipSlice: self.mip_level_base,
PlaneSlice: aspects_to_plane(self.aspects),
}
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 = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
unsafe {
*desc.u.Texture2DArray_mut() = d3d12_ty::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),
}
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 = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE3D;
unsafe {
*desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_UAV {
MipSlice: self.mip_level_base,
FirstWSlice: self.array_layer_base,
WSize: self.array_layer_count,
}
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 => {
@ -221,78 +196,66 @@ impl ViewDescriptor {
Some(desc)
}
pub(crate) unsafe fn to_rtv(&self) -> d3d12_ty::D3D12_RENDER_TARGET_VIEW_DESC {
let mut desc = d3d12_ty::D3D12_RENDER_TARGET_VIEW_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: 0,
u: unsafe { mem::zeroed() },
ViewDimension: Direct3D12::D3D12_RTV_DIMENSION_UNKNOWN,
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE1D;
unsafe {
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_RTV {
MipSlice: self.mip_level_base,
}
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_RTV {
MipSlice: self.mip_level_base,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_RTV {
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 = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DMS;
unsafe {
*desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_RTV {
UnusedField_NothingToDefine: 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 = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2D;
unsafe {
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_RTV {
MipSlice: self.mip_level_base,
PlaneSlice: aspects_to_plane(self.aspects),
}
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 = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
unsafe {
*desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_RTV {
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
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 = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
unsafe {
*desc.u.Texture2DArray_mut() = d3d12_ty::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),
}
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 = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE3D;
unsafe {
*desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_RTV {
MipSlice: self.mip_level_base,
FirstWSlice: self.array_layer_base,
WSize: self.array_layer_count,
}
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 => {
@ -303,78 +266,72 @@ impl ViewDescriptor {
desc
}
pub(crate) unsafe fn to_dsv(&self, read_only: bool) -> d3d12_ty::D3D12_DEPTH_STENCIL_VIEW_DESC {
let mut desc = d3d12_ty::D3D12_DEPTH_STENCIL_VIEW_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: 0,
ViewDimension: Direct3D12::D3D12_DSV_DIMENSION_UNKNOWN,
Flags: {
let mut flags = d3d12_ty::D3D12_DSV_FLAG_NONE;
let mut flags = Direct3D12::D3D12_DSV_FLAG_NONE;
if read_only {
if self.aspects.contains(crate::FormatAspects::DEPTH) {
flags |= d3d12_ty::D3D12_DSV_FLAG_READ_ONLY_DEPTH;
flags |= Direct3D12::D3D12_DSV_FLAG_READ_ONLY_DEPTH;
}
if self.aspects.contains(crate::FormatAspects::STENCIL) {
flags |= d3d12_ty::D3D12_DSV_FLAG_READ_ONLY_STENCIL;
flags |= Direct3D12::D3D12_DSV_FLAG_READ_ONLY_STENCIL;
}
}
flags
},
u: unsafe { mem::zeroed() },
Anonymous: Default::default(),
};
match self.dimension {
wgt::TextureViewDimension::D1 => {
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE1D;
unsafe {
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_DSV {
MipSlice: self.mip_level_base,
}
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1D;
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_DSV {
MipSlice: self.mip_level_base,
}
}
/*
wgt::TextureViewDimension::D1Array => {
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_DSV {
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 = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DMS;
unsafe {
*desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_DSV {
UnusedField_NothingToDefine: 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 = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2D;
unsafe {
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_DSV {
MipSlice: self.mip_level_base,
}
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 = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
unsafe {
*desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_DSV {
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
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 = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
unsafe {
*desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_DSV {
MipSlice: self.mip_level_base,
FirstArraySlice: self.array_layer_base,
ArraySize: self.array_layer_count,
}
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

View File

@ -64,29 +64,3 @@ macro_rules! strict_assert_ne {
debug_assert_ne!( $( $arg )* )
};
}
/// Unwrapping using strict_asserts
pub trait StrictAssertUnwrapExt<T> {
/// Unchecked unwrap, with a [`strict_assert`] backed assertion of validitly.
///
/// # Safety
///
/// It _must_ be valid to call unwrap_unchecked on this value.
unsafe fn strict_unwrap_unchecked(self) -> T;
}
impl<T> StrictAssertUnwrapExt<T> for Option<T> {
unsafe fn strict_unwrap_unchecked(self) -> T {
strict_assert!(self.is_some(), "Called strict_unwrap_unchecked on None");
// SAFETY: Checked by above assert, or by assertion by unsafe.
unsafe { self.unwrap_unchecked() }
}
}
impl<T, E> StrictAssertUnwrapExt<T> for Result<T, E> {
unsafe fn strict_unwrap_unchecked(self) -> T {
strict_assert!(self.is_ok(), "Called strict_unwrap_unchecked on Err");
// SAFETY: Checked by above assert, or by assertion by unsafe.
unsafe { self.unwrap_unchecked() }
}
}

View File

@ -164,7 +164,6 @@ hal = { workspace = true, features = ["renderdoc"] }
hal = { workspace = true, features = [
"dxc_shader_compiler",
"renderdoc",
"windows_rs",
] }
[target.'cfg(target_arch = "wasm32")'.dependencies.hal]

View File

@ -332,15 +332,18 @@ pub enum SurfaceTargetUnsafe {
///
/// # Safety
///
/// - visual must be a valid IDCompositionVisual to create a surface upon.
/// - visual must be a valid `IDCompositionVisual` to create a surface upon. Its refcount will be incremented internally and kept live as long as the resulting [`Surface`] is live.
#[cfg(dx12)]
CompositionVisual(*mut std::ffi::c_void),
/// Surface from DX12 `SurfaceHandle`.
/// Surface from DX12 `DirectComposition` handle.
///
/// <https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nf-dxgi1_3-idxgifactorymedia-createswapchainforcompositionsurfacehandle>
///
/// # Safety
///
/// - surface_handle must be a valid SurfaceHandle to create a surface upon.
/// - surface_handle must be a valid `DirectComposition` handle to create a surface upon. Its lifetime **will not** be internally managed: this handle **should not** be freed before
/// the resulting [`Surface`] is destroyed.
#[cfg(dx12)]
SurfaceHandle(*mut std::ffi::c_void),
@ -348,7 +351,7 @@ pub enum SurfaceTargetUnsafe {
///
/// # Safety
///
/// - visual must be a valid SwapChainPanel to create a surface upon.
/// - visual must be a valid SwapChainPanel to create a surface upon. Its refcount will be incremented internally and kept live as long as the resulting [`Surface`] is live.
#[cfg(dx12)]
SwapChainPanel(*mut std::ffi::c_void),
}