mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
[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:
parent
222f1ea733
commit
a157c3cf4b
@ -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
13
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
||||
|
13
Cargo.toml
13
Cargo.toml
@ -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"
|
||||
|
@ -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
|
@ -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"]
|
@ -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.
|
263
d3d12/src/com.rs
263
d3d12/src/com.rs
@ -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) }
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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() }
|
||||
}
|
||||
}
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
125
d3d12/src/lib.rs
125
d3d12/src/lib.rs
@ -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 }) }
|
||||
}
|
||||
}
|
182
d3d12/src/pso.rs
182
d3d12/src/pso.rs
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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>;
|
@ -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) }
|
||||
}
|
||||
}
|
@ -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() }
|
||||
}
|
||||
}
|
@ -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) }
|
||||
}
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
@ -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),
|
||||
|
@ -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
@ -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),
|
||||
}),
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user