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)
|
- 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)
|
## 22.0.0 (2024-07-17)
|
||||||
|
|
||||||
### Overview
|
### Overview
|
||||||
@ -749,7 +753,7 @@ The easiest way to make this code safe is to use shared ownership:
|
|||||||
```rust
|
```rust
|
||||||
let window: Arc<winit::Window>;
|
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.
|
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "d3d12"
|
|
||||||
version = "22.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.6.0",
|
|
||||||
"libloading 0.8.5",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.13.4"
|
version = "0.13.4"
|
||||||
@ -1684,7 +1675,6 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"presser",
|
"presser",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winapi",
|
|
||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4325,7 +4315,6 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"d3d12",
|
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"glam",
|
"glam",
|
||||||
"glow",
|
"glow",
|
||||||
@ -4356,8 +4345,8 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
"winapi",
|
|
||||||
"windows",
|
"windows",
|
||||||
|
"windows-core",
|
||||||
"winit 0.29.15",
|
"winit 0.29.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
13
Cargo.toml
13
Cargo.toml
@ -6,7 +6,6 @@ members = [
|
|||||||
|
|
||||||
# default members
|
# default members
|
||||||
"benches",
|
"benches",
|
||||||
"d3d12",
|
|
||||||
"examples",
|
"examples",
|
||||||
"naga-cli",
|
"naga-cli",
|
||||||
"naga",
|
"naga",
|
||||||
@ -24,7 +23,6 @@ members = [
|
|||||||
exclude = []
|
exclude = []
|
||||||
default-members = [
|
default-members = [
|
||||||
"benches",
|
"benches",
|
||||||
"d3d12",
|
|
||||||
"examples",
|
"examples",
|
||||||
"naga-cli",
|
"naga-cli",
|
||||||
"naga",
|
"naga",
|
||||||
@ -96,8 +94,7 @@ indexmap = "2"
|
|||||||
itertools = { version = "0.10.5" }
|
itertools = { version = "0.10.5" }
|
||||||
ktx2 = "0.3"
|
ktx2 = "0.3"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
# libloading 0.8 switches from `winapi` to `windows-sys`; permit either
|
libloading = "0.8"
|
||||||
libloading = ">=0.7, <0.9"
|
|
||||||
libtest-mimic = "0.6"
|
libtest-mimic = "0.6"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
nanorand = { version = "0.7", default-features = false, features = ["wyrand"] }
|
nanorand = { version = "0.7", default-features = false, features = ["wyrand"] }
|
||||||
@ -148,14 +145,10 @@ gpu-descriptor = "0.3"
|
|||||||
|
|
||||||
# DX dependencies
|
# DX dependencies
|
||||||
bit-set = "0.8"
|
bit-set = "0.8"
|
||||||
gpu-allocator = { version = "0.27", default-features = false, features = [
|
gpu-allocator = { version = "0.27", default-features = false }
|
||||||
"d3d12",
|
|
||||||
"public-winapi",
|
|
||||||
] }
|
|
||||||
d3d12 = { version = "22.0.0", path = "./d3d12/" }
|
|
||||||
range-alloc = "0.1"
|
range-alloc = "0.1"
|
||||||
winapi = "0.3"
|
|
||||||
hassle-rs = "0.11.0"
|
hassle-rs = "0.11.0"
|
||||||
|
windows-core = { version = "0.58", default-features = false }
|
||||||
|
|
||||||
# Gles dependencies
|
# Gles dependencies
|
||||||
khronos-egl = "6"
|
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> {
|
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||||
profiling::scope!("Instance::instance_create_surface_from_visual");
|
profiling::scope!("Instance::instance_create_surface_from_visual");
|
||||||
self.instance_create_surface_dx12(id_in, |inst| unsafe {
|
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> {
|
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||||
profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
|
profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
|
||||||
self.instance_create_surface_dx12(id_in, |inst| unsafe {
|
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.
|
## Has no effect if not targeting Windows.
|
||||||
dx12 = [
|
dx12 = [
|
||||||
# DX12 is only available on Windows, therefore request HLSL output also only if we target Windows.
|
# 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:bit-set",
|
||||||
"dep:libloading",
|
"dep:libloading",
|
||||||
"dep:range-alloc",
|
"dep:range-alloc",
|
||||||
"winapi/std",
|
"dep:windows-core",
|
||||||
"winapi/winbase",
|
"gpu-allocator/d3d12",
|
||||||
"winapi/d3d12",
|
"naga/hlsl-out-if-target-windows",
|
||||||
"winapi/d3d12shader",
|
"windows/Win32_Graphics_Direct3D_Fxc",
|
||||||
"winapi/d3d12sdklayers",
|
"windows/Win32_Graphics_Direct3D",
|
||||||
"winapi/dxgi1_6",
|
"windows/Win32_Graphics_Direct3D12",
|
||||||
"winapi/errhandlingapi",
|
"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"]
|
dxc_shader_compiler = ["dep:hassle-rs"]
|
||||||
renderdoc = ["dep:libloading", "dep:renderdoc-sys"]
|
renderdoc = ["dep:libloading", "dep:renderdoc-sys"]
|
||||||
fragile-send-sync-non-atomic-wasm = ["wgt/fragile-send-sync-non-atomic-wasm"]
|
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 }
|
range-alloc = { workspace = true, optional = true }
|
||||||
gpu-allocator = { workspace = true, optional = true }
|
gpu-allocator = { workspace = true, optional = true }
|
||||||
hassle-rs = { 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
|
# backend: Gles
|
||||||
glutin_wgl_sys = { workspace = true, optional = true }
|
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]
|
[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
|
||||||
# backend: Metal
|
# backend: Metal
|
||||||
block = { workspace = true, optional = true }
|
block = { workspace = true, optional = true }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
|
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
|
// Helper to convert DXGI adapter name to a normal string
|
||||||
pub fn map_adapter_name(name: [u16; 128]) -> 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()
|
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 wgt::TextureFormat as Tf;
|
||||||
use winapi::shared::dxgiformat::*;
|
use Dxgi::Common::*;
|
||||||
|
|
||||||
Some(match format {
|
Some(match format {
|
||||||
Tf::R8Unorm => DXGI_FORMAT_R8_UNORM,
|
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) {
|
match map_texture_format_failable(format) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => unreachable!(),
|
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,
|
// Note: DXGI doesn't allow sRGB format on the swapchain,
|
||||||
// but creating RTV of swapchain buffers with sRGB works.
|
// 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 {
|
match format {
|
||||||
wgt::TextureFormat::Bgra8UnormSrgb => dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
|
wgt::TextureFormat::Bgra8UnormSrgb => Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||||
wgt::TextureFormat::Rgba8UnormSrgb => dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
|
wgt::TextureFormat::Rgba8UnormSrgb => Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||||
_ => map_texture_format(format),
|
_ => 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(
|
pub fn map_texture_format_for_srv_uav(
|
||||||
format: wgt::TextureFormat,
|
format: wgt::TextureFormat,
|
||||||
aspect: crate::FormatAspects,
|
aspect: crate::FormatAspects,
|
||||||
) -> Option<dxgiformat::DXGI_FORMAT> {
|
) -> Option<Dxgi::Common::DXGI_FORMAT> {
|
||||||
Some(match (format, aspect) {
|
Some(match (format, aspect) {
|
||||||
(wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => {
|
(wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => {
|
||||||
dxgiformat::DXGI_FORMAT_R16_UNORM
|
Dxgi::Common::DXGI_FORMAT_R16_UNORM
|
||||||
}
|
}
|
||||||
(wgt::TextureFormat::Depth32Float, crate::FormatAspects::DEPTH) => {
|
(wgt::TextureFormat::Depth32Float, crate::FormatAspects::DEPTH) => {
|
||||||
dxgiformat::DXGI_FORMAT_R32_FLOAT
|
Dxgi::Common::DXGI_FORMAT_R32_FLOAT
|
||||||
}
|
}
|
||||||
(wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::DEPTH) => {
|
(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,
|
wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8,
|
||||||
crate::FormatAspects::DEPTH,
|
crate::FormatAspects::DEPTH,
|
||||||
) => dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
|
) => Dxgi::Common::DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
|
||||||
|
|
||||||
(wgt::TextureFormat::Depth32FloatStencil8, crate::FormatAspects::STENCIL) => {
|
(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,
|
wgt::TextureFormat::Stencil8 | wgt::TextureFormat::Depth24PlusStencil8,
|
||||||
crate::FormatAspects::STENCIL,
|
crate::FormatAspects::STENCIL,
|
||||||
) => dxgiformat::DXGI_FORMAT_X24_TYPELESS_G8_UINT,
|
) => Dxgi::Common::DXGI_FORMAT_X24_TYPELESS_G8_UINT,
|
||||||
|
|
||||||
(_, crate::FormatAspects::DEPTH)
|
(_, crate::FormatAspects::DEPTH)
|
||||||
| (_, crate::FormatAspects::STENCIL)
|
| (_, crate::FormatAspects::STENCIL)
|
||||||
@ -152,22 +155,22 @@ pub fn map_texture_format_for_srv_uav(
|
|||||||
pub fn map_texture_format_for_copy(
|
pub fn map_texture_format_for_copy(
|
||||||
format: wgt::TextureFormat,
|
format: wgt::TextureFormat,
|
||||||
aspect: crate::FormatAspects,
|
aspect: crate::FormatAspects,
|
||||||
) -> Option<dxgiformat::DXGI_FORMAT> {
|
) -> Option<Dxgi::Common::DXGI_FORMAT> {
|
||||||
Some(match (format, aspect) {
|
Some(match (format, aspect) {
|
||||||
(wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => {
|
(wgt::TextureFormat::Depth16Unorm, crate::FormatAspects::DEPTH) => {
|
||||||
dxgiformat::DXGI_FORMAT_R16_UNORM
|
Dxgi::Common::DXGI_FORMAT_R16_UNORM
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth32FloatStencil8,
|
wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth32FloatStencil8,
|
||||||
crate::FormatAspects::DEPTH,
|
crate::FormatAspects::DEPTH,
|
||||||
) => dxgiformat::DXGI_FORMAT_R32_FLOAT,
|
) => Dxgi::Common::DXGI_FORMAT_R32_FLOAT,
|
||||||
|
|
||||||
(
|
(
|
||||||
wgt::TextureFormat::Stencil8
|
wgt::TextureFormat::Stencil8
|
||||||
| wgt::TextureFormat::Depth24PlusStencil8
|
| wgt::TextureFormat::Depth24PlusStencil8
|
||||||
| wgt::TextureFormat::Depth32FloatStencil8,
|
| wgt::TextureFormat::Depth32FloatStencil8,
|
||||||
crate::FormatAspects::STENCIL,
|
crate::FormatAspects::STENCIL,
|
||||||
) => dxgiformat::DXGI_FORMAT_R8_UINT,
|
) => Dxgi::Common::DXGI_FORMAT_R8_UINT,
|
||||||
|
|
||||||
(format, crate::FormatAspects::COLOR) => map_texture_format(format),
|
(format, crate::FormatAspects::COLOR) => map_texture_format(format),
|
||||||
|
|
||||||
@ -180,9 +183,9 @@ pub fn map_texture_format_for_resource(
|
|||||||
usage: crate::TextureUses,
|
usage: crate::TextureUses,
|
||||||
has_view_formats: bool,
|
has_view_formats: bool,
|
||||||
casting_fully_typed_format_supported: bool,
|
casting_fully_typed_format_supported: bool,
|
||||||
) -> dxgiformat::DXGI_FORMAT {
|
) -> Dxgi::Common::DXGI_FORMAT {
|
||||||
use wgt::TextureFormat as Tf;
|
use wgt::TextureFormat as Tf;
|
||||||
use winapi::shared::dxgiformat::*;
|
use Dxgi::Common::*;
|
||||||
|
|
||||||
if casting_fully_typed_format_supported {
|
if casting_fully_typed_format_supported {
|
||||||
map_texture_format(format)
|
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 {
|
match format {
|
||||||
wgt::IndexFormat::Uint16 => dxgiformat::DXGI_FORMAT_R16_UINT,
|
wgt::IndexFormat::Uint16 => Dxgi::Common::DXGI_FORMAT_R16_UINT,
|
||||||
wgt::IndexFormat::Uint32 => dxgiformat::DXGI_FORMAT_R32_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 wgt::VertexFormat as Vf;
|
||||||
use winapi::shared::dxgiformat::*;
|
use Dxgi::Common::*;
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
Vf::Unorm8x2 => DXGI_FORMAT_R8G8_UNORM,
|
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 {
|
pub fn map_acomposite_alpha_mode(_mode: wgt::CompositeAlphaMode) -> Dxgi::Common::DXGI_ALPHA_MODE {
|
||||||
d3d12::AlphaMode::Ignore
|
Dxgi::Common::DXGI_ALPHA_MODE_IGNORE
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
use std::{borrow::Cow, slice};
|
use std::{borrow::Cow, slice};
|
||||||
|
|
||||||
use parking_lot::{lock_api::RawMutex, Mutex};
|
use parking_lot::{lock_api::RawMutex, Mutex};
|
||||||
use winapi::{
|
use windows::Win32::{Foundation, System::Diagnostics::Debug};
|
||||||
um::{errhandlingapi, winnt},
|
|
||||||
vc::excpt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is a mutex as opposed to an atomic as we need to completely
|
// This is a mutex as opposed to an atomic as we need to completely
|
||||||
// lock everyone out until we have registered or unregistered the
|
// 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() {
|
pub fn register_exception_handler() {
|
||||||
let mut count_guard = EXCEPTION_HANDLER_COUNT.lock();
|
let mut count_guard = EXCEPTION_HANDLER_COUNT.lock();
|
||||||
if *count_guard == 0 {
|
if *count_guard == 0 {
|
||||||
unsafe {
|
unsafe { Debug::AddVectoredExceptionHandler(0, Some(output_debug_string_handler)) };
|
||||||
errhandlingapi::AddVectoredExceptionHandler(0, Some(output_debug_string_handler))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
*count_guard += 1;
|
*count_guard += 1;
|
||||||
}
|
}
|
||||||
@ -27,9 +22,7 @@ pub fn register_exception_handler() {
|
|||||||
pub fn unregister_exception_handler() {
|
pub fn unregister_exception_handler() {
|
||||||
let mut count_guard = EXCEPTION_HANDLER_COUNT.lock();
|
let mut count_guard = EXCEPTION_HANDLER_COUNT.lock();
|
||||||
if *count_guard == 1 {
|
if *count_guard == 1 {
|
||||||
unsafe {
|
unsafe { Debug::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _) };
|
||||||
errhandlingapi::RemoveVectoredExceptionHandler(output_debug_string_handler as *mut _)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
*count_guard -= 1;
|
*count_guard -= 1;
|
||||||
}
|
}
|
||||||
@ -43,34 +36,34 @@ const MESSAGE_PREFIXES: &[(&str, log::Level)] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
unsafe extern "system" fn output_debug_string_handler(
|
unsafe extern "system" fn output_debug_string_handler(
|
||||||
exception_info: *mut winnt::EXCEPTION_POINTERS,
|
exception_info: *mut Debug::EXCEPTION_POINTERS,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
// See https://stackoverflow.com/a/41480827
|
// See https://stackoverflow.com/a/41480827
|
||||||
let record = unsafe { &*(*exception_info).ExceptionRecord };
|
let record = unsafe { &*(*exception_info).ExceptionRecord };
|
||||||
if record.NumberParameters != 2 {
|
if record.NumberParameters != 2 {
|
||||||
return excpt::EXCEPTION_CONTINUE_SEARCH;
|
return Debug::EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
let message = match record.ExceptionCode {
|
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(
|
slice::from_raw_parts(
|
||||||
record.ExceptionInformation[1] as *const u8,
|
record.ExceptionInformation[1] as *const u8,
|
||||||
record.ExceptionInformation[0],
|
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(
|
slice::from_raw_parts(
|
||||||
record.ExceptionInformation[1] as *const u16,
|
record.ExceptionInformation[1] as *const u16,
|
||||||
record.ExceptionInformation[0],
|
record.ExceptionInformation[0],
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
_ => return excpt::EXCEPTION_CONTINUE_SEARCH,
|
_ => return Debug::EXCEPTION_CONTINUE_SEARCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = match message.strip_prefix("D3D12 ") {
|
let message = match message.strip_prefix("D3D12 ") {
|
||||||
Some(msg) => msg
|
Some(msg) => msg
|
||||||
.trim_end_matches("\n\0")
|
.trim_end_matches("\n\0")
|
||||||
.trim_end_matches("[ STATE_CREATION WARNING #0: UNKNOWN]"),
|
.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
|
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") {
|
if level == log::Level::Warn && message.contains("#82") {
|
||||||
// This is are useless spammy warnings (#820, #821):
|
// This is are useless spammy warnings (#820, #821):
|
||||||
// "The application did not pass any clear value to resource creation"
|
// "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") {
|
if level == log::Level::Warn && message.contains("DRAW_EMPTY_SCISSOR_RECTANGLE") {
|
||||||
// This is normal, WebGPU allows passing empty scissor rectangles.
|
// This is normal, WebGPU allows passing empty scissor rectangles.
|
||||||
return excpt::EXCEPTION_CONTINUE_SEARCH;
|
return Debug::EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = std::panic::catch_unwind(|| {
|
let _ = std::panic::catch_unwind(|| {
|
||||||
@ -101,5 +94,5 @@ unsafe extern "system" fn output_debug_string_handler(
|
|||||||
crate::VALIDATION_CANARY.add(message.to_string());
|
crate::VALIDATION_CANARY.add(message.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
excpt::EXCEPTION_CONTINUE_EXECUTION
|
Debug::EXCEPTION_CONTINUE_EXECUTION
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use winapi::{
|
use std::ops::Deref;
|
||||||
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_6, winerror},
|
|
||||||
Interface,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::result::HResult as _;
|
use windows::{core::Interface as _, Win32::Graphics::Dxgi};
|
||||||
|
|
||||||
|
use crate::dx12::DxgiLib;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum DxgiFactoryType {
|
pub enum DxgiFactoryType {
|
||||||
@ -12,9 +11,8 @@ pub enum DxgiFactoryType {
|
|||||||
Factory6,
|
Factory6,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool {
|
fn should_keep_adapter(adapter: &Dxgi::IDXGIAdapter1) -> bool {
|
||||||
let mut desc = unsafe { std::mem::zeroed() };
|
let desc = unsafe { adapter.GetDesc1() }.unwrap();
|
||||||
unsafe { adapter.GetDesc1(&mut desc) };
|
|
||||||
|
|
||||||
// The Intel Haswell family of iGPUs had support for the D3D12 API but it was later
|
// The Intel Haswell family of iGPUs had support for the D3D12 API but it was later
|
||||||
// removed due to a security vulnerability.
|
// 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
|
// 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.
|
// 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.
|
// We don't want that and discourage that kind of filtering anyway, so we skip the integrated WARP.
|
||||||
if desc.VendorId == 5140 && (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) == 0 {
|
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);
|
let adapter_name = super::conv::map_adapter_name(desc.Description);
|
||||||
if adapter_name.contains("Microsoft Basic Render Driver") {
|
if adapter_name.contains("Microsoft Basic Render Driver") {
|
||||||
return false;
|
return false;
|
||||||
@ -51,50 +51,85 @@ fn should_keep_adapter(adapter: &dxgi::IDXGIAdapter1) -> bool {
|
|||||||
true
|
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);
|
let mut adapters = Vec::with_capacity(8);
|
||||||
|
|
||||||
for cur_index in 0.. {
|
for cur_index in 0.. {
|
||||||
if let Some(factory6) = factory.as_factory6() {
|
if let DxgiFactory::Factory6(ref factory6) = factory {
|
||||||
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
|
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
|
||||||
// We're already at dxgi1.6, we can grab IDXGIAdapter4 directly
|
// We're already at dxgi1.6, we can grab IDXGIAdapter4 directly
|
||||||
let mut adapter4 = d3d12::ComPtr::<dxgi1_6::IDXGIAdapter4>::null();
|
let adapter4: Dxgi::IDXGIAdapter4 = match unsafe {
|
||||||
let hr = unsafe {
|
|
||||||
factory6.EnumAdapterByGpuPreference(
|
factory6.EnumAdapterByGpuPreference(
|
||||||
cur_index,
|
cur_index,
|
||||||
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
Dxgi::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
||||||
&dxgi1_6::IDXGIAdapter4::uuidof(),
|
|
||||||
adapter4.mut_void(),
|
|
||||||
)
|
)
|
||||||
|
} {
|
||||||
|
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) {
|
if !should_keep_adapter(&adapter4) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
adapters.push(d3d12::DxgiAdapter::Adapter4(adapter4));
|
adapters.push(DxgiAdapter::Adapter4(adapter4));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
profiling::scope!("IDXGIFactory1::EnumAdapters1");
|
profiling::scope!("IDXGIFactory1::EnumAdapters1");
|
||||||
let mut adapter1 = d3d12::ComPtr::<dxgi::IDXGIAdapter1>::null();
|
let adapter1: Dxgi::IDXGIAdapter1 = match unsafe { factory.EnumAdapters1(cur_index) } {
|
||||||
let hr = unsafe { factory.EnumAdapters1(cur_index, adapter1.mut_self()) };
|
Ok(a) => a,
|
||||||
|
Err(e) if e.code() == Dxgi::DXGI_ERROR_NOT_FOUND => break,
|
||||||
if hr == winerror::DXGI_ERROR_NOT_FOUND {
|
Err(e) => {
|
||||||
break;
|
log::error!("Failed enumerating adapters: {}", e);
|
||||||
}
|
break;
|
||||||
if let Err(err) = hr.into_result() {
|
}
|
||||||
log::error!("Failed enumerating adapters: {}", err);
|
};
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !should_keep_adapter(&adapter1) {
|
if !should_keep_adapter(&adapter1) {
|
||||||
continue;
|
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.
|
// Do the most aggressive casts first, skipping Adapter4 as we definitely don't have dxgi1_6.
|
||||||
|
|
||||||
// Adapter1 -> Adapter3
|
// Adapter1 -> Adapter3
|
||||||
unsafe {
|
match adapter1.cast::<Dxgi::IDXGIAdapter3>() {
|
||||||
match adapter1.cast::<dxgi1_4::IDXGIAdapter3>().into_result() {
|
Ok(adapter3) => {
|
||||||
Ok(adapter3) => {
|
adapters.push(DxgiAdapter::Adapter3(adapter3));
|
||||||
adapters.push(d3d12::DxgiAdapter::Adapter3(adapter3));
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
Err(err) => {
|
||||||
Err(err) => {
|
log::warn!("Failed casting Adapter1 to Adapter3: {}", err);
|
||||||
log::warn!("Failed casting Adapter1 to Adapter3: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adapter1 -> Adapter2
|
// Adapter1 -> Adapter2
|
||||||
unsafe {
|
match adapter1.cast::<Dxgi::IDXGIAdapter2>() {
|
||||||
match adapter1.cast::<dxgi1_2::IDXGIAdapter2>().into_result() {
|
Ok(adapter2) => {
|
||||||
Ok(adapter2) => {
|
adapters.push(DxgiAdapter::Adapter2(adapter2));
|
||||||
adapters.push(d3d12::DxgiAdapter::Adapter2(adapter2));
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
Err(err) => {
|
||||||
Err(err) => {
|
log::warn!("Failed casting Adapter1 to Adapter2: {}", err);
|
||||||
log::warn!("Failed casting Adapter1 to Adapter2: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
adapters.push(d3d12::DxgiAdapter::Adapter1(adapter1));
|
adapters.push(DxgiAdapter::Adapter1(adapter1));
|
||||||
}
|
}
|
||||||
|
|
||||||
adapters
|
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
|
/// returning the one that succeeds, or if the required_factory_type fails to be
|
||||||
/// created.
|
/// created.
|
||||||
pub fn create_factory(
|
pub fn create_factory(
|
||||||
required_factory_type: DxgiFactoryType,
|
required_factory_type: DxgiFactoryType,
|
||||||
instance_flags: wgt::InstanceFlags,
|
instance_flags: wgt::InstanceFlags,
|
||||||
) -> Result<(d3d12::DxgiLib, d3d12::DxgiFactory), crate::InstanceError> {
|
) -> Result<(DxgiLib, DxgiFactory), crate::InstanceError> {
|
||||||
let lib_dxgi = d3d12::DxgiLib::new().map_err(|e| {
|
let lib_dxgi = DxgiLib::new().map_err(|e| {
|
||||||
crate::InstanceError::with_source(String::from("failed to load dxgi.dll"), 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) {
|
if instance_flags.contains(wgt::InstanceFlags::VALIDATION) {
|
||||||
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
|
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
|
||||||
// `CreateDXGIFactory2` if the debug interface is actually available. So
|
// `CreateDXGIFactory2` if the debug interface is actually available. So
|
||||||
// we check for whether it exists first.
|
// we check for whether it exists first.
|
||||||
match lib_dxgi.get_debug_interface1() {
|
match lib_dxgi.debug_interface1() {
|
||||||
Ok(pair) => match pair.into_result() {
|
Ok(pair) => match pair {
|
||||||
Ok(_debug_controller) => {
|
Ok(_debug_controller) => {
|
||||||
factory_flags |= d3d12::FactoryCreationFlags::DEBUG;
|
factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Unable to enable DXGI debug interface: {}", err);
|
log::warn!("Unable to enable DXGI debug interface: {}", err);
|
||||||
@ -171,7 +245,7 @@ pub fn create_factory(
|
|||||||
|
|
||||||
// Try to create IDXGIFactory4
|
// Try to create IDXGIFactory4
|
||||||
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
|
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
|
||||||
Ok(pair) => match pair.into_result() {
|
Ok(pair) => match pair {
|
||||||
Ok(factory) => Some(factory),
|
Ok(factory) => Some(factory),
|
||||||
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
|
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -197,10 +271,10 @@ pub fn create_factory(
|
|||||||
|
|
||||||
if let Some(factory4) = factory4 {
|
if let Some(factory4) = factory4 {
|
||||||
// Try to cast the IDXGIFactory4 into IDXGIFactory6
|
// 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 {
|
match factory6 {
|
||||||
Ok(factory6) => {
|
Ok(factory6) => {
|
||||||
return Ok((lib_dxgi, d3d12::DxgiFactory::Factory6(factory6)));
|
return Ok((lib_dxgi, DxgiFactory::Factory6(factory6)));
|
||||||
}
|
}
|
||||||
// If we require factory6, hard error.
|
// If we require factory6, hard error.
|
||||||
Err(err) if required_factory_type == DxgiFactoryType::Factory6 => {
|
Err(err) if required_factory_type == DxgiFactoryType::Factory6 => {
|
||||||
@ -212,14 +286,14 @@ pub fn create_factory(
|
|||||||
// If we don't print it to warn.
|
// If we don't print it to warn.
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", 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
|
// Try to create IDXGIFactory1
|
||||||
let factory1 = match lib_dxgi.create_factory1() {
|
let factory1 = match lib_dxgi.create_factory1() {
|
||||||
Ok(pair) => match pair.into_result() {
|
Ok(pair) => match pair {
|
||||||
Ok(factory) => factory,
|
Ok(factory) => factory,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// err is a Cow<str>, not an Error implementor
|
// err is a Cow<str>, not an Error implementor
|
||||||
@ -238,10 +312,10 @@ pub fn create_factory(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Try to cast the IDXGIFactory1 into IDXGIFactory2
|
// 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 {
|
match factory2 {
|
||||||
Ok(factory2) => {
|
Ok(factory2) => {
|
||||||
return Ok((lib_dxgi, d3d12::DxgiFactory::Factory2(factory2)));
|
return Ok((lib_dxgi, DxgiFactory::Factory2(factory2)));
|
||||||
}
|
}
|
||||||
// If we require factory2, hard error.
|
// If we require factory2, hard error.
|
||||||
Err(err) if required_factory_type == DxgiFactoryType::Factory2 => {
|
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.
|
// 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 std::borrow::Cow;
|
||||||
|
|
||||||
use winapi::shared::winerror;
|
use windows::Win32::{Foundation, Graphics::Dxgi};
|
||||||
|
|
||||||
pub(crate) trait HResult<O> {
|
pub(crate) trait HResult<O> {
|
||||||
fn into_result(self) -> Result<O, Cow<'static, str>>;
|
fn into_result(self) -> Result<O, Cow<'static, str>>;
|
||||||
fn into_device_result(self, description: &str) -> Result<O, crate::DeviceError>;
|
fn into_device_result(self, description: &str) -> Result<O, crate::DeviceError>;
|
||||||
}
|
}
|
||||||
impl HResult<()> for i32 {
|
impl<T> HResult<T> for windows::core::Result<T> {
|
||||||
fn into_result(self) -> Result<(), Cow<'static, str>> {
|
fn into_result(self) -> Result<T, Cow<'static, str>> {
|
||||||
if self >= 0 {
|
// TODO: use windows-rs built-in error formatting?
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let description = match self {
|
let description = match self {
|
||||||
winerror::E_UNEXPECTED => "unexpected",
|
Ok(t) => return Ok(t),
|
||||||
winerror::E_NOTIMPL => "not implemented",
|
Err(e) if e.code() == Foundation::E_UNEXPECTED => "unexpected",
|
||||||
winerror::E_OUTOFMEMORY => "out of memory",
|
Err(e) if e.code() == Foundation::E_NOTIMPL => "not implemented",
|
||||||
winerror::E_INVALIDARG => "invalid argument",
|
Err(e) if e.code() == Foundation::E_OUTOFMEMORY => "out of memory",
|
||||||
_ => return Err(Cow::Owned(format!("0x{:X}", self as u32))),
|
Err(e) if e.code() == Foundation::E_INVALIDARG => "invalid argument",
|
||||||
|
Err(e) => return Err(Cow::Owned(format!("{e:?}"))),
|
||||||
};
|
};
|
||||||
Err(Cow::Borrowed(description))
|
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)]
|
#![allow(unreachable_code)]
|
||||||
|
|
||||||
|
let err_code = if let Err(err) = &self {
|
||||||
|
Some(err.code())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
self.into_result().map_err(|err| {
|
self.into_result().map_err(|err| {
|
||||||
log::error!("{} failed: {}", description, err);
|
log::error!("{} failed: {}", description, err);
|
||||||
|
|
||||||
match self {
|
let Some(err_code) = err_code else {
|
||||||
winerror::E_OUTOFMEMORY => {
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
match err_code {
|
||||||
|
Foundation::E_OUTOFMEMORY => {
|
||||||
#[cfg(feature = "oom_panic")]
|
#[cfg(feature = "oom_panic")]
|
||||||
panic!("{description} failed: Out of memory");
|
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")]
|
#[cfg(feature = "device_lost_panic")]
|
||||||
panic!("{description} failed: Device lost ({err})");
|
panic!("{description} failed: Device lost ({err})");
|
||||||
}
|
}
|
||||||
@ -41,20 +50,7 @@ impl HResult<()> for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self == winerror::E_OUTOFMEMORY {
|
crate::DeviceError::Lost
|
||||||
crate::DeviceError::OutOfMemory
|
|
||||||
} else {
|
|
||||||
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
|
#![allow(dead_code)] // IPresentationManager is unused currently
|
||||||
|
|
||||||
use std::mem;
|
use windows::Win32::System::Performance::{QueryPerformanceCounter, QueryPerformanceFrequency};
|
||||||
|
|
||||||
use winapi::um::{
|
|
||||||
profileapi::{QueryPerformanceCounter, QueryPerformanceFrequency},
|
|
||||||
winnt::LARGE_INTEGER,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum PresentationTimer {
|
pub enum PresentationTimer {
|
||||||
/// DXGI uses QueryPerformanceCounter
|
/// DXGI uses [`QueryPerformanceCounter()`]
|
||||||
Dxgi {
|
Dxgi {
|
||||||
/// How many ticks of QPC per second
|
/// How many ticks of QPC per second
|
||||||
frequency: u64,
|
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)]
|
#[allow(non_snake_case)]
|
||||||
IPresentationManager {
|
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 {
|
impl PresentationTimer {
|
||||||
/// Create a presentation timer using QueryPerformanceFrequency (what DXGI uses for presentation times)
|
/// Create a presentation timer using QueryPerformanceFrequency (what DXGI uses for presentation times)
|
||||||
pub fn new_dxgi() -> Self {
|
pub fn new_dxgi() -> Self {
|
||||||
let mut frequency: LARGE_INTEGER = unsafe { mem::zeroed() };
|
let mut frequency = 0;
|
||||||
let success = unsafe { QueryPerformanceFrequency(&mut frequency) };
|
unsafe { QueryPerformanceFrequency(&mut frequency) }.unwrap();
|
||||||
assert_ne!(success, 0);
|
|
||||||
|
|
||||||
Self::Dxgi {
|
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+
|
// 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.
|
// 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 =
|
let kernelbase =
|
||||||
libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap();
|
libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap();
|
||||||
// No concerns about lifetimes here as kernelbase is always there.
|
// 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.
|
// Always do u128 math _after_ hitting the timing function.
|
||||||
match *self {
|
match *self {
|
||||||
PresentationTimer::Dxgi { frequency } => {
|
PresentationTimer::Dxgi { frequency } => {
|
||||||
let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() };
|
let mut counter = 0;
|
||||||
let success = unsafe { QueryPerformanceCounter(&mut counter) };
|
unsafe { QueryPerformanceCounter(&mut counter) }.unwrap();
|
||||||
assert_ne!(success, 0);
|
|
||||||
|
|
||||||
// counter * (1_000_000_000 / freq) but re-ordered to make more precise
|
// 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 {
|
PresentationTimer::IPresentationManager {
|
||||||
fnQueryInterruptTimePrecise,
|
fnQueryInterruptTimePrecise,
|
||||||
|
@ -106,7 +106,7 @@ impl Default for RenderDoc {
|
|||||||
unsafe { Self::new() }
|
unsafe { Self::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A implementation specific handle
|
/// An implementation specific handle
|
||||||
pub type Handle = *mut os::raw::c_void;
|
pub type Handle = *mut os::raw::c_void;
|
||||||
|
|
||||||
impl RenderDoc {
|
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 std::{mem, ptr, sync::Arc, thread};
|
||||||
use winapi::{
|
|
||||||
shared::{
|
use parking_lot::Mutex;
|
||||||
dxgi, dxgi1_2, dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM, minwindef::DWORD, windef, winerror,
|
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 {
|
impl Drop for super::Adapter {
|
||||||
@ -30,34 +36,31 @@ impl Drop for super::Adapter {
|
|||||||
|
|
||||||
impl super::Adapter {
|
impl super::Adapter {
|
||||||
pub unsafe fn report_live_objects(&self) {
|
pub unsafe fn report_live_objects(&self) {
|
||||||
if let Ok(debug_device) = unsafe {
|
if let Ok(debug_device) = self.raw.cast::<Direct3D12::ID3D12DebugDevice>() {
|
||||||
self.raw
|
|
||||||
.cast::<d3d12sdklayers::ID3D12DebugDevice>()
|
|
||||||
.into_result()
|
|
||||||
} {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
debug_device.ReportLiveDeviceObjects(
|
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
|
&self.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn expose(
|
pub(super) fn expose(
|
||||||
adapter: d3d12::DxgiAdapter,
|
adapter: DxgiAdapter,
|
||||||
library: &Arc<d3d12::D3D12Lib>,
|
library: &Arc<D3D12Lib>,
|
||||||
instance_flags: wgt::InstanceFlags,
|
instance_flags: wgt::InstanceFlags,
|
||||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||||
) -> Option<crate::ExposedAdapter<super::Api>> {
|
) -> Option<crate::ExposedAdapter<super::Api>> {
|
||||||
// Create the device so that we can get the capabilities.
|
// Create the device so that we can get the capabilities.
|
||||||
let device = {
|
let device = {
|
||||||
profiling::scope!("ID3D12Device::create_device");
|
profiling::scope!("ID3D12Device::create_device");
|
||||||
match library.create_device(&adapter, d3d12::FeatureLevel::L11_0) {
|
match library.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) {
|
||||||
Ok(pair) => match pair.into_result() {
|
Ok(pair) => match pair {
|
||||||
Ok(device) => device,
|
Ok(device) => device,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Device creation failed: {}", err);
|
log::warn!("Device creation failed: {}", err);
|
||||||
@ -75,45 +78,42 @@ impl super::Adapter {
|
|||||||
|
|
||||||
// Detect the highest supported feature level.
|
// Detect the highest supported feature level.
|
||||||
let d3d_feature_level = [
|
let d3d_feature_level = [
|
||||||
d3d12::FeatureLevel::L12_1,
|
Direct3D::D3D_FEATURE_LEVEL_12_1,
|
||||||
d3d12::FeatureLevel::L12_0,
|
Direct3D::D3D_FEATURE_LEVEL_12_0,
|
||||||
d3d12::FeatureLevel::L11_1,
|
Direct3D::D3D_FEATURE_LEVEL_11_1,
|
||||||
d3d12::FeatureLevel::L11_0,
|
Direct3D::D3D_FEATURE_LEVEL_11_0,
|
||||||
];
|
];
|
||||||
let mut device_levels: d3d12_ty::D3D12_FEATURE_DATA_FEATURE_LEVELS =
|
let mut device_levels = Direct3D12::D3D12_FEATURE_DATA_FEATURE_LEVELS {
|
||||||
unsafe { mem::zeroed() };
|
NumFeatureLevels: d3d_feature_level.len() as u32,
|
||||||
device_levels.NumFeatureLevels = d3d_feature_level.len() as u32;
|
pFeatureLevelsRequested: d3d_feature_level.as_ptr().cast(),
|
||||||
device_levels.pFeatureLevelsRequested = d3d_feature_level.as_ptr().cast();
|
MaxSupportedFeatureLevel: Default::default(),
|
||||||
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_FEATURE_LEVELS,
|
Direct3D12::D3D12_FEATURE_FEATURE_LEVELS,
|
||||||
ptr::from_mut(&mut device_levels).cast(),
|
<*mut _>::cast(&mut device_levels),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FEATURE_LEVELS>() as _,
|
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.
|
.unwrap();
|
||||||
let max_feature_level =
|
let max_feature_level = device_levels.MaxSupportedFeatureLevel;
|
||||||
d3d12::FeatureLevel::try_from(device_levels.MaxSupportedFeatureLevel)
|
|
||||||
.expect("Unexpected feature level");
|
|
||||||
|
|
||||||
// We have found a possible adapter.
|
// We have found a possible adapter.
|
||||||
// Acquire the device information.
|
// Acquire the device information.
|
||||||
let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
|
let desc = unsafe { adapter.unwrap_adapter2().GetDesc2() }.unwrap();
|
||||||
unsafe {
|
|
||||||
adapter.unwrap_adapter2().GetDesc2(&mut desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description);
|
let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description);
|
||||||
|
|
||||||
let mut features_architecture: d3d12_ty::D3D12_FEATURE_DATA_ARCHITECTURE =
|
let mut features_architecture = Direct3D12::D3D12_FEATURE_DATA_ARCHITECTURE::default();
|
||||||
unsafe { mem::zeroed() };
|
|
||||||
assert_eq!(0, unsafe {
|
unsafe {
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_ARCHITECTURE,
|
Direct3D12::D3D12_FEATURE_ARCHITECTURE,
|
||||||
ptr::from_mut(&mut features_architecture).cast(),
|
<*mut _>::cast(&mut features_architecture),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_ARCHITECTURE>() as _,
|
mem::size_of_val(&features_architecture) as u32,
|
||||||
)
|
)
|
||||||
});
|
}
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut workarounds = super::Workarounds::default();
|
let mut workarounds = super::Workarounds::default();
|
||||||
|
|
||||||
@ -122,27 +122,25 @@ impl super::Adapter {
|
|||||||
name: device_name,
|
name: device_name,
|
||||||
vendor: desc.VendorId,
|
vendor: desc.VendorId,
|
||||||
device: desc.DeviceId,
|
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;
|
workarounds.avoid_cpu_descriptor_overwrites = true;
|
||||||
wgt::DeviceType::Cpu
|
wgt::DeviceType::Cpu
|
||||||
} else if features_architecture.UMA != 0 {
|
} else if features_architecture.UMA.as_bool() {
|
||||||
wgt::DeviceType::IntegratedGpu
|
wgt::DeviceType::IntegratedGpu
|
||||||
} else {
|
} else {
|
||||||
wgt::DeviceType::DiscreteGpu
|
wgt::DeviceType::DiscreteGpu
|
||||||
},
|
},
|
||||||
driver: {
|
driver: {
|
||||||
let mut i: winnt::LARGE_INTEGER = unsafe { mem::zeroed() };
|
if let Ok(i) = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } {
|
||||||
if 0 == unsafe {
|
|
||||||
adapter.CheckInterfaceSupport(&dxgi::IDXGIDevice::uuidof(), &mut i)
|
|
||||||
} {
|
|
||||||
let quad_part = unsafe { *i.QuadPart() };
|
|
||||||
const MASK: i64 = 0xFFFF;
|
const MASK: i64 = 0xFFFF;
|
||||||
format!(
|
format!(
|
||||||
"{}.{}.{}.{}",
|
"{}.{}.{}.{}",
|
||||||
quad_part >> 48,
|
i >> 48,
|
||||||
(quad_part >> 32) & MASK,
|
(i >> 32) & MASK,
|
||||||
(quad_part >> 16) & MASK,
|
(i >> 16) & MASK,
|
||||||
quad_part & MASK
|
i & MASK
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
@ -151,84 +149,101 @@ impl super::Adapter {
|
|||||||
driver_info: String::new(),
|
driver_info: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut options: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS = unsafe { mem::zeroed() };
|
let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default();
|
||||||
assert_eq!(0, unsafe {
|
unsafe {
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS,
|
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS,
|
||||||
ptr::from_mut(&mut options).cast(),
|
<*mut _>::cast(&mut options),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS>() as _,
|
mem::size_of_val(&options) as u32,
|
||||||
)
|
)
|
||||||
});
|
}
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let _depth_bounds_test_supported = {
|
let _depth_bounds_test_supported = {
|
||||||
let mut features2: d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS2 =
|
let mut features2 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS2::default();
|
||||||
unsafe { mem::zeroed() };
|
unsafe {
|
||||||
let hr = unsafe {
|
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS2,
|
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS2,
|
||||||
ptr::from_mut(&mut features2).cast(),
|
<*mut _>::cast(&mut features2),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS2>() as _,
|
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 casting_fully_typed_format_supported = {
|
||||||
let mut features3: crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS3 =
|
let mut features3 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS3::default();
|
||||||
unsafe { mem::zeroed() };
|
unsafe {
|
||||||
let hr = unsafe {
|
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
21, // D3D12_FEATURE_D3D12_OPTIONS3
|
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3,
|
||||||
ptr::from_mut(&mut features3).cast(),
|
<*mut _>::cast(&mut features3),
|
||||||
mem::size_of::<crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS3>() as _,
|
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() {
|
let shader_model = if dxc_container.is_none() {
|
||||||
naga::back::hlsl::ShaderModel::V5_1
|
naga::back::hlsl::ShaderModel::V5_1
|
||||||
} else {
|
} else {
|
||||||
let mut versions = [
|
let mut versions = [
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_7,
|
Direct3D12::D3D_SHADER_MODEL_6_7,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_6,
|
Direct3D12::D3D_SHADER_MODEL_6_6,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_5,
|
Direct3D12::D3D_SHADER_MODEL_6_5,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_4,
|
Direct3D12::D3D_SHADER_MODEL_6_4,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_3,
|
Direct3D12::D3D_SHADER_MODEL_6_3,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_2,
|
Direct3D12::D3D_SHADER_MODEL_6_2,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_1,
|
Direct3D12::D3D_SHADER_MODEL_6_1,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_6_0,
|
Direct3D12::D3D_SHADER_MODEL_6_0,
|
||||||
crate::dx12::types::D3D_SHADER_MODEL_5_1,
|
Direct3D12::D3D_SHADER_MODEL_5_1,
|
||||||
]
|
]
|
||||||
.iter();
|
.iter();
|
||||||
match loop {
|
match loop {
|
||||||
if let Some(&sm) = versions.next() {
|
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,
|
HighestShaderModel: sm,
|
||||||
};
|
};
|
||||||
if 0 == unsafe {
|
if unsafe {
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
7, // D3D12_FEATURE_SHADER_MODEL
|
Direct3D12::D3D12_FEATURE_SHADER_MODEL,
|
||||||
ptr::from_mut(&mut sm).cast(),
|
<*mut _>::cast(&mut sm),
|
||||||
mem::size_of::<crate::dx12::types::D3D12_FEATURE_DATA_SHADER_MODEL>()
|
mem::size_of_val(&sm) as u32,
|
||||||
as _,
|
|
||||||
)
|
)
|
||||||
} {
|
}
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
break sm.HighestShaderModel;
|
break sm.HighestShaderModel;
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
Direct3D12::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,
|
Direct3D12::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,
|
Direct3D12::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,
|
Direct3D12::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,
|
Direct3D12::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,
|
Direct3D12::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,
|
Direct3D12::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,
|
Direct3D12::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_6_7 => naga::back::hlsl::ShaderModel::V6_7,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -236,15 +251,15 @@ impl super::Adapter {
|
|||||||
let private_caps = super::PrivateCapabilities {
|
let private_caps = super::PrivateCapabilities {
|
||||||
instance_flags,
|
instance_flags,
|
||||||
heterogeneous_resource_heaps: options.ResourceHeapTier
|
heterogeneous_resource_heaps: options.ResourceHeapTier
|
||||||
!= d3d12_ty::D3D12_RESOURCE_HEAP_TIER_1,
|
!= Direct3D12::D3D12_RESOURCE_HEAP_TIER_1,
|
||||||
memory_architecture: if features_architecture.UMA != 0 {
|
memory_architecture: if features_architecture.UMA.as_bool() {
|
||||||
super::MemoryArchitecture::Unified {
|
super::MemoryArchitecture::Unified {
|
||||||
cache_coherent: features_architecture.CacheCoherentUMA != 0,
|
cache_coherent: features_architecture.CacheCoherentUMA.as_bool(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
super::MemoryArchitecture::NonUnified
|
super::MemoryArchitecture::NonUnified
|
||||||
},
|
},
|
||||||
heap_create_not_zeroed: false, //TODO: winapi support for Options7
|
heap_create_not_zeroed,
|
||||||
casting_fully_typed_format_supported,
|
casting_fully_typed_format_supported,
|
||||||
// See https://github.com/gfx-rs/wgpu/issues/3552
|
// See https://github.com/gfx-rs/wgpu/issues/3552
|
||||||
suballocation_supported: !info.name.contains("Iris(R) Xe"),
|
suballocation_supported: !info.name.contains("Iris(R) Xe"),
|
||||||
@ -255,29 +270,29 @@ impl super::Adapter {
|
|||||||
let tier3_practical_descriptor_limit = 1 << 20;
|
let tier3_practical_descriptor_limit = 1 << 20;
|
||||||
|
|
||||||
let (full_heap_count, uav_count) = match options.ResourceBindingTier {
|
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 {
|
let uav_count = match max_feature_level {
|
||||||
d3d12::FeatureLevel::L11_0 => 8,
|
Direct3D::D3D_FEATURE_LEVEL_11_0 => 8,
|
||||||
_ => 64,
|
_ => 64,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
|
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1,
|
||||||
uav_count,
|
uav_count,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_2 => (
|
Direct3D12::D3D12_RESOURCE_BINDING_TIER_2 => (
|
||||||
d3d12_ty::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2,
|
Direct3D12::D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2,
|
||||||
64,
|
64,
|
||||||
),
|
),
|
||||||
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_3 => (
|
Direct3D12::D3D12_RESOURCE_BINDING_TIER_3 => (
|
||||||
tier3_practical_descriptor_limit,
|
tier3_practical_descriptor_limit,
|
||||||
tier3_practical_descriptor_limit,
|
tier3_practical_descriptor_limit,
|
||||||
),
|
),
|
||||||
other => {
|
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,
|
8,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -313,14 +328,14 @@ impl super::Adapter {
|
|||||||
// write the results there, and issue a bunch of copy commands.
|
// write the results there, and issue a bunch of copy commands.
|
||||||
//| wgt::Features::PIPELINE_STATISTICS_QUERY
|
//| 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 |= wgt::Features::VERTEX_WRITABLE_STORAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
features.set(
|
features.set(
|
||||||
wgt::Features::CONSERVATIVE_RASTERIZATION,
|
wgt::Features::CONSERVATIVE_RASTERIZATION,
|
||||||
options.ConservativeRasterizationTier
|
options.ConservativeRasterizationTier
|
||||||
!= d3d12_ty::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
|
!= Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
|
||||||
);
|
);
|
||||||
|
|
||||||
features.set(
|
features.set(
|
||||||
@ -331,60 +346,62 @@ impl super::Adapter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let bgra8unorm_storage_supported = {
|
let bgra8unorm_storage_supported = {
|
||||||
let mut bgra8unorm_info: d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT =
|
let mut bgra8unorm_info = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
|
||||||
unsafe { mem::zeroed() };
|
Format: Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||||
bgra8unorm_info.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
..Default::default()
|
||||||
|
};
|
||||||
let hr = unsafe {
|
let hr = unsafe {
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT,
|
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||||
ptr::from_mut(&mut bgra8unorm_info).cast(),
|
<*mut _>::cast(&mut bgra8unorm_info),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
|
mem::size_of_val(&bgra8unorm_info) as u32,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
hr == 0
|
hr.is_ok()
|
||||||
&& (bgra8unorm_info.Support2 & d3d12_ty::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE != 0)
|
&& bgra8unorm_info
|
||||||
|
.Support2
|
||||||
|
.contains(Direct3D12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)
|
||||||
};
|
};
|
||||||
features.set(
|
features.set(
|
||||||
wgt::Features::BGRA8UNORM_STORAGE,
|
wgt::Features::BGRA8UNORM_STORAGE,
|
||||||
bgra8unorm_storage_supported,
|
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 {
|
let hr = unsafe {
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_D3D12_OPTIONS1,
|
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS1,
|
||||||
ptr::from_mut(&mut features1).cast(),
|
<*mut _>::cast(&mut features1),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_D3D12_OPTIONS1>() as _,
|
mem::size_of_val(&features1) as u32,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
features.set(
|
features.set(
|
||||||
wgt::Features::SHADER_INT64,
|
wgt::Features::SHADER_INT64,
|
||||||
shader_model >= naga::back::hlsl::ShaderModel::V6_0
|
shader_model >= naga::back::hlsl::ShaderModel::V6_0
|
||||||
&& hr == 0
|
&& hr.is_ok()
|
||||||
&& features1.Int64ShaderOps != 0,
|
&& features1.Int64ShaderOps.as_bool(),
|
||||||
);
|
);
|
||||||
|
|
||||||
features.set(
|
features.set(
|
||||||
wgt::Features::SUBGROUP,
|
wgt::Features::SUBGROUP,
|
||||||
shader_model >= naga::back::hlsl::ShaderModel::V6_0
|
shader_model >= naga::back::hlsl::ShaderModel::V6_0
|
||||||
&& hr == 0
|
&& hr.is_ok()
|
||||||
&& features1.WaveOps != 0,
|
&& features1.WaveOps.as_bool(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let atomic_int64_on_typed_resource_supported = {
|
let atomic_int64_on_typed_resource_supported = {
|
||||||
let mut features9: crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS9 =
|
let mut features9 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS9::default();
|
||||||
unsafe { mem::zeroed() };
|
unsafe {
|
||||||
let hr = unsafe {
|
|
||||||
device.CheckFeatureSupport(
|
device.CheckFeatureSupport(
|
||||||
37, // D3D12_FEATURE_D3D12_OPTIONS9
|
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS9,
|
||||||
ptr::from_mut(&mut features9).cast(),
|
<*mut _>::cast(&mut features9),
|
||||||
mem::size_of::<crate::dx12::types::D3D12_FEATURE_DATA_D3D12_OPTIONS9>() as _,
|
mem::size_of_val(&features9) as u32,
|
||||||
)
|
)
|
||||||
};
|
}
|
||||||
hr == 0
|
.is_ok()
|
||||||
&& features9.AtomicInt64OnGroupSharedSupported != 0
|
&& features9.AtomicInt64OnGroupSharedSupported.as_bool()
|
||||||
&& features9.AtomicInt64OnTypedResourceSupported != 0
|
&& features9.AtomicInt64OnTypedResourceSupported.as_bool()
|
||||||
};
|
};
|
||||||
features.set(
|
features.set(
|
||||||
wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX,
|
wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX,
|
||||||
@ -424,11 +441,11 @@ impl super::Adapter {
|
|||||||
features,
|
features,
|
||||||
capabilities: crate::Capabilities {
|
capabilities: crate::Capabilities {
|
||||||
limits: wgt::Limits {
|
limits: wgt::Limits {
|
||||||
max_texture_dimension_1d: d3d12_ty::D3D12_REQ_TEXTURE1D_U_DIMENSION,
|
max_texture_dimension_1d: Direct3D12::D3D12_REQ_TEXTURE1D_U_DIMENSION,
|
||||||
max_texture_dimension_2d: d3d12_ty::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
max_texture_dimension_2d: Direct3D12::D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||||
.min(d3d12_ty::D3D12_REQ_TEXTURECUBE_DIMENSION),
|
.min(Direct3D12::D3D12_REQ_TEXTURECUBE_DIMENSION),
|
||||||
max_texture_dimension_3d: d3d12_ty::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
|
max_texture_dimension_3d: Direct3D12::D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
|
||||||
max_texture_array_layers: d3d12_ty::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
|
max_texture_array_layers: Direct3D12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
|
||||||
max_bind_groups: crate::MAX_BIND_GROUPS as u32,
|
max_bind_groups: crate::MAX_BIND_GROUPS as u32,
|
||||||
max_bindings_per_bind_group: 65535,
|
max_bindings_per_bind_group: 65535,
|
||||||
// dynamic offsets take a root constant, so we expose the minimum here
|
// 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: base
|
||||||
.max_dynamic_storage_buffers_per_pipeline_layout,
|
.max_dynamic_storage_buffers_per_pipeline_layout,
|
||||||
max_sampled_textures_per_shader_stage: match options.ResourceBindingTier {
|
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,
|
_ => full_heap_count,
|
||||||
},
|
},
|
||||||
max_samplers_per_shader_stage: match options.ResourceBindingTier {
|
max_samplers_per_shader_stage: match options.ResourceBindingTier {
|
||||||
d3d12_ty::D3D12_RESOURCE_BINDING_TIER_1 => 16,
|
Direct3D12::D3D12_RESOURCE_BINDING_TIER_1 => 16,
|
||||||
_ => d3d12_ty::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE,
|
_ => Direct3D12::D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE,
|
||||||
},
|
},
|
||||||
// these both account towards `uav_count`, but we can't express the limit as as sum
|
// 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
|
// 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_storage_textures_per_shader_stage: uav_count / 4,
|
||||||
max_uniform_buffers_per_shader_stage: full_heap_count,
|
max_uniform_buffers_per_shader_stage: full_heap_count,
|
||||||
max_uniform_buffer_binding_size:
|
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_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),
|
.min(crate::MAX_VERTEX_BUFFERS as u32),
|
||||||
max_vertex_attributes: d3d12_ty::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
|
max_vertex_attributes: Direct3D12::D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT,
|
||||||
max_vertex_buffer_array_stride: d3d12_ty::D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES,
|
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
|
min_subgroup_size: 4, // Not using `features1.WaveLaneCountMin` as it is unreliable
|
||||||
max_subgroup_size: 128,
|
max_subgroup_size: 128,
|
||||||
// The push constants are part of the root signature which
|
// 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
|
// Source: https://learn.microsoft.com/en-us/windows/win32/direct3d12/root-signature-limits#memory-limits-and-costs
|
||||||
max_push_constant_size: 128,
|
max_push_constant_size: 128,
|
||||||
min_uniform_buffer_offset_alignment:
|
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,
|
min_storage_buffer_offset_alignment: 4,
|
||||||
max_inter_stage_shader_components: base.max_inter_stage_shader_components,
|
max_inter_stage_shader_components: base.max_inter_stage_shader_components,
|
||||||
max_color_attachments,
|
max_color_attachments,
|
||||||
max_color_attachment_bytes_per_sample,
|
max_color_attachment_bytes_per_sample,
|
||||||
max_compute_workgroup_storage_size: base.max_compute_workgroup_storage_size, //TODO?
|
max_compute_workgroup_storage_size: base.max_compute_workgroup_storage_size, //TODO?
|
||||||
max_compute_invocations_per_workgroup:
|
max_compute_invocations_per_workgroup:
|
||||||
d3d12_ty::D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP,
|
Direct3D12::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_x: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_X,
|
||||||
max_compute_workgroup_size_y: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_Y,
|
max_compute_workgroup_size_y: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_Y,
|
||||||
max_compute_workgroup_size_z: d3d12_ty::D3D12_CS_THREAD_GROUP_MAX_Z,
|
max_compute_workgroup_size_z: Direct3D12::D3D12_CS_THREAD_GROUP_MAX_Z,
|
||||||
max_compute_workgroups_per_dimension:
|
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.
|
// Dx12 does not expose a maximum buffer size in the API.
|
||||||
// This limit is chosen to avoid potential issues with drivers should they internally
|
// 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).
|
// 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 {
|
alignments: crate::Alignments {
|
||||||
buffer_copy_offset: wgt::BufferSize::new(
|
buffer_copy_offset: wgt::BufferSize::new(
|
||||||
d3d12_ty::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64,
|
Direct3D12::D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT as u64,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
buffer_copy_pitch: wgt::BufferSize::new(
|
buffer_copy_pitch: wgt::BufferSize::new(
|
||||||
d3d12_ty::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
|
Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
},
|
||||||
@ -523,16 +540,18 @@ impl crate::Adapter for super::Adapter {
|
|||||||
limits: &wgt::Limits,
|
limits: &wgt::Limits,
|
||||||
memory_hints: &wgt::MemoryHints,
|
memory_hints: &wgt::MemoryHints,
|
||||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||||
let queue = {
|
let queue: Direct3D12::ID3D12CommandQueue = {
|
||||||
profiling::scope!("ID3D12Device::CreateCommandQueue");
|
profiling::scope!("ID3D12Device::CreateCommandQueue");
|
||||||
self.device
|
unsafe {
|
||||||
.create_command_queue(
|
self.device
|
||||||
d3d12::CmdListType::Direct,
|
.CreateCommandQueue(&Direct3D12::D3D12_COMMAND_QUEUE_DESC {
|
||||||
d3d12::Priority::Normal,
|
Type: Direct3D12::D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
d3d12::CommandQueueFlags::empty(),
|
Priority: Direct3D12::D3D12_COMMAND_QUEUE_PRIORITY_NORMAL.0,
|
||||||
0,
|
Flags: Direct3D12::D3D12_COMMAND_QUEUE_FLAG_NONE,
|
||||||
)
|
NodeMask: 0,
|
||||||
.into_device_result("Queue creation")?
|
})
|
||||||
|
}
|
||||||
|
.into_device_result("Queue creation")?
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = super::Device::new(
|
let device = super::Device::new(
|
||||||
@ -577,99 +596,118 @@ impl crate::Adapter for super::Adapter {
|
|||||||
}
|
}
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut data = d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
|
let mut data = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT {
|
||||||
Format: raw_format,
|
Format: raw_format,
|
||||||
Support1: unsafe { mem::zeroed() },
|
..Default::default()
|
||||||
Support2: unsafe { mem::zeroed() },
|
|
||||||
};
|
};
|
||||||
assert_eq!(winerror::S_OK, unsafe {
|
unsafe {
|
||||||
self.device.CheckFeatureSupport(
|
self.device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT,
|
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||||
ptr::from_mut(&mut data).cast(),
|
<*mut _>::cast(&mut data),
|
||||||
mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as _,
|
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
|
// 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.
|
// 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,
|
Format: srv_uav_format,
|
||||||
Support1: d3d12_ty::D3D12_FORMAT_SUPPORT1_NONE,
|
Support1: Direct3D12::D3D12_FORMAT_SUPPORT1_NONE,
|
||||||
Support2: d3d12_ty::D3D12_FORMAT_SUPPORT2_NONE,
|
Support2: Direct3D12::D3D12_FORMAT_SUPPORT2_NONE,
|
||||||
};
|
};
|
||||||
if raw_format != srv_uav_format {
|
if raw_format != srv_uav_format {
|
||||||
// Only-recheck if we're using a different format
|
// Only-recheck if we're using a different format
|
||||||
assert_eq!(winerror::S_OK, unsafe {
|
unsafe {
|
||||||
self.device.CheckFeatureSupport(
|
self.device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_FORMAT_SUPPORT,
|
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||||
ptr::addr_of_mut!(data_srv_uav).cast(),
|
ptr::addr_of_mut!(data_srv_uav).cast(),
|
||||||
DWORD::try_from(mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_FORMAT_SUPPORT>())
|
mem::size_of::<Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as u32,
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
});
|
}
|
||||||
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
// Same format, just copy over.
|
// Same format, just copy over.
|
||||||
data_srv_uav = data;
|
data_srv_uav = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut caps = Tfc::COPY_SRC | Tfc::COPY_DST;
|
let mut caps = Tfc::COPY_SRC | Tfc::COPY_DST;
|
||||||
let is_texture = data.Support1
|
// Cannot use the contains() helper, and windows-rs doesn't provide a .intersect() helper
|
||||||
& (d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE1D
|
let is_texture = (data.Support1
|
||||||
| d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE2D
|
& (Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE1D
|
||||||
| d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURE3D
|
| Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE2D
|
||||||
| d3d12_ty::D3D12_FORMAT_SUPPORT1_TEXTURECUBE)
|
| Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE3D
|
||||||
|
| Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE))
|
||||||
|
.0
|
||||||
!= 0;
|
!= 0;
|
||||||
// SRVs use srv_uav_format
|
// SRVs use srv_uav_format
|
||||||
caps.set(
|
caps.set(
|
||||||
Tfc::SAMPLED,
|
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(
|
caps.set(
|
||||||
Tfc::SAMPLED_LINEAR,
|
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(
|
caps.set(
|
||||||
Tfc::COLOR_ATTACHMENT,
|
Tfc::COLOR_ATTACHMENT,
|
||||||
data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_RENDER_TARGET != 0,
|
data.Support1
|
||||||
|
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET),
|
||||||
);
|
);
|
||||||
caps.set(
|
caps.set(
|
||||||
Tfc::COLOR_ATTACHMENT_BLEND,
|
Tfc::COLOR_ATTACHMENT_BLEND,
|
||||||
data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_BLENDABLE != 0,
|
data.Support1
|
||||||
|
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_BLENDABLE),
|
||||||
);
|
);
|
||||||
caps.set(
|
caps.set(
|
||||||
Tfc::DEPTH_STENCIL_ATTACHMENT,
|
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
|
// UAVs use srv_uav_format
|
||||||
caps.set(
|
caps.set(
|
||||||
Tfc::STORAGE,
|
Tfc::STORAGE,
|
||||||
data_srv_uav.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW
|
data_srv_uav
|
||||||
!= 0,
|
.Support1
|
||||||
|
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW),
|
||||||
);
|
);
|
||||||
caps.set(
|
caps.set(
|
||||||
Tfc::STORAGE_READ_WRITE,
|
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
|
// We load via UAV/SRV so use srv_uav_format
|
||||||
let no_msaa_load = caps.contains(Tfc::SAMPLED)
|
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
|
let no_msaa_target = (data.Support1
|
||||||
& (d3d12_ty::D3D12_FORMAT_SUPPORT1_RENDER_TARGET
|
& (Direct3D12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET
|
||||||
| d3d12_ty::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)
|
| Direct3D12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL))
|
||||||
|
.0
|
||||||
!= 0
|
!= 0
|
||||||
&& data.Support1 & d3d12_ty::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET == 0;
|
&& !data
|
||||||
|
.Support1
|
||||||
|
.contains(Direct3D12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET);
|
||||||
|
|
||||||
caps.set(
|
caps.set(
|
||||||
Tfc::MULTISAMPLE_RESOLVE,
|
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,
|
Format: raw_format,
|
||||||
SampleCount: 0,
|
SampleCount: 0,
|
||||||
Flags: d3d12_ty::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE,
|
Flags: Direct3D12::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE,
|
||||||
NumQualityLevels: 0,
|
NumQualityLevels: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -678,11 +716,12 @@ impl crate::Adapter for super::Adapter {
|
|||||||
|
|
||||||
if unsafe {
|
if unsafe {
|
||||||
self.device.CheckFeatureSupport(
|
self.device.CheckFeatureSupport(
|
||||||
d3d12_ty::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
|
Direct3D12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
|
||||||
<*mut _>::cast(&mut ms_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
|
&& ms_levels.NumQualityLevels != 0
|
||||||
{
|
{
|
||||||
caps.set(tfc, !no_msaa_load && !no_msaa_target);
|
caps.set(tfc, !no_msaa_load && !no_msaa_target);
|
||||||
@ -704,8 +743,9 @@ impl crate::Adapter for super::Adapter {
|
|||||||
let current_extent = {
|
let current_extent = {
|
||||||
match surface.target {
|
match surface.target {
|
||||||
SurfaceTarget::WndHandle(wnd_handle) => {
|
SurfaceTarget::WndHandle(wnd_handle) => {
|
||||||
let mut rect: windef::RECT = unsafe { mem::zeroed() };
|
let mut rect = Default::default();
|
||||||
if unsafe { winuser::GetClientRect(wnd_handle, &mut rect) } != 0 {
|
if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok()
|
||||||
|
{
|
||||||
Some(wgt::Extent3d {
|
Some(wgt::Extent3d {
|
||||||
width: (rect.right - rect.left) as u32,
|
width: (rect.right - rect.left) as u32,
|
||||||
height: (rect.bottom - rect.top) 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 windows::Win32::Graphics::{Direct3D, Direct3D12};
|
||||||
use winapi::{
|
|
||||||
shared::minwindef::BOOL,
|
|
||||||
um::{d3d12 as d3d12_ty, d3dcommon},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn map_buffer_usage_to_resource_flags(
|
pub fn map_buffer_usage_to_resource_flags(
|
||||||
usage: crate::BufferUses,
|
usage: crate::BufferUses,
|
||||||
) -> d3d12_ty::D3D12_RESOURCE_FLAGS {
|
) -> Direct3D12::D3D12_RESOURCE_FLAGS {
|
||||||
let mut flags = 0;
|
let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE;
|
||||||
if usage.contains(crate::BufferUses::STORAGE_READ_WRITE) {
|
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
|
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 {
|
match dim {
|
||||||
wgt::TextureDimension::D1 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE1D,
|
wgt::TextureDimension::D1 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE1D,
|
||||||
wgt::TextureDimension::D2 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
wgt::TextureDimension::D2 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||||
wgt::TextureDimension::D3 => d3d12_ty::D3D12_RESOURCE_DIMENSION_TEXTURE3D,
|
wgt::TextureDimension::D3 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE3D,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_texture_usage_to_resource_flags(
|
pub fn map_texture_usage_to_resource_flags(
|
||||||
usage: crate::TextureUses,
|
usage: crate::TextureUses,
|
||||||
) -> d3d12_ty::D3D12_RESOURCE_FLAGS {
|
) -> Direct3D12::D3D12_RESOURCE_FLAGS {
|
||||||
let mut flags = 0;
|
let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
if usage.contains(crate::TextureUses::COLOR_TARGET) {
|
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(
|
if usage.intersects(
|
||||||
crate::TextureUses::DEPTH_STENCIL_READ | crate::TextureUses::DEPTH_STENCIL_WRITE,
|
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) {
|
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) {
|
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
|
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;
|
use wgt::AddressMode as Am;
|
||||||
match mode {
|
match mode {
|
||||||
Am::Repeat => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
Am::Repeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||||
Am::MirrorRepeat => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
|
Am::MirrorRepeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
|
||||||
Am::ClampToEdge => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
|
Am::ClampToEdge => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
|
||||||
Am::ClampToBorder => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_BORDER,
|
Am::ClampToBorder => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_BORDER,
|
||||||
//Am::MirrorClamp => d3d12_ty::D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
|
//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 {
|
match mode {
|
||||||
wgt::FilterMode::Nearest => d3d12_ty::D3D12_FILTER_TYPE_POINT,
|
wgt::FilterMode::Nearest => Direct3D12::D3D12_FILTER_TYPE_POINT,
|
||||||
wgt::FilterMode::Linear => d3d12_ty::D3D12_FILTER_TYPE_LINEAR,
|
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;
|
use wgt::CompareFunction as Cf;
|
||||||
match func {
|
match func {
|
||||||
Cf::Never => d3d12_ty::D3D12_COMPARISON_FUNC_NEVER,
|
Cf::Never => Direct3D12::D3D12_COMPARISON_FUNC_NEVER,
|
||||||
Cf::Less => d3d12_ty::D3D12_COMPARISON_FUNC_LESS,
|
Cf::Less => Direct3D12::D3D12_COMPARISON_FUNC_LESS,
|
||||||
Cf::LessEqual => d3d12_ty::D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
Cf::LessEqual => Direct3D12::D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
||||||
Cf::Equal => d3d12_ty::D3D12_COMPARISON_FUNC_EQUAL,
|
Cf::Equal => Direct3D12::D3D12_COMPARISON_FUNC_EQUAL,
|
||||||
Cf::GreaterEqual => d3d12_ty::D3D12_COMPARISON_FUNC_GREATER_EQUAL,
|
Cf::GreaterEqual => Direct3D12::D3D12_COMPARISON_FUNC_GREATER_EQUAL,
|
||||||
Cf::Greater => d3d12_ty::D3D12_COMPARISON_FUNC_GREATER,
|
Cf::Greater => Direct3D12::D3D12_COMPARISON_FUNC_GREATER,
|
||||||
Cf::NotEqual => d3d12_ty::D3D12_COMPARISON_FUNC_NOT_EQUAL,
|
Cf::NotEqual => Direct3D12::D3D12_COMPARISON_FUNC_NOT_EQUAL,
|
||||||
Cf::Always => d3d12_ty::D3D12_COMPARISON_FUNC_ALWAYS,
|
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 {
|
match visibility {
|
||||||
wgt::ShaderStages::VERTEX => d3d12::ShaderVisibility::VS,
|
wgt::ShaderStages::VERTEX => Direct3D12::D3D12_SHADER_VISIBILITY_VERTEX,
|
||||||
wgt::ShaderStages::FRAGMENT => d3d12::ShaderVisibility::PS,
|
wgt::ShaderStages::FRAGMENT => Direct3D12::D3D12_SHADER_VISIBILITY_PIXEL,
|
||||||
_ => d3d12::ShaderVisibility::All,
|
_ => 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;
|
use wgt::BindingType as Bt;
|
||||||
match *ty {
|
match *ty {
|
||||||
Bt::Sampler { .. } => d3d12::DescriptorRangeType::Sampler,
|
Bt::Sampler { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
|
||||||
Bt::Buffer {
|
Bt::Buffer {
|
||||||
ty: wgt::BufferBindingType::Uniform,
|
ty: wgt::BufferBindingType::Uniform,
|
||||||
..
|
..
|
||||||
} => d3d12::DescriptorRangeType::CBV,
|
} => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
|
||||||
Bt::Buffer {
|
Bt::Buffer {
|
||||||
ty: wgt::BufferBindingType::Storage { read_only: true },
|
ty: wgt::BufferBindingType::Storage { read_only: true },
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
| Bt::Texture { .. } => d3d12::DescriptorRangeType::SRV,
|
| Bt::Texture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
|
||||||
Bt::Buffer {
|
Bt::Buffer {
|
||||||
ty: wgt::BufferBindingType::Storage { read_only: false },
|
ty: wgt::BufferBindingType::Storage { read_only: false },
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
| Bt::StorageTexture { .. } => d3d12::DescriptorRangeType::UAV,
|
| Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
|
||||||
Bt::AccelerationStructure => todo!(),
|
Bt::AccelerationStructure => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_label(name: &str) -> Vec<u16> {
|
pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> Direct3D12::D3D12_RESOURCE_STATES {
|
||||||
name.encode_utf16().chain(iter::once(0)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> d3d12_ty::D3D12_RESOURCE_STATES {
|
|
||||||
use crate::BufferUses as Bu;
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
} else if usage.intersects(Bu::STORAGE_READ) {
|
||||||
state |= d3d12_ty::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
|
state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
|
||||||
| d3d12_ty::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
| Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||||
}
|
}
|
||||||
if usage.intersects(Bu::INDIRECT) {
|
if usage.intersects(Bu::INDIRECT) {
|
||||||
state |= d3d12_ty::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
|
state |= Direct3D12::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
|
||||||
}
|
}
|
||||||
state
|
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;
|
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: `RESOLVE_SOURCE` and `RESOLVE_DEST` are not used here
|
||||||
//Note: `PRESENT` is the same as `COMMON`
|
//Note: `PRESENT` is the same as `COMMON`
|
||||||
if usage == crate::TextureUses::UNINITIALIZED {
|
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) {
|
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) {
|
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) {
|
if usage.intersects(Tu::RESOURCE) {
|
||||||
state |= d3d12_ty::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
|
state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
|
||||||
| d3d12_ty::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
| Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||||
}
|
}
|
||||||
if usage.intersects(Tu::COLOR_TARGET) {
|
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) {
|
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) {
|
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) {
|
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
|
state
|
||||||
}
|
}
|
||||||
@ -185,37 +177,37 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12_ty::D3D12_
|
|||||||
pub fn map_topology(
|
pub fn map_topology(
|
||||||
topology: wgt::PrimitiveTopology,
|
topology: wgt::PrimitiveTopology,
|
||||||
) -> (
|
) -> (
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE,
|
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE,
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY,
|
Direct3D::D3D_PRIMITIVE_TOPOLOGY,
|
||||||
) {
|
) {
|
||||||
match topology {
|
match topology {
|
||||||
wgt::PrimitiveTopology::PointList => (
|
wgt::PrimitiveTopology::PointList => (
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
|
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
|
||||||
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
|
Direct3D::D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
|
||||||
),
|
),
|
||||||
wgt::PrimitiveTopology::LineList => (
|
wgt::PrimitiveTopology::LineList => (
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
|
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
|
||||||
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_LINELIST,
|
Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINELIST,
|
||||||
),
|
),
|
||||||
wgt::PrimitiveTopology::LineStrip => (
|
wgt::PrimitiveTopology::LineStrip => (
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
|
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
|
||||||
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
|
Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
|
||||||
),
|
),
|
||||||
wgt::PrimitiveTopology::TriangleList => (
|
wgt::PrimitiveTopology::TriangleList => (
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
||||||
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
|
Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
|
||||||
),
|
),
|
||||||
wgt::PrimitiveTopology::TriangleStrip => (
|
wgt::PrimitiveTopology::TriangleStrip => (
|
||||||
d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
||||||
d3dcommon::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
|
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 {
|
match mode {
|
||||||
wgt::PolygonMode::Fill => d3d12_ty::D3D12_FILL_MODE_SOLID,
|
wgt::PolygonMode::Fill => Direct3D12::D3D12_FILL_MODE_SOLID,
|
||||||
wgt::PolygonMode::Line => d3d12_ty::D3D12_FILL_MODE_WIREFRAME,
|
wgt::PolygonMode::Line => Direct3D12::D3D12_FILL_MODE_WIREFRAME,
|
||||||
wgt::PolygonMode::Point => panic!(
|
wgt::PolygonMode::Point => panic!(
|
||||||
"{:?} is not enabled for this backend",
|
"{:?} is not enabled for this backend",
|
||||||
wgt::Features::POLYGON_MODE_POINT
|
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>).
|
/// (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
|
/// Therefore this function takes an additional `is_alpha` argument
|
||||||
/// which if set will return an equivalent `_ALPHA` factor.
|
/// 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;
|
use wgt::BlendFactor as Bf;
|
||||||
match factor {
|
match factor {
|
||||||
Bf::Zero => d3d12_ty::D3D12_BLEND_ZERO,
|
Bf::Zero => Direct3D12::D3D12_BLEND_ZERO,
|
||||||
Bf::One => d3d12_ty::D3D12_BLEND_ONE,
|
Bf::One => Direct3D12::D3D12_BLEND_ONE,
|
||||||
Bf::Src if is_alpha => d3d12_ty::D3D12_BLEND_SRC_ALPHA,
|
Bf::Src if is_alpha => Direct3D12::D3D12_BLEND_SRC_ALPHA,
|
||||||
Bf::Src => d3d12_ty::D3D12_BLEND_SRC_COLOR,
|
Bf::Src => Direct3D12::D3D12_BLEND_SRC_COLOR,
|
||||||
Bf::OneMinusSrc if is_alpha => d3d12_ty::D3D12_BLEND_INV_SRC_ALPHA,
|
Bf::OneMinusSrc if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA,
|
||||||
Bf::OneMinusSrc => d3d12_ty::D3D12_BLEND_INV_SRC_COLOR,
|
Bf::OneMinusSrc => Direct3D12::D3D12_BLEND_INV_SRC_COLOR,
|
||||||
Bf::Dst if is_alpha => d3d12_ty::D3D12_BLEND_DEST_ALPHA,
|
Bf::Dst if is_alpha => Direct3D12::D3D12_BLEND_DEST_ALPHA,
|
||||||
Bf::Dst => d3d12_ty::D3D12_BLEND_DEST_COLOR,
|
Bf::Dst => Direct3D12::D3D12_BLEND_DEST_COLOR,
|
||||||
Bf::OneMinusDst if is_alpha => d3d12_ty::D3D12_BLEND_INV_DEST_ALPHA,
|
Bf::OneMinusDst if is_alpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA,
|
||||||
Bf::OneMinusDst => d3d12_ty::D3D12_BLEND_INV_DEST_COLOR,
|
Bf::OneMinusDst => Direct3D12::D3D12_BLEND_INV_DEST_COLOR,
|
||||||
Bf::SrcAlpha => d3d12_ty::D3D12_BLEND_SRC_ALPHA,
|
Bf::SrcAlpha => Direct3D12::D3D12_BLEND_SRC_ALPHA,
|
||||||
Bf::OneMinusSrcAlpha => d3d12_ty::D3D12_BLEND_INV_SRC_ALPHA,
|
Bf::OneMinusSrcAlpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA,
|
||||||
Bf::DstAlpha => d3d12_ty::D3D12_BLEND_DEST_ALPHA,
|
Bf::DstAlpha => Direct3D12::D3D12_BLEND_DEST_ALPHA,
|
||||||
Bf::OneMinusDstAlpha => d3d12_ty::D3D12_BLEND_INV_DEST_ALPHA,
|
Bf::OneMinusDstAlpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA,
|
||||||
Bf::Constant => d3d12_ty::D3D12_BLEND_BLEND_FACTOR,
|
Bf::Constant => Direct3D12::D3D12_BLEND_BLEND_FACTOR,
|
||||||
Bf::OneMinusConstant => d3d12_ty::D3D12_BLEND_INV_BLEND_FACTOR,
|
Bf::OneMinusConstant => Direct3D12::D3D12_BLEND_INV_BLEND_FACTOR,
|
||||||
Bf::SrcAlphaSaturated => d3d12_ty::D3D12_BLEND_SRC_ALPHA_SAT,
|
Bf::SrcAlphaSaturated => Direct3D12::D3D12_BLEND_SRC_ALPHA_SAT,
|
||||||
Bf::Src1 if is_alpha => d3d12_ty::D3D12_BLEND_SRC1_ALPHA,
|
Bf::Src1 if is_alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA,
|
||||||
Bf::Src1 => d3d12_ty::D3D12_BLEND_SRC1_COLOR,
|
Bf::Src1 => Direct3D12::D3D12_BLEND_SRC1_COLOR,
|
||||||
Bf::OneMinusSrc1 if is_alpha => d3d12_ty::D3D12_BLEND_INV_SRC1_ALPHA,
|
Bf::OneMinusSrc1 if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA,
|
||||||
Bf::OneMinusSrc1 => d3d12_ty::D3D12_BLEND_INV_SRC1_COLOR,
|
Bf::OneMinusSrc1 => Direct3D12::D3D12_BLEND_INV_SRC1_COLOR,
|
||||||
Bf::Src1Alpha => d3d12_ty::D3D12_BLEND_SRC1_ALPHA,
|
Bf::Src1Alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA,
|
||||||
Bf::OneMinusSrc1Alpha => d3d12_ty::D3D12_BLEND_INV_SRC1_ALPHA,
|
Bf::OneMinusSrc1Alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,16 +252,16 @@ fn map_blend_component(
|
|||||||
component: &wgt::BlendComponent,
|
component: &wgt::BlendComponent,
|
||||||
is_alpha: bool,
|
is_alpha: bool,
|
||||||
) -> (
|
) -> (
|
||||||
d3d12_ty::D3D12_BLEND_OP,
|
Direct3D12::D3D12_BLEND_OP,
|
||||||
d3d12_ty::D3D12_BLEND,
|
Direct3D12::D3D12_BLEND,
|
||||||
d3d12_ty::D3D12_BLEND,
|
Direct3D12::D3D12_BLEND,
|
||||||
) {
|
) {
|
||||||
let raw_op = match component.operation {
|
let raw_op = match component.operation {
|
||||||
wgt::BlendOperation::Add => d3d12_ty::D3D12_BLEND_OP_ADD,
|
wgt::BlendOperation::Add => Direct3D12::D3D12_BLEND_OP_ADD,
|
||||||
wgt::BlendOperation::Subtract => d3d12_ty::D3D12_BLEND_OP_SUBTRACT,
|
wgt::BlendOperation::Subtract => Direct3D12::D3D12_BLEND_OP_SUBTRACT,
|
||||||
wgt::BlendOperation::ReverseSubtract => d3d12_ty::D3D12_BLEND_OP_REV_SUBTRACT,
|
wgt::BlendOperation::ReverseSubtract => Direct3D12::D3D12_BLEND_OP_REV_SUBTRACT,
|
||||||
wgt::BlendOperation::Min => d3d12_ty::D3D12_BLEND_OP_MIN,
|
wgt::BlendOperation::Min => Direct3D12::D3D12_BLEND_OP_MIN,
|
||||||
wgt::BlendOperation::Max => d3d12_ty::D3D12_BLEND_OP_MAX,
|
wgt::BlendOperation::Max => Direct3D12::D3D12_BLEND_OP_MAX,
|
||||||
};
|
};
|
||||||
let raw_src = map_blend_factor(component.src_factor, is_alpha);
|
let raw_src = map_blend_factor(component.src_factor, is_alpha);
|
||||||
let raw_dst = map_blend_factor(component.dst_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(
|
pub fn map_render_targets(
|
||||||
color_targets: &[Option<wgt::ColorTargetState>],
|
color_targets: &[Option<wgt::ColorTargetState>],
|
||||||
) -> [d3d12_ty::D3D12_RENDER_TARGET_BLEND_DESC;
|
) -> [Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC;
|
||||||
d3d12_ty::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] {
|
Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] {
|
||||||
let dummy_target = d3d12_ty::D3D12_RENDER_TARGET_BLEND_DESC {
|
let dummy_target = Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC {
|
||||||
BlendEnable: 0,
|
BlendEnable: false.into(),
|
||||||
LogicOpEnable: 0,
|
LogicOpEnable: false.into(),
|
||||||
SrcBlend: d3d12_ty::D3D12_BLEND_ZERO,
|
SrcBlend: Direct3D12::D3D12_BLEND_ZERO,
|
||||||
DestBlend: d3d12_ty::D3D12_BLEND_ZERO,
|
DestBlend: Direct3D12::D3D12_BLEND_ZERO,
|
||||||
BlendOp: d3d12_ty::D3D12_BLEND_OP_ADD,
|
BlendOp: Direct3D12::D3D12_BLEND_OP_ADD,
|
||||||
SrcBlendAlpha: d3d12_ty::D3D12_BLEND_ZERO,
|
SrcBlendAlpha: Direct3D12::D3D12_BLEND_ZERO,
|
||||||
DestBlendAlpha: d3d12_ty::D3D12_BLEND_ZERO,
|
DestBlendAlpha: Direct3D12::D3D12_BLEND_ZERO,
|
||||||
BlendOpAlpha: d3d12_ty::D3D12_BLEND_OP_ADD,
|
BlendOpAlpha: Direct3D12::D3D12_BLEND_OP_ADD,
|
||||||
LogicOp: d3d12_ty::D3D12_LOGIC_OP_CLEAR,
|
LogicOp: Direct3D12::D3D12_LOGIC_OP_CLEAR,
|
||||||
RenderTargetWriteMask: 0,
|
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()) {
|
for (raw, ct) in raw_targets.iter_mut().zip(color_targets.iter()) {
|
||||||
if let Some(ct) = ct.as_ref() {
|
if let Some(ct) = ct.as_ref() {
|
||||||
@ -300,7 +293,7 @@ pub fn map_render_targets(
|
|||||||
if let Some(ref blend) = ct.blend {
|
if let Some(ref blend) = ct.blend {
|
||||||
let (color_op, color_src, color_dst) = map_blend_component(&blend.color, false);
|
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);
|
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.BlendOp = color_op;
|
||||||
raw.SrcBlend = color_src;
|
raw.SrcBlend = color_src;
|
||||||
raw.DestBlend = color_dst;
|
raw.DestBlend = color_dst;
|
||||||
@ -314,22 +307,22 @@ pub fn map_render_targets(
|
|||||||
raw_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;
|
use wgt::StencilOperation as So;
|
||||||
match op {
|
match op {
|
||||||
So::Keep => d3d12_ty::D3D12_STENCIL_OP_KEEP,
|
So::Keep => Direct3D12::D3D12_STENCIL_OP_KEEP,
|
||||||
So::Zero => d3d12_ty::D3D12_STENCIL_OP_ZERO,
|
So::Zero => Direct3D12::D3D12_STENCIL_OP_ZERO,
|
||||||
So::Replace => d3d12_ty::D3D12_STENCIL_OP_REPLACE,
|
So::Replace => Direct3D12::D3D12_STENCIL_OP_REPLACE,
|
||||||
So::IncrementClamp => d3d12_ty::D3D12_STENCIL_OP_INCR_SAT,
|
So::IncrementClamp => Direct3D12::D3D12_STENCIL_OP_INCR_SAT,
|
||||||
So::IncrementWrap => d3d12_ty::D3D12_STENCIL_OP_INCR,
|
So::IncrementWrap => Direct3D12::D3D12_STENCIL_OP_INCR,
|
||||||
So::DecrementClamp => d3d12_ty::D3D12_STENCIL_OP_DECR_SAT,
|
So::DecrementClamp => Direct3D12::D3D12_STENCIL_OP_DECR_SAT,
|
||||||
So::DecrementWrap => d3d12_ty::D3D12_STENCIL_OP_DECR,
|
So::DecrementWrap => Direct3D12::D3D12_STENCIL_OP_DECR,
|
||||||
So::Invert => d3d12_ty::D3D12_STENCIL_OP_INVERT,
|
So::Invert => Direct3D12::D3D12_STENCIL_OP_INVERT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_stencil_face(face: &wgt::StencilFaceState) -> d3d12_ty::D3D12_DEPTH_STENCILOP_DESC {
|
fn map_stencil_face(face: &wgt::StencilFaceState) -> Direct3D12::D3D12_DEPTH_STENCILOP_DESC {
|
||||||
d3d12_ty::D3D12_DEPTH_STENCILOP_DESC {
|
Direct3D12::D3D12_DEPTH_STENCILOP_DESC {
|
||||||
StencilFailOp: map_stencil_op(face.fail_op),
|
StencilFailOp: map_stencil_op(face.fail_op),
|
||||||
StencilDepthFailOp: map_stencil_op(face.depth_fail_op),
|
StencilDepthFailOp: map_stencil_op(face.depth_fail_op),
|
||||||
StencilPassOp: map_stencil_op(face.pass_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 {
|
pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> Direct3D12::D3D12_DEPTH_STENCIL_DESC {
|
||||||
d3d12_ty::D3D12_DEPTH_STENCIL_DESC {
|
Direct3D12::D3D12_DEPTH_STENCIL_DESC {
|
||||||
DepthEnable: BOOL::from(ds.is_depth_enabled()),
|
DepthEnable: ds.is_depth_enabled().into(),
|
||||||
DepthWriteMask: if ds.depth_write_enabled {
|
DepthWriteMask: if ds.depth_write_enabled {
|
||||||
d3d12_ty::D3D12_DEPTH_WRITE_MASK_ALL
|
Direct3D12::D3D12_DEPTH_WRITE_MASK_ALL
|
||||||
} else {
|
} else {
|
||||||
d3d12_ty::D3D12_DEPTH_WRITE_MASK_ZERO
|
Direct3D12::D3D12_DEPTH_WRITE_MASK_ZERO
|
||||||
},
|
},
|
||||||
DepthFunc: map_comparison(ds.depth_compare),
|
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,
|
StencilReadMask: ds.stencil.read_mask as u8,
|
||||||
StencilWriteMask: ds.stencil.write_mask as u8,
|
StencilWriteMask: ds.stencil.write_mask as u8,
|
||||||
FrontFace: map_stencil_face(&ds.stencil.front),
|
FrontFace: map_stencil_face(&ds.stencil.front),
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
use super::null_comptr_check;
|
use std::fmt;
|
||||||
use crate::auxil::dxgi::result::HResult as _;
|
|
||||||
use bit_set::BitSet;
|
use bit_set::BitSet;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use range_alloc::RangeAllocator;
|
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;
|
const HEAP_SIZE_FIXED: usize = 64;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(super) struct DualHandle {
|
pub(super) struct DualHandle {
|
||||||
cpu: d3d12::CpuDescriptor,
|
cpu: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
||||||
pub gpu: d3d12::GpuDescriptor,
|
pub gpu: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE,
|
||||||
/// How large the block allocated to this handle is.
|
/// How large the block allocated to this handle is.
|
||||||
count: u64,
|
count: u64,
|
||||||
}
|
}
|
||||||
@ -28,8 +30,8 @@ impl fmt::Debug for DualHandle {
|
|||||||
type DescriptorIndex = u64;
|
type DescriptorIndex = u64;
|
||||||
|
|
||||||
pub(super) struct GeneralHeap {
|
pub(super) struct GeneralHeap {
|
||||||
pub raw: d3d12::DescriptorHeap,
|
pub raw: Direct3D12::ID3D12DescriptorHeap,
|
||||||
ty: d3d12::DescriptorHeapType,
|
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
||||||
handle_size: u64,
|
handle_size: u64,
|
||||||
total_handles: u64,
|
total_handles: u64,
|
||||||
start: DualHandle,
|
start: DualHandle,
|
||||||
@ -38,32 +40,30 @@ pub(super) struct GeneralHeap {
|
|||||||
|
|
||||||
impl GeneralHeap {
|
impl GeneralHeap {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
device: d3d12::Device,
|
device: &Direct3D12::ID3D12Device,
|
||||||
ty: d3d12::DescriptorHeapType,
|
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
||||||
total_handles: u64,
|
total_handles: u64,
|
||||||
) -> Result<Self, crate::DeviceError> {
|
) -> Result<Self, crate::DeviceError> {
|
||||||
let raw = {
|
let raw = {
|
||||||
profiling::scope!("ID3D12Device::CreateDescriptorHeap");
|
profiling::scope!("ID3D12Device::CreateDescriptorHeap");
|
||||||
device
|
let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC {
|
||||||
.create_descriptor_heap(
|
Type: ty,
|
||||||
total_handles as u32,
|
NumDescriptors: total_handles as u32,
|
||||||
ty,
|
Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
|
||||||
d3d12::DescriptorHeapFlags::SHADER_VISIBLE,
|
NodeMask: 0,
|
||||||
0,
|
};
|
||||||
)
|
unsafe { device.CreateDescriptorHeap::<Direct3D12::ID3D12DescriptorHeap>(&desc) }
|
||||||
.into_device_result("Descriptor heap creation")?
|
.into_device_result("Descriptor heap creation")?
|
||||||
};
|
};
|
||||||
|
|
||||||
null_comptr_check(&raw)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
raw: raw.clone(),
|
raw: raw.clone(),
|
||||||
ty,
|
ty,
|
||||||
handle_size: device.get_descriptor_increment_size(ty) as u64,
|
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as u64,
|
||||||
total_handles,
|
total_handles,
|
||||||
start: DualHandle {
|
start: DualHandle {
|
||||||
cpu: raw.start_cpu_descriptor(),
|
cpu: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
|
||||||
gpu: raw.start_gpu_descriptor(),
|
gpu: unsafe { raw.GetGPUDescriptorHandleForHeapStart() },
|
||||||
count: 0,
|
count: 0,
|
||||||
},
|
},
|
||||||
ranges: Mutex::new(RangeAllocator::new(0..total_handles)),
|
ranges: Mutex::new(RangeAllocator::new(0..total_handles)),
|
||||||
@ -79,14 +79,14 @@ impl GeneralHeap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpu_descriptor_at(&self, index: u64) -> d3d12::CpuDescriptor {
|
fn cpu_descriptor_at(&self, index: u64) -> Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
|
||||||
d3d12::CpuDescriptor {
|
Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
|
||||||
ptr: self.start.cpu.ptr + (self.handle_size * index) as usize,
|
ptr: self.start.cpu.ptr + (self.handle_size * index) as usize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gpu_descriptor_at(&self, index: u64) -> d3d12::GpuDescriptor {
|
fn gpu_descriptor_at(&self, index: u64) -> Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE {
|
||||||
d3d12::GpuDescriptor {
|
Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE {
|
||||||
ptr: self.start.gpu.ptr + self.handle_size * index,
|
ptr: self.start.gpu.ptr + self.handle_size * index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,41 +109,42 @@ impl GeneralHeap {
|
|||||||
|
|
||||||
/// Fixed-size free-list allocator for CPU descriptors.
|
/// Fixed-size free-list allocator for CPU descriptors.
|
||||||
struct FixedSizeHeap {
|
struct FixedSizeHeap {
|
||||||
_raw: d3d12::DescriptorHeap,
|
_raw: Direct3D12::ID3D12DescriptorHeap,
|
||||||
/// Bit flag representation of available handles in the heap.
|
/// Bit flag representation of available handles in the heap.
|
||||||
///
|
///
|
||||||
/// 0 - Occupied
|
/// 0 - Occupied
|
||||||
/// 1 - free
|
/// 1 - free
|
||||||
availability: u64,
|
availability: u64,
|
||||||
handle_size: usize,
|
handle_size: usize,
|
||||||
start: d3d12::CpuDescriptor,
|
start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FixedSizeHeap {
|
impl FixedSizeHeap {
|
||||||
fn new(
|
fn new(
|
||||||
device: &d3d12::Device,
|
device: &Direct3D12::ID3D12Device,
|
||||||
ty: d3d12::DescriptorHeapType,
|
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
||||||
) -> Result<Self, crate::DeviceError> {
|
) -> Result<Self, crate::DeviceError> {
|
||||||
let heap = device
|
let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC {
|
||||||
.create_descriptor_heap(
|
Type: ty,
|
||||||
HEAP_SIZE_FIXED as _,
|
NumDescriptors: HEAP_SIZE_FIXED as u32,
|
||||||
ty,
|
Flags: Direct3D12::D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
|
||||||
d3d12::DescriptorHeapFlags::empty(),
|
NodeMask: 0,
|
||||||
0,
|
};
|
||||||
)
|
let heap =
|
||||||
.into_device_result("Descriptor heap creation")?;
|
unsafe { device.CreateDescriptorHeap::<Direct3D12::ID3D12DescriptorHeap>(&desc) }
|
||||||
|
.into_device_result("Descriptor heap creation")?;
|
||||||
null_comptr_check(&heap)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
handle_size: device.get_descriptor_increment_size(ty) as _,
|
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as usize,
|
||||||
availability: !0, // all free!
|
availability: !0, // all free!
|
||||||
start: heap.start_cpu_descriptor(),
|
start: unsafe { heap.GetCPUDescriptorHandleForHeapStart() },
|
||||||
_raw: heap,
|
_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.
|
// Find first free slot.
|
||||||
let slot = self.availability.trailing_zeros() as usize;
|
let slot = self.availability.trailing_zeros() as usize;
|
||||||
if slot >= HEAP_SIZE_FIXED {
|
if slot >= HEAP_SIZE_FIXED {
|
||||||
@ -153,12 +154,12 @@ impl FixedSizeHeap {
|
|||||||
// Set the slot as occupied.
|
// Set the slot as occupied.
|
||||||
self.availability ^= 1 << slot;
|
self.availability ^= 1 << slot;
|
||||||
|
|
||||||
Ok(d3d12::CpuDescriptor {
|
Ok(Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
|
||||||
ptr: self.start.ptr + self.handle_size * slot,
|
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;
|
let slot = (handle.ptr - self.start.ptr) / self.handle_size;
|
||||||
assert!(slot < HEAP_SIZE_FIXED);
|
assert!(slot < HEAP_SIZE_FIXED);
|
||||||
assert_eq!(self.availability & (1 << slot), 0);
|
assert_eq!(self.availability & (1 << slot), 0);
|
||||||
@ -172,7 +173,7 @@ impl FixedSizeHeap {
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(super) struct Handle {
|
pub(super) struct Handle {
|
||||||
pub raw: d3d12::CpuDescriptor,
|
pub raw: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
||||||
heap_index: usize,
|
heap_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,14 +187,17 @@ impl fmt::Debug for Handle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CpuPool {
|
pub(super) struct CpuPool {
|
||||||
device: d3d12::Device,
|
device: Direct3D12::ID3D12Device,
|
||||||
ty: d3d12::DescriptorHeapType,
|
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
||||||
heaps: Vec<FixedSizeHeap>,
|
heaps: Vec<FixedSizeHeap>,
|
||||||
available_heap_indices: BitSet,
|
available_heap_indices: BitSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuPool {
|
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 {
|
Self {
|
||||||
device,
|
device,
|
||||||
ty,
|
ty,
|
||||||
@ -234,13 +238,13 @@ impl CpuPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CpuHeapInner {
|
pub(super) struct CpuHeapInner {
|
||||||
pub _raw: d3d12::DescriptorHeap,
|
pub _raw: Direct3D12::ID3D12DescriptorHeap,
|
||||||
pub stage: Vec<d3d12::CpuDescriptor>,
|
pub stage: Vec<Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CpuHeap {
|
pub(super) struct CpuHeap {
|
||||||
pub inner: Mutex<CpuHeapInner>,
|
pub inner: Mutex<CpuHeapInner>,
|
||||||
start: d3d12::CpuDescriptor,
|
start: Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
||||||
handle_size: u32,
|
handle_size: u32,
|
||||||
total: u32,
|
total: u32,
|
||||||
}
|
}
|
||||||
@ -250,30 +254,33 @@ unsafe impl Sync for CpuHeap {}
|
|||||||
|
|
||||||
impl CpuHeap {
|
impl CpuHeap {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
device: d3d12::Device,
|
device: &Direct3D12::ID3D12Device,
|
||||||
ty: d3d12::DescriptorHeapType,
|
ty: Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
||||||
total: u32,
|
total: u32,
|
||||||
) -> Result<Self, crate::DeviceError> {
|
) -> Result<Self, crate::DeviceError> {
|
||||||
let handle_size = device.get_descriptor_increment_size(ty);
|
let handle_size = unsafe { device.GetDescriptorHandleIncrementSize(ty) };
|
||||||
let raw = device
|
let desc = Direct3D12::D3D12_DESCRIPTOR_HEAP_DESC {
|
||||||
.create_descriptor_heap(total, ty, d3d12::DescriptorHeapFlags::empty(), 0)
|
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")?;
|
.into_device_result("CPU descriptor heap creation")?;
|
||||||
|
|
||||||
null_comptr_check(&raw)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: Mutex::new(CpuHeapInner {
|
inner: Mutex::new(CpuHeapInner {
|
||||||
_raw: raw.clone(),
|
_raw: raw.clone(),
|
||||||
stage: Vec::new(),
|
stage: Vec::new(),
|
||||||
}),
|
}),
|
||||||
start: raw.start_cpu_descriptor(),
|
start: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
|
||||||
handle_size,
|
handle_size,
|
||||||
total,
|
total,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn at(&self, index: u32) -> d3d12::CpuDescriptor {
|
pub(super) fn at(&self, index: u32) -> Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
|
||||||
d3d12::CpuDescriptor {
|
Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE {
|
||||||
ptr: self.start.ptr + (self.handle_size * index) as usize,
|
ptr: self.start.ptr + (self.handle_size * index) as usize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,7 +297,7 @@ impl fmt::Debug for CpuHeap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn upload(
|
pub(super) unsafe fn upload(
|
||||||
device: d3d12::Device,
|
device: Direct3D12::ID3D12Device,
|
||||||
src: &CpuHeapInner,
|
src: &CpuHeapInner,
|
||||||
dst: &GeneralHeap,
|
dst: &GeneralHeap,
|
||||||
dummy_copy_counts: &[u32],
|
dummy_copy_counts: &[u32],
|
||||||
@ -301,11 +308,11 @@ pub(super) unsafe fn upload(
|
|||||||
device.CopyDescriptors(
|
device.CopyDescriptors(
|
||||||
1,
|
1,
|
||||||
&dst.cpu_descriptor_at(index),
|
&dst.cpu_descriptor_at(index),
|
||||||
&count,
|
Some(&count),
|
||||||
count,
|
count,
|
||||||
src.stage.as_ptr(),
|
src.stage.as_ptr(),
|
||||||
dummy_copy_counts.as_ptr(),
|
Some(dummy_copy_counts.as_ptr()),
|
||||||
dst.ty as u32,
|
dst.ty,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
Ok(dst.at(index, count as u64))
|
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 parking_lot::RwLock;
|
||||||
use winapi::shared::{dxgi1_5, minwindef};
|
use windows::{
|
||||||
|
core::Interface as _,
|
||||||
|
Win32::{
|
||||||
|
Foundation,
|
||||||
|
Graphics::{Direct3D12, Dxgi},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::SurfaceTarget;
|
use super::SurfaceTarget;
|
||||||
use crate::auxil::{self, dxgi::result::HResult as _};
|
use crate::{
|
||||||
use std::{mem, sync::Arc};
|
auxil::{self, dxgi::result::HResult as _},
|
||||||
|
dx12::D3D12Lib,
|
||||||
|
};
|
||||||
|
|
||||||
impl Drop for super::Instance {
|
impl Drop for super::Instance {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
@ -18,7 +28,7 @@ impl crate::Instance for super::Instance {
|
|||||||
|
|
||||||
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
||||||
profiling::scope!("Init DX12 Backend");
|
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)
|
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)
|
.intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION)
|
||||||
{
|
{
|
||||||
// Enable debug layer
|
// Enable debug layer
|
||||||
match lib_main.get_debug_interface() {
|
match lib_main.debug_interface() {
|
||||||
Ok(pair) => match pair.into_result() {
|
Ok(pair) => match pair {
|
||||||
Ok(debug_controller) => {
|
Ok(debug_controller) => {
|
||||||
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
|
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
|
||||||
debug_controller.enable_layer();
|
unsafe { debug_controller.EnableDebugLayer() }
|
||||||
}
|
}
|
||||||
if desc
|
if desc
|
||||||
.flags
|
.flags
|
||||||
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
|
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
|
||||||
{
|
{
|
||||||
#[allow(clippy::collapsible_if)]
|
#[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");
|
log::warn!("Failed to enable GPU-based validation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +74,7 @@ impl crate::Instance for super::Instance {
|
|||||||
|
|
||||||
// Create IDXGIFactoryMedia
|
// Create IDXGIFactoryMedia
|
||||||
let factory_media = match lib_dxgi.create_factory_media() {
|
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),
|
Ok(factory_media) => Some(factory_media),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Failed to create IDXGIFactoryMedia: {}", err);
|
log::error!("Failed to create IDXGIFactoryMedia: {}", err);
|
||||||
@ -76,12 +89,12 @@ impl crate::Instance for super::Instance {
|
|||||||
|
|
||||||
let mut supports_allow_tearing = false;
|
let mut supports_allow_tearing = false;
|
||||||
if let Some(factory5) = factory.as_factory5() {
|
if let Some(factory5) = factory.as_factory5() {
|
||||||
let mut allow_tearing: minwindef::BOOL = minwindef::FALSE;
|
let mut allow_tearing = Foundation::FALSE;
|
||||||
let hr = unsafe {
|
let hr = unsafe {
|
||||||
factory5.CheckFeatureSupport(
|
factory5.CheckFeatureSupport(
|
||||||
dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
|
Dxgi::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
|
||||||
std::ptr::from_mut(&mut allow_tearing).cast(),
|
<*mut _>::cast(&mut allow_tearing),
|
||||||
mem::size_of::<minwindef::BOOL>() as _,
|
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 {
|
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
|
||||||
factory: self.factory.clone(),
|
factory: self.factory.clone(),
|
||||||
factory_media: self.factory_media.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,
|
supports_allow_tearing: self.supports_allow_tearing,
|
||||||
swap_chain: RwLock::new(None),
|
swap_chain: RwLock::new(None),
|
||||||
}),
|
}),
|
||||||
|
@ -44,16 +44,258 @@ mod suballocation;
|
|||||||
mod types;
|
mod types;
|
||||||
mod view;
|
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 arrayvec::ArrayVec;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::{ffi, fmt, mem, num::NonZeroU32, sync::Arc};
|
use windows::{
|
||||||
use winapi::{
|
core::{Interface, Param as _},
|
||||||
shared::{dxgi, dxgi1_4, dxgitype, windef, winerror},
|
Win32::{
|
||||||
um::{d3d12 as d3d12_ty, dcomp, synchapi, winbase, winnt},
|
Foundation,
|
||||||
Interface as _,
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Api;
|
pub struct Api;
|
||||||
@ -116,24 +358,23 @@ const MAX_ROOT_ELEMENTS: usize = 64;
|
|||||||
const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10;
|
const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10;
|
||||||
|
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
factory: d3d12::DxgiFactory,
|
factory: DxgiFactory,
|
||||||
factory_media: Option<d3d12::FactoryMedia>,
|
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
|
||||||
library: Arc<d3d12::D3D12Lib>,
|
library: Arc<D3D12Lib>,
|
||||||
supports_allow_tearing: bool,
|
supports_allow_tearing: bool,
|
||||||
_lib_dxgi: d3d12::DxgiLib,
|
_lib_dxgi: DxgiLib,
|
||||||
flags: wgt::InstanceFlags,
|
flags: wgt::InstanceFlags,
|
||||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
pub unsafe fn create_surface_from_visual(
|
pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface {
|
||||||
&self,
|
let visual = unsafe { DirectComposition::IDCompositionVisual::from_raw_borrowed(&visual) }
|
||||||
visual: *mut dcomp::IDCompositionVisual,
|
.expect("COM pointer should not be NULL");
|
||||||
) -> Surface {
|
|
||||||
Surface {
|
Surface {
|
||||||
factory: self.factory.clone(),
|
factory: self.factory.clone(),
|
||||||
factory_media: self.factory_media.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,
|
supports_allow_tearing: self.supports_allow_tearing,
|
||||||
swap_chain: RwLock::new(None),
|
swap_chain: RwLock::new(None),
|
||||||
}
|
}
|
||||||
@ -141,8 +382,12 @@ impl Instance {
|
|||||||
|
|
||||||
pub unsafe fn create_surface_from_surface_handle(
|
pub unsafe fn create_surface_from_surface_handle(
|
||||||
&self,
|
&self,
|
||||||
surface_handle: winnt::HANDLE,
|
surface_handle: *mut std::ffi::c_void,
|
||||||
) -> Surface {
|
) -> 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 {
|
Surface {
|
||||||
factory: self.factory.clone(),
|
factory: self.factory.clone(),
|
||||||
factory_media: self.factory_media.clone(),
|
factory_media: self.factory_media.clone(),
|
||||||
@ -154,14 +399,15 @@ impl Instance {
|
|||||||
|
|
||||||
pub unsafe fn create_surface_from_swap_chain_panel(
|
pub unsafe fn create_surface_from_swap_chain_panel(
|
||||||
&self,
|
&self,
|
||||||
swap_chain_panel: *mut types::ISwapChainPanelNative,
|
swap_chain_panel: *mut std::ffi::c_void,
|
||||||
) -> Surface {
|
) -> Surface {
|
||||||
|
let swap_chain_panel =
|
||||||
|
unsafe { types::ISwapChainPanelNative::from_raw_borrowed(&swap_chain_panel) }
|
||||||
|
.expect("COM pointer should not be NULL");
|
||||||
Surface {
|
Surface {
|
||||||
factory: self.factory.clone(),
|
factory: self.factory.clone(),
|
||||||
factory_media: self.factory_media.clone(),
|
factory_media: self.factory_media.clone(),
|
||||||
target: SurfaceTarget::SwapChainPanel(unsafe {
|
target: SurfaceTarget::SwapChainPanel(swap_chain_panel.to_owned()),
|
||||||
d3d12::ComPtr::from_raw(swap_chain_panel)
|
|
||||||
}),
|
|
||||||
supports_allow_tearing: self.supports_allow_tearing,
|
supports_allow_tearing: self.supports_allow_tearing,
|
||||||
swap_chain: RwLock::new(None),
|
swap_chain: RwLock::new(None),
|
||||||
}
|
}
|
||||||
@ -172,11 +418,13 @@ unsafe impl Send for Instance {}
|
|||||||
unsafe impl Sync for Instance {}
|
unsafe impl Sync for Instance {}
|
||||||
|
|
||||||
struct SwapChain {
|
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
|
// need to associate raw image pointers with the swapchain so they can be properly released
|
||||||
// when the swapchain is destroyed
|
// when the swapchain is destroyed
|
||||||
resources: Vec<d3d12::Resource>,
|
resources: Vec<Direct3D12::ID3D12Resource>,
|
||||||
waitable: winnt::HANDLE,
|
/// Handle is freed in [`Self::release_resources()`]
|
||||||
|
waitable: Foundation::HANDLE,
|
||||||
acquired_count: usize,
|
acquired_count: usize,
|
||||||
present_mode: wgt::PresentMode,
|
present_mode: wgt::PresentMode,
|
||||||
format: wgt::TextureFormat,
|
format: wgt::TextureFormat,
|
||||||
@ -184,15 +432,17 @@ struct SwapChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum SurfaceTarget {
|
enum SurfaceTarget {
|
||||||
WndHandle(windef::HWND),
|
/// Borrowed, lifetime externally managed
|
||||||
Visual(d3d12::ComPtr<dcomp::IDCompositionVisual>),
|
WndHandle(Foundation::HWND),
|
||||||
SurfaceHandle(winnt::HANDLE),
|
Visual(DirectComposition::IDCompositionVisual),
|
||||||
SwapChainPanel(d3d12::ComPtr<types::ISwapChainPanelNative>),
|
/// Borrowed, lifetime externally managed
|
||||||
|
SurfaceHandle(Foundation::HANDLE),
|
||||||
|
SwapChainPanel(types::ISwapChainPanelNative),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Surface {
|
pub struct Surface {
|
||||||
factory: d3d12::DxgiFactory,
|
factory: DxgiFactory,
|
||||||
factory_media: Option<d3d12::FactoryMedia>,
|
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
|
||||||
target: SurfaceTarget,
|
target: SurfaceTarget,
|
||||||
supports_allow_tearing: bool,
|
supports_allow_tearing: bool,
|
||||||
swap_chain: RwLock<Option<SwapChain>>,
|
swap_chain: RwLock<Option<SwapChain>>,
|
||||||
@ -216,7 +466,6 @@ struct PrivateCapabilities {
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
heterogeneous_resource_heaps: bool,
|
heterogeneous_resource_heaps: bool,
|
||||||
memory_architecture: MemoryArchitecture,
|
memory_architecture: MemoryArchitecture,
|
||||||
#[allow(unused)] // TODO: Exists until windows-rs is standard, then it can probably be removed?
|
|
||||||
heap_create_not_zeroed: bool,
|
heap_create_not_zeroed: bool,
|
||||||
casting_fully_typed_format_supported: bool,
|
casting_fully_typed_format_supported: bool,
|
||||||
suballocation_supported: bool,
|
suballocation_supported: bool,
|
||||||
@ -231,12 +480,12 @@ struct Workarounds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Adapter {
|
pub struct Adapter {
|
||||||
raw: d3d12::DxgiAdapter,
|
raw: DxgiAdapter,
|
||||||
device: d3d12::Device,
|
device: Direct3D12::ID3D12Device,
|
||||||
library: Arc<d3d12::D3D12Lib>,
|
library: Arc<D3D12Lib>,
|
||||||
private_caps: PrivateCapabilities,
|
private_caps: PrivateCapabilities,
|
||||||
presentation_timer: auxil::dxgi::time::PresentationTimer,
|
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)]
|
#[allow(unused)]
|
||||||
workarounds: Workarounds,
|
workarounds: Workarounds,
|
||||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||||
@ -245,20 +494,36 @@ pub struct Adapter {
|
|||||||
unsafe impl Send for Adapter {}
|
unsafe impl Send for Adapter {}
|
||||||
unsafe impl Sync 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.
|
/// Helper structure for waiting for GPU.
|
||||||
struct Idler {
|
struct Idler {
|
||||||
fence: d3d12::Fence,
|
fence: Direct3D12::ID3D12Fence,
|
||||||
event: d3d12::Event,
|
event: Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CommandSignatures {
|
struct CommandSignatures {
|
||||||
draw: d3d12::CommandSignature,
|
draw: Direct3D12::ID3D12CommandSignature,
|
||||||
draw_indexed: d3d12::CommandSignature,
|
draw_indexed: Direct3D12::ID3D12CommandSignature,
|
||||||
dispatch: d3d12::CommandSignature,
|
dispatch: Direct3D12::ID3D12CommandSignature,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceShared {
|
struct DeviceShared {
|
||||||
zero_buffer: d3d12::Resource,
|
zero_buffer: Direct3D12::ID3D12Resource,
|
||||||
cmd_signatures: CommandSignatures,
|
cmd_signatures: CommandSignatures,
|
||||||
heap_views: descriptor::GeneralHeap,
|
heap_views: descriptor::GeneralHeap,
|
||||||
heap_samplers: descriptor::GeneralHeap,
|
heap_samplers: descriptor::GeneralHeap,
|
||||||
@ -268,8 +533,8 @@ unsafe impl Send for DeviceShared {}
|
|||||||
unsafe impl Sync for DeviceShared {}
|
unsafe impl Sync for DeviceShared {}
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
raw: d3d12::Device,
|
raw: Direct3D12::ID3D12Device,
|
||||||
present_queue: d3d12::CommandQueue,
|
present_queue: Direct3D12::ID3D12CommandQueue,
|
||||||
idler: Idler,
|
idler: Idler,
|
||||||
private_caps: PrivateCapabilities,
|
private_caps: PrivateCapabilities,
|
||||||
shared: Arc<DeviceShared>,
|
shared: Arc<DeviceShared>,
|
||||||
@ -279,11 +544,11 @@ pub struct Device {
|
|||||||
srv_uav_pool: Mutex<descriptor::CpuPool>,
|
srv_uav_pool: Mutex<descriptor::CpuPool>,
|
||||||
sampler_pool: Mutex<descriptor::CpuPool>,
|
sampler_pool: Mutex<descriptor::CpuPool>,
|
||||||
// library
|
// library
|
||||||
library: Arc<d3d12::D3D12Lib>,
|
library: Arc<D3D12Lib>,
|
||||||
#[cfg(feature = "renderdoc")]
|
#[cfg(feature = "renderdoc")]
|
||||||
render_doc: auxil::renderdoc::RenderDoc,
|
render_doc: auxil::renderdoc::RenderDoc,
|
||||||
null_rtv_handle: descriptor::Handle,
|
null_rtv_handle: descriptor::Handle,
|
||||||
mem_allocator: Option<Mutex<suballocation::GpuAllocatorWrapper>>,
|
mem_allocator: Mutex<suballocation::GpuAllocatorWrapper>,
|
||||||
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
|
||||||
counters: wgt::HalCounters,
|
counters: wgt::HalCounters,
|
||||||
}
|
}
|
||||||
@ -292,8 +557,8 @@ unsafe impl Send for Device {}
|
|||||||
unsafe impl Sync for Device {}
|
unsafe impl Sync for Device {}
|
||||||
|
|
||||||
pub struct Queue {
|
pub struct Queue {
|
||||||
raw: d3d12::CommandQueue,
|
raw: Direct3D12::ID3D12CommandQueue,
|
||||||
temp_lists: Mutex<Vec<d3d12::CommandList>>,
|
temp_lists: Mutex<Vec<Option<Direct3D12::ID3D12CommandList>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Queue {}
|
unsafe impl Send for Queue {}
|
||||||
@ -302,7 +567,7 @@ unsafe impl Sync for Queue {}
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Temp {
|
struct Temp {
|
||||||
marker: Vec<u16>,
|
marker: Vec<u16>,
|
||||||
barriers: Vec<d3d12_ty::D3D12_RESOURCE_BARRIER>,
|
barriers: Vec<Direct3D12::D3D12_RESOURCE_BARRIER>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Temp {
|
impl Temp {
|
||||||
@ -313,9 +578,9 @@ impl Temp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct PassResolve {
|
struct PassResolve {
|
||||||
src: (d3d12::Resource, u32),
|
src: (Direct3D12::ID3D12Resource, u32),
|
||||||
dst: (d3d12::Resource, u32),
|
dst: (Direct3D12::ID3D12Resource, u32),
|
||||||
format: d3d12::Format,
|
format: Dxgi::Common::DXGI_FORMAT,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -328,11 +593,11 @@ enum RootElement {
|
|||||||
other: u32,
|
other: u32,
|
||||||
},
|
},
|
||||||
/// Descriptor table.
|
/// Descriptor table.
|
||||||
Table(d3d12::GpuDescriptor),
|
Table(Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE),
|
||||||
/// Descriptor for a buffer that has dynamic offset.
|
/// Descriptor for a buffer that has dynamic offset.
|
||||||
DynamicOffsetBuffer {
|
DynamicOffsetBuffer {
|
||||||
kind: BufferViewKind,
|
kind: BufferViewKind,
|
||||||
address: d3d12::GpuAddress,
|
address: Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +615,7 @@ struct PassState {
|
|||||||
root_elements: [RootElement; MAX_ROOT_ELEMENTS],
|
root_elements: [RootElement; MAX_ROOT_ELEMENTS],
|
||||||
constant_data: [u32; MAX_ROOT_ELEMENTS],
|
constant_data: [u32; MAX_ROOT_ELEMENTS],
|
||||||
dirty_root_elements: u64,
|
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,
|
dirty_vertex_buffers: usize,
|
||||||
kind: PassKind,
|
kind: PassKind,
|
||||||
}
|
}
|
||||||
@ -366,7 +631,7 @@ impl PassState {
|
|||||||
has_label: false,
|
has_label: false,
|
||||||
resolves: ArrayVec::new(),
|
resolves: ArrayVec::new(),
|
||||||
layout: PipelineLayoutShared {
|
layout: PipelineLayoutShared {
|
||||||
signature: d3d12::RootSignature::null(),
|
signature: None,
|
||||||
total_root_elements: 0,
|
total_root_elements: 0,
|
||||||
special_constants_root_index: None,
|
special_constants_root_index: None,
|
||||||
root_constant_info: None,
|
root_constant_info: None,
|
||||||
@ -374,7 +639,7 @@ impl PassState {
|
|||||||
root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS],
|
root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS],
|
||||||
constant_data: [0; MAX_ROOT_ELEMENTS],
|
constant_data: [0; MAX_ROOT_ELEMENTS],
|
||||||
dirty_root_elements: 0,
|
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,
|
dirty_vertex_buffers: 0,
|
||||||
kind: PassKind::Transfer,
|
kind: PassKind::Transfer,
|
||||||
}
|
}
|
||||||
@ -387,18 +652,18 @@ impl PassState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommandEncoder {
|
pub struct CommandEncoder {
|
||||||
allocator: d3d12::CommandAllocator,
|
allocator: Direct3D12::ID3D12CommandAllocator,
|
||||||
device: d3d12::Device,
|
device: Direct3D12::ID3D12Device,
|
||||||
shared: Arc<DeviceShared>,
|
shared: Arc<DeviceShared>,
|
||||||
null_rtv_handle: descriptor::Handle,
|
null_rtv_handle: descriptor::Handle,
|
||||||
list: Option<d3d12::GraphicsCommandList>,
|
list: Option<Direct3D12::ID3D12GraphicsCommandList>,
|
||||||
free_lists: Vec<d3d12::GraphicsCommandList>,
|
free_lists: Vec<Direct3D12::ID3D12GraphicsCommandList>,
|
||||||
pass: PassState,
|
pass: PassState,
|
||||||
temp: Temp,
|
temp: Temp,
|
||||||
|
|
||||||
/// If set, the end of the next render/compute pass will write a timestamp at
|
/// If set, the end of the next render/compute pass will write a timestamp at
|
||||||
/// the given pool & location.
|
/// 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 {}
|
unsafe impl Send for CommandEncoder {}
|
||||||
@ -415,7 +680,7 @@ impl fmt::Debug for CommandEncoder {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CommandBuffer {
|
pub struct CommandBuffer {
|
||||||
raw: d3d12::GraphicsCommandList,
|
raw: Direct3D12::ID3D12GraphicsCommandList,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::DynCommandBuffer for CommandBuffer {}
|
impl crate::DynCommandBuffer for CommandBuffer {}
|
||||||
@ -425,7 +690,7 @@ unsafe impl Sync for CommandBuffer {}
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
resource: d3d12::Resource,
|
resource: Direct3D12::ID3D12Resource,
|
||||||
size: wgt::BufferAddress,
|
size: wgt::BufferAddress,
|
||||||
allocation: Option<suballocation::AllocationWrapper>,
|
allocation: Option<suballocation::AllocationWrapper>,
|
||||||
}
|
}
|
||||||
@ -443,14 +708,15 @@ impl crate::BufferBinding<'_, Buffer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Return GPU handle directly?
|
||||||
fn resolve_address(&self) -> wgt::BufferAddress {
|
fn resolve_address(&self) -> wgt::BufferAddress {
|
||||||
self.buffer.resource.gpu_virtual_address() + self.offset
|
(unsafe { self.buffer.resource.GetGPUVirtualAddress() }) + self.offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
resource: d3d12::Resource,
|
resource: Direct3D12::ID3D12Resource,
|
||||||
format: wgt::TextureFormat,
|
format: wgt::TextureFormat,
|
||||||
dimension: wgt::TextureDimension,
|
dimension: wgt::TextureDimension,
|
||||||
size: wgt::Extent3d,
|
size: wgt::Extent3d,
|
||||||
@ -496,10 +762,10 @@ impl Texture {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TextureView {
|
pub struct TextureView {
|
||||||
raw_format: d3d12::Format,
|
raw_format: Dxgi::Common::DXGI_FORMAT,
|
||||||
aspects: crate::FormatAspects,
|
aspects: crate::FormatAspects,
|
||||||
/// only used by resolve
|
/// only used by resolve
|
||||||
target_base: (d3d12::Resource, u32),
|
target_base: (Direct3D12::ID3D12Resource, u32),
|
||||||
handle_srv: Option<descriptor::Handle>,
|
handle_srv: Option<descriptor::Handle>,
|
||||||
handle_uav: Option<descriptor::Handle>,
|
handle_uav: Option<descriptor::Handle>,
|
||||||
handle_rtv: Option<descriptor::Handle>,
|
handle_rtv: Option<descriptor::Handle>,
|
||||||
@ -524,8 +790,8 @@ unsafe impl Sync for Sampler {}
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct QuerySet {
|
pub struct QuerySet {
|
||||||
raw: d3d12::QueryHeap,
|
raw: Direct3D12::ID3D12QueryHeap,
|
||||||
raw_ty: d3d12_ty::D3D12_QUERY_TYPE,
|
raw_ty: Direct3D12::D3D12_QUERY_TYPE,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::DynQuerySet for QuerySet {}
|
impl crate::DynQuerySet for QuerySet {}
|
||||||
@ -535,7 +801,7 @@ unsafe impl Sync for QuerySet {}
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Fence {
|
pub struct Fence {
|
||||||
raw: d3d12::Fence,
|
raw: Direct3D12::ID3D12Fence,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::DynFence for Fence {}
|
impl crate::DynFence for Fence {}
|
||||||
@ -544,7 +810,7 @@ unsafe impl Send for Fence {}
|
|||||||
unsafe impl Sync for Fence {}
|
unsafe impl Sync for Fence {}
|
||||||
|
|
||||||
impl Fence {
|
impl Fence {
|
||||||
pub fn raw_fence(&self) -> &d3d12::Fence {
|
pub fn raw_fence(&self) -> &Direct3D12::ID3D12Fence {
|
||||||
&self.raw
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -571,7 +837,7 @@ enum BufferViewKind {
|
|||||||
pub struct BindGroup {
|
pub struct BindGroup {
|
||||||
handle_views: Option<descriptor::DualHandle>,
|
handle_views: Option<descriptor::DualHandle>,
|
||||||
handle_samplers: 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 {}
|
impl crate::DynBindGroup for BindGroup {}
|
||||||
@ -602,7 +868,7 @@ struct RootConstantInfo {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct PipelineLayoutShared {
|
struct PipelineLayoutShared {
|
||||||
signature: d3d12::RootSignature,
|
signature: Option<Direct3D12::ID3D12RootSignature>,
|
||||||
total_root_elements: RootIndex,
|
total_root_elements: RootIndex,
|
||||||
special_constants_root_index: Option<RootIndex>,
|
special_constants_root_index: Option<RootIndex>,
|
||||||
root_constant_info: Option<RootConstantInfo>,
|
root_constant_info: Option<RootConstantInfo>,
|
||||||
@ -633,14 +899,20 @@ impl crate::DynShaderModule for ShaderModule {}
|
|||||||
pub(super) enum CompiledShader {
|
pub(super) enum CompiledShader {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Dxc(Vec<u8>),
|
Dxc(Vec<u8>),
|
||||||
Fxc(d3d12::Blob),
|
Fxc(Direct3D::ID3DBlob),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompiledShader {
|
impl CompiledShader {
|
||||||
fn create_native_shader(&self) -> d3d12::Shader {
|
fn create_native_shader(&self) -> Direct3D12::D3D12_SHADER_BYTECODE {
|
||||||
match *self {
|
match self {
|
||||||
CompiledShader::Dxc(ref shader) => d3d12::Shader::from_raw(shader),
|
CompiledShader::Dxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE {
|
||||||
CompiledShader::Fxc(ref shader) => d3d12::Shader::from_blob(shader),
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct RenderPipeline {
|
pub struct RenderPipeline {
|
||||||
raw: d3d12::PipelineState,
|
raw: Direct3D12::ID3D12PipelineState,
|
||||||
layout: PipelineLayoutShared,
|
layout: PipelineLayoutShared,
|
||||||
topology: d3d12_ty::D3D12_PRIMITIVE_TOPOLOGY,
|
topology: Direct3D::D3D_PRIMITIVE_TOPOLOGY,
|
||||||
vertex_strides: [Option<NonZeroU32>; crate::MAX_VERTEX_BUFFERS],
|
vertex_strides: [Option<NonZeroU32>; crate::MAX_VERTEX_BUFFERS],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +934,7 @@ unsafe impl Sync for RenderPipeline {}
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ComputePipeline {
|
pub struct ComputePipeline {
|
||||||
raw: d3d12::PipelineState,
|
raw: Direct3D12::ID3D12PipelineState,
|
||||||
layout: PipelineLayoutShared,
|
layout: PipelineLayoutShared,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,7 +954,8 @@ pub struct AccelerationStructure {}
|
|||||||
impl crate::DynAccelerationStructure for AccelerationStructure {}
|
impl crate::DynAccelerationStructure for AccelerationStructure {}
|
||||||
|
|
||||||
impl SwapChain {
|
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
|
self.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,14 +965,14 @@ impl SwapChain {
|
|||||||
) -> Result<bool, crate::SurfaceError> {
|
) -> Result<bool, crate::SurfaceError> {
|
||||||
let timeout_ms = match timeout {
|
let timeout_ms = match timeout {
|
||||||
Some(duration) => duration.as_millis() as u32,
|
Some(duration) => duration.as_millis() as u32,
|
||||||
None => winbase::INFINITE,
|
None => Threading::INFINITE,
|
||||||
};
|
};
|
||||||
match unsafe { synchapi::WaitForSingleObject(self.waitable, timeout_ms) } {
|
match unsafe { Threading::WaitForSingleObject(self.waitable, timeout_ms) } {
|
||||||
winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => Err(crate::SurfaceError::Lost),
|
Foundation::WAIT_ABANDONED | Foundation::WAIT_FAILED => Err(crate::SurfaceError::Lost),
|
||||||
winbase::WAIT_OBJECT_0 => Ok(true),
|
Foundation::WAIT_OBJECT_0 => Ok(true),
|
||||||
winerror::WAIT_TIMEOUT => Ok(false),
|
Foundation::WAIT_TIMEOUT => Ok(false),
|
||||||
other => {
|
other => {
|
||||||
log::error!("Unexpected wait status: 0x{:x}", other);
|
log::error!("Unexpected wait status: 0x{:x?}", other);
|
||||||
Err(crate::SurfaceError::Lost)
|
Err(crate::SurfaceError::Lost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +987,7 @@ impl crate::Surface for Surface {
|
|||||||
device: &Device,
|
device: &Device,
|
||||||
config: &crate::SurfaceConfiguration,
|
config: &crate::SurfaceConfiguration,
|
||||||
) -> Result<(), crate::SurfaceError> {
|
) -> 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
|
// We always set ALLOW_TEARING on the swapchain no matter
|
||||||
// what kind of swapchain we want because ResizeBuffers
|
// what kind of swapchain we want because ResizeBuffers
|
||||||
// cannot change the swapchain's ALLOW_TEARING flag.
|
// 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
|
// This does not change the behavior of the swapchain, just
|
||||||
// allow present calls to use tearing.
|
// allow present calls to use tearing.
|
||||||
if self.supports_allow_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
|
// While `configure`s contract ensures that no work on the GPU's main queues
|
||||||
@ -760,77 +1033,72 @@ impl crate::Surface for Surface {
|
|||||||
raw
|
raw
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let desc = d3d12::SwapchainDesc {
|
let desc = Dxgi::DXGI_SWAP_CHAIN_DESC1 {
|
||||||
alpha_mode: auxil::dxgi::conv::map_acomposite_alpha_mode(
|
AlphaMode: auxil::dxgi::conv::map_acomposite_alpha_mode(
|
||||||
config.composite_alpha_mode,
|
config.composite_alpha_mode,
|
||||||
),
|
),
|
||||||
width: config.extent.width,
|
Width: config.extent.width,
|
||||||
height: config.extent.height,
|
Height: config.extent.height,
|
||||||
format: non_srgb_format,
|
Format: non_srgb_format,
|
||||||
stereo: false,
|
Stereo: false.into(),
|
||||||
sample: d3d12::SampleDesc {
|
SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC {
|
||||||
count: 1,
|
Count: 1,
|
||||||
quality: 0,
|
Quality: 0,
|
||||||
},
|
},
|
||||||
buffer_usage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
BufferUsage: Dxgi::DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||||
buffer_count: swap_chain_buffer,
|
BufferCount: swap_chain_buffer,
|
||||||
scaling: d3d12::Scaling::Stretch,
|
Scaling: Dxgi::DXGI_SCALING_STRETCH,
|
||||||
swap_effect: d3d12::SwapEffect::FlipDiscard,
|
SwapEffect: Dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
||||||
flags,
|
Flags: flags.0 as u32,
|
||||||
};
|
};
|
||||||
let swap_chain1 = match self.target {
|
let swap_chain1 = match self.target {
|
||||||
SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => {
|
SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => {
|
||||||
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
|
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
|
||||||
self.factory
|
unsafe {
|
||||||
.unwrap_factory2()
|
self.factory
|
||||||
.create_swapchain_for_composition(
|
.unwrap_factory2()
|
||||||
device.present_queue.as_mut_ptr().cast(),
|
.CreateSwapChainForComposition(&device.present_queue, &desc, None)
|
||||||
&desc,
|
}
|
||||||
)
|
|
||||||
.into_result()
|
|
||||||
}
|
}
|
||||||
SurfaceTarget::SurfaceHandle(handle) => {
|
SurfaceTarget::SurfaceHandle(handle) => {
|
||||||
profiling::scope!(
|
profiling::scope!(
|
||||||
"IDXGIFactoryMedia::CreateSwapChainForCompositionSurfaceHandle"
|
"IDXGIFactoryMedia::CreateSwapChainForCompositionSurfaceHandle"
|
||||||
);
|
);
|
||||||
self.factory_media
|
unsafe {
|
||||||
.clone()
|
self.factory_media
|
||||||
.ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))?
|
.as_ref()
|
||||||
.create_swapchain_for_composition_surface_handle(
|
.ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))?
|
||||||
device.present_queue.as_mut_ptr().cast(),
|
.CreateSwapChainForCompositionSurfaceHandle(
|
||||||
handle,
|
&device.present_queue,
|
||||||
&desc,
|
handle,
|
||||||
)
|
&desc,
|
||||||
.into_result()
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SurfaceTarget::WndHandle(hwnd) => {
|
SurfaceTarget::WndHandle(hwnd) => {
|
||||||
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
|
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
|
||||||
self.factory
|
unsafe {
|
||||||
.as_factory2()
|
self.factory.unwrap_factory2().CreateSwapChainForHwnd(
|
||||||
.unwrap()
|
&device.present_queue,
|
||||||
.create_swapchain_for_hwnd(
|
|
||||||
device.present_queue.as_mut_ptr().cast(),
|
|
||||||
hwnd,
|
hwnd,
|
||||||
&desc,
|
&desc,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.into_result()
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let swap_chain1 = match swap_chain1 {
|
let swap_chain1 = swap_chain1.map_err(|err| {
|
||||||
Ok(s) => s,
|
log::error!("SwapChain creation error: {}", err);
|
||||||
Err(err) => {
|
crate::SurfaceError::Other("swap chain creation")
|
||||||
log::error!("SwapChain creation error: {}", err);
|
})?;
|
||||||
return Err(crate::SurfaceError::Other("swap chain creation"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match &self.target {
|
match &self.target {
|
||||||
SurfaceTarget::WndHandle(_) | &SurfaceTarget::SurfaceHandle(_) => {}
|
SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {}
|
||||||
SurfaceTarget::Visual(visual) => {
|
SurfaceTarget::Visual(visual) => {
|
||||||
if let Err(err) =
|
if let Err(err) = unsafe { visual.SetContent(&swap_chain1) }.into_result() {
|
||||||
unsafe { visual.SetContent(swap_chain1.as_unknown()) }.into_result()
|
|
||||||
{
|
|
||||||
log::error!("Unable to SetContent: {}", err);
|
log::error!("Unable to SetContent: {}", err);
|
||||||
return Err(crate::SurfaceError::Other(
|
return Err(crate::SurfaceError::Other(
|
||||||
"IDCompositionVisual::SetContent",
|
"IDCompositionVisual::SetContent",
|
||||||
@ -839,8 +1107,7 @@ impl crate::Surface for Surface {
|
|||||||
}
|
}
|
||||||
SurfaceTarget::SwapChainPanel(swap_chain_panel) => {
|
SurfaceTarget::SwapChainPanel(swap_chain_panel) => {
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
unsafe { swap_chain_panel.SetSwapChain(swap_chain1.as_ptr()) }
|
unsafe { swap_chain_panel.SetSwapChain(&swap_chain1) }.into_result()
|
||||||
.into_result()
|
|
||||||
{
|
{
|
||||||
log::error!("Unable to SetSwapChain: {}", err);
|
log::error!("Unable to SetSwapChain: {}", err);
|
||||||
return Err(crate::SurfaceError::Other(
|
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,
|
Ok(swap_chain3) => swap_chain3,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Unable to cast swap chain: {}", err);
|
log::error!("Unable to cast swap chain: {}", err);
|
||||||
@ -863,29 +1130,27 @@ impl crate::Surface for Surface {
|
|||||||
match self.target {
|
match self.target {
|
||||||
SurfaceTarget::WndHandle(wnd_handle) => {
|
SurfaceTarget::WndHandle(wnd_handle) => {
|
||||||
// Disable automatic Alt+Enter handling by DXGI.
|
// Disable automatic Alt+Enter handling by DXGI.
|
||||||
const DXGI_MWA_NO_WINDOW_CHANGES: u32 = 1;
|
|
||||||
const DXGI_MWA_NO_ALT_ENTER: u32 = 2;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.factory.MakeWindowAssociation(
|
self.factory.MakeWindowAssociation(
|
||||||
wnd_handle,
|
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::Visual(_)
|
||||||
| SurfaceTarget::SurfaceHandle(_)
|
| SurfaceTarget::SurfaceHandle(_)
|
||||||
| SurfaceTarget::SwapChainPanel(_) => {}
|
| 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 waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() };
|
||||||
|
|
||||||
let mut resources = Vec::with_capacity(swap_chain_buffer as usize);
|
let mut resources = Vec::with_capacity(swap_chain_buffer as usize);
|
||||||
for i in 0..swap_chain_buffer {
|
for i in 0..swap_chain_buffer {
|
||||||
let mut resource = d3d12::Resource::null();
|
let resource = unsafe { swap_chain.GetBuffer(i) }
|
||||||
unsafe {
|
.into_device_result("Failed to get swapchain buffer")?;
|
||||||
swap_chain.GetBuffer(i, &d3d12_ty::ID3D12Resource::uuidof(), resource.mut_void())
|
|
||||||
};
|
|
||||||
resources.push(resource);
|
resources.push(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,16 +1231,15 @@ impl crate::Queue for Queue {
|
|||||||
let mut temp_lists = self.temp_lists.lock();
|
let mut temp_lists = self.temp_lists.lock();
|
||||||
temp_lists.clear();
|
temp_lists.clear();
|
||||||
for cmd_buf in command_buffers {
|
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");
|
profiling::scope!("ID3D12CommandQueue::ExecuteCommandLists");
|
||||||
self.raw.execute_command_lists(&temp_lists);
|
unsafe { self.raw.ExecuteCommandLists(&temp_lists) }
|
||||||
}
|
}
|
||||||
|
|
||||||
self.raw
|
unsafe { self.raw.Signal(&signal_fence.raw, signal_value) }
|
||||||
.signal(&signal_fence.raw, signal_value)
|
|
||||||
.into_device_result("Signal fence")?;
|
.into_device_result("Signal fence")?;
|
||||||
|
|
||||||
// Note the lack of synchronization here between the main Direct queue
|
// 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 {
|
let (interval, flags) = match sc.present_mode {
|
||||||
// We only allow immediate if ALLOW_TEARING is valid.
|
// We only allow immediate if ALLOW_TEARING is valid.
|
||||||
wgt::PresentMode::Immediate => (0, dxgi::DXGI_PRESENT_ALLOW_TEARING),
|
wgt::PresentMode::Immediate => (0, Dxgi::DXGI_PRESENT_ALLOW_TEARING),
|
||||||
wgt::PresentMode::Mailbox => (0, 0),
|
wgt::PresentMode::Mailbox => (0, Dxgi::DXGI_PRESENT::default()),
|
||||||
wgt::PresentMode::Fifo => (1, 0),
|
wgt::PresentMode::Fifo => (1, Dxgi::DXGI_PRESENT::default()),
|
||||||
m => unreachable!("Cannot make surface with present mode {m:?}"),
|
m => unreachable!("Cannot make surface with present mode {m:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
profiling::scope!("IDXGISwapchain3::Present");
|
profiling::scope!("IDXGISwapchain3::Present");
|
||||||
unsafe { sc.raw.Present(interval, flags) };
|
unsafe { sc.raw.Present(interval, flags) }
|
||||||
|
.ok()
|
||||||
|
.into_device_result("Present")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_timestamp_period(&self) -> f32 {
|
unsafe fn get_timestamp_period(&self) -> f32 {
|
||||||
let mut frequency = 0u64;
|
let frequency = unsafe { self.raw.GetTimestampFrequency() }.expect("GetTimestampFrequency");
|
||||||
unsafe { self.raw.GetTimestampFrequency(&mut frequency) };
|
|
||||||
(1_000_000_000.0 / frequency as f64) as f32
|
(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;
|
use std::ptr;
|
||||||
|
|
||||||
pub(super) use dxc::{compile_dxc, get_dxc_container, DxcContainer};
|
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;
|
use crate::auxil::dxgi::result::HResult;
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ pub(super) fn compile_fxc(
|
|||||||
device: &super::Device,
|
device: &super::Device,
|
||||||
source: &str,
|
source: &str,
|
||||||
source_name: Option<&CStr>,
|
source_name: Option<&CStr>,
|
||||||
raw_ep: &std::ffi::CString,
|
raw_ep: &CStr,
|
||||||
stage_bit: wgt::ShaderStages,
|
stage_bit: wgt::ShaderStages,
|
||||||
full_stage: &CStr,
|
full_stage: &CStr,
|
||||||
) -> (
|
) -> (
|
||||||
@ -24,49 +24,54 @@ pub(super) fn compile_fxc(
|
|||||||
log::Level,
|
log::Level,
|
||||||
) {
|
) {
|
||||||
profiling::scope!("compile_fxc");
|
profiling::scope!("compile_fxc");
|
||||||
let mut shader_data = d3d12::Blob::null();
|
let mut shader_data = None;
|
||||||
let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS;
|
let mut compile_flags = Direct3D::Fxc::D3DCOMPILE_ENABLE_STRICTNESS;
|
||||||
if device
|
if device
|
||||||
.private_caps
|
.private_caps
|
||||||
.instance_flags
|
.instance_flags
|
||||||
.contains(wgt::InstanceFlags::DEBUG)
|
.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.
|
// 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 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 {
|
let hr = unsafe {
|
||||||
profiling::scope!("d3dcompiler::D3DCompile");
|
profiling::scope!("Direct3D::Fxc::D3DCompile");
|
||||||
d3dcompiler::D3DCompile(
|
Direct3D::Fxc::D3DCompile(
|
||||||
|
// TODO: Update low-level bindings to accept a slice here
|
||||||
source.as_ptr().cast(),
|
source.as_ptr().cast(),
|
||||||
source.len(),
|
source.len(),
|
||||||
source_name.cast(),
|
windows::core::PCSTR(source_name.cast()),
|
||||||
ptr::null(),
|
None,
|
||||||
ptr::null_mut(),
|
None,
|
||||||
raw_ep.as_ptr(),
|
windows::core::PCSTR(raw_ep.as_ptr().cast()),
|
||||||
full_stage.as_ptr().cast(),
|
windows::core::PCSTR(full_stage.as_ptr().cast()),
|
||||||
compile_flags,
|
compile_flags,
|
||||||
0,
|
0,
|
||||||
shader_data.mut_void().cast(),
|
&mut shader_data,
|
||||||
error.mut_void().cast(),
|
Some(&mut error),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
match hr.into_result() {
|
match hr.into_result() {
|
||||||
Ok(()) => (
|
Ok(()) => {
|
||||||
Ok(super::CompiledShader::Fxc(shader_data)),
|
let shader_data = shader_data.unwrap();
|
||||||
log::Level::Info,
|
(
|
||||||
),
|
Ok(super::CompiledShader::Fxc(shader_data)),
|
||||||
|
log::Level::Info,
|
||||||
|
)
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let mut full_msg = format!("FXC D3DCompile error ({e})");
|
let mut full_msg = format!("FXC D3DCompile error ({e})");
|
||||||
if !error.is_null() {
|
if let Some(error) = error {
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
let message = unsafe {
|
let message = unsafe {
|
||||||
std::slice::from_raw_parts(
|
std::slice::from_raw_parts(
|
||||||
error.GetBufferPointer() as *const u8,
|
error.GetBufferPointer().cast(),
|
||||||
error.GetBufferSize(),
|
error.GetBufferSize(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -149,7 +154,7 @@ mod dxc {
|
|||||||
) {
|
) {
|
||||||
profiling::scope!("compile_dxc");
|
profiling::scope!("compile_dxc");
|
||||||
let mut compile_flags = arrayvec::ArrayVec::<&str, 6>::new_const();
|
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("-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("-HV"); // Use HLSL 2018, Naga doesn't supported 2021 yet.
|
||||||
compile_flags.push("2018");
|
compile_flags.push("2018");
|
||||||
@ -159,8 +164,8 @@ mod dxc {
|
|||||||
.instance_flags
|
.instance_flags
|
||||||
.contains(wgt::InstanceFlags::DEBUG)
|
.contains(wgt::InstanceFlags::DEBUG)
|
||||||
{
|
{
|
||||||
compile_flags.push("-Zi"); // d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION
|
compile_flags.push("-Zi"); // Direct3D::Fxc::D3DCOMPILE_SKIP_OPTIMIZATION
|
||||||
compile_flags.push("-Od"); // d3dcompiler::D3DCOMPILE_DEBUG
|
compile_flags.push("-Od"); // Direct3D::Fxc::D3DCOMPILE_DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
let blob = match dxc_container
|
let blob = match dxc_container
|
||||||
|
@ -1,409 +1,314 @@
|
|||||||
pub(crate) use allocation::{
|
use gpu_allocator::{d3d12::AllocationCreateDesc, MemoryLocation};
|
||||||
create_allocator_wrapper, create_buffer_resource, create_texture_resource,
|
use parking_lot::Mutex;
|
||||||
free_buffer_allocation, free_texture_allocation, AllocationWrapper, GpuAllocatorWrapper,
|
use windows::Win32::Graphics::Direct3D12;
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(feature = "windows_rs"))]
|
use crate::auxil::dxgi::result::HResult as _;
|
||||||
use committed as allocation;
|
|
||||||
#[cfg(feature = "windows_rs")]
|
|
||||||
use placed as allocation;
|
|
||||||
|
|
||||||
// This exists to work around https://github.com/gfx-rs/wgpu/issues/3207
|
#[derive(Debug)]
|
||||||
// Currently this will work the older, slower way if the windows_rs feature is disabled,
|
pub(crate) struct GpuAllocatorWrapper {
|
||||||
// and will use the fast path of suballocating buffers and textures using gpu_allocator if
|
pub(crate) allocator: gpu_allocator::d3d12::Allocator,
|
||||||
// the windows_rs feature is enabled.
|
}
|
||||||
|
|
||||||
// This is the fast path using gpu_allocator to suballocate buffers and textures.
|
#[derive(Debug)]
|
||||||
#[cfg(feature = "windows_rs")]
|
pub(crate) struct AllocationWrapper {
|
||||||
mod placed {
|
pub(crate) allocation: gpu_allocator::d3d12::Allocation,
|
||||||
use crate::dx12::null_comptr_check;
|
}
|
||||||
use d3d12::ComPtr;
|
|
||||||
use parking_lot::Mutex;
|
pub(crate) fn create_allocator_wrapper(
|
||||||
use std::ptr;
|
raw: &Direct3D12::ID3D12Device,
|
||||||
use wgt::assertions::StrictAssertUnwrapExt;
|
memory_hints: &wgt::MemoryHints,
|
||||||
use winapi::{
|
) -> Result<Mutex<GpuAllocatorWrapper>, crate::DeviceError> {
|
||||||
um::{
|
// TODO: the allocator's configuration should take hardware capability into
|
||||||
d3d12::{self as d3d12_ty, ID3D12Resource},
|
// account.
|
||||||
winnt::HRESULT,
|
let mb = 1024 * 1024;
|
||||||
},
|
let allocation_sizes = match memory_hints {
|
||||||
Interface,
|
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::{
|
match gpu_allocator::d3d12::Allocator::new(&gpu_allocator::d3d12::AllocatorCreateDesc {
|
||||||
d3d12::{AllocationCreateDesc, ToWinapi, ToWindows},
|
device: gpu_allocator::d3d12::ID3D12DeviceVersion::Device(raw.clone()),
|
||||||
MemoryLocation,
|
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)]
|
let name = desc.label.unwrap_or("Unlabeled buffer");
|
||||||
pub(crate) struct GpuAllocatorWrapper {
|
|
||||||
pub(crate) allocator: gpu_allocator::d3d12::Allocator,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
let mut allocator = device.mem_allocator.lock();
|
||||||
pub(crate) struct AllocationWrapper {
|
|
||||||
pub(crate) allocation: gpu_allocator::d3d12::Allocation,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn create_allocator_wrapper(
|
let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc(
|
||||||
raw: &d3d12::Device,
|
allocator.allocator.device(),
|
||||||
memory_hints: &wgt::MemoryHints,
|
&raw_desc,
|
||||||
) -> Result<Option<Mutex<GpuAllocatorWrapper>>, crate::DeviceError> {
|
name,
|
||||||
let device = raw.as_ptr();
|
location,
|
||||||
|
);
|
||||||
|
let allocation = allocator.allocator.allocate(&allocation_desc)?;
|
||||||
|
|
||||||
// TODO: the allocator's configuration should take hardware capability into
|
unsafe {
|
||||||
// account.
|
device.raw.CreatePlacedResource(
|
||||||
let mb = 1024 * 1024;
|
allocation.heap(),
|
||||||
let allocation_sizes = match memory_hints {
|
allocation.offset(),
|
||||||
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(),
|
|
||||||
&raw_desc,
|
&raw_desc,
|
||||||
name,
|
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||||
location,
|
None,
|
||||||
);
|
resource,
|
||||||
let allocation = allocator.allocator.allocate(&allocation_desc)?;
|
)
|
||||||
|
}
|
||||||
|
.into_device_result("Placed buffer creation")?;
|
||||||
|
|
||||||
let hr = unsafe {
|
if resource.is_none() {
|
||||||
device.raw.CreatePlacedResource(
|
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||||
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 })))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_texture_resource(
|
device
|
||||||
device: &crate::dx12::Device,
|
.counters
|
||||||
desc: &crate::TextureDescriptor,
|
.buffer_memory
|
||||||
raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
|
.add(allocation.size() as isize);
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 location = MemoryLocation::GpuOnly;
|
||||||
let mut allocator = unsafe {
|
|
||||||
device
|
let name = desc.label.unwrap_or("Unlabeled texture");
|
||||||
.mem_allocator
|
|
||||||
.as_ref()
|
let mut allocator = device.mem_allocator.lock();
|
||||||
.strict_unwrap_unchecked()
|
let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc(
|
||||||
.lock()
|
allocator.allocator.device(),
|
||||||
};
|
&raw_desc,
|
||||||
let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc(
|
name,
|
||||||
allocator.allocator.device().as_winapi(),
|
location,
|
||||||
|
);
|
||||||
|
let allocation = allocator.allocator.allocate(&allocation_desc)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
device.raw.CreatePlacedResource(
|
||||||
|
allocation.heap(),
|
||||||
|
allocation.offset(),
|
||||||
&raw_desc,
|
&raw_desc,
|
||||||
name,
|
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||||
location,
|
None, // clear value
|
||||||
);
|
resource,
|
||||||
let allocation = allocator.allocator.allocate(&allocation_desc)?;
|
)
|
||||||
|
}
|
||||||
|
.into_device_result("Placed texture creation")?;
|
||||||
|
|
||||||
let hr = unsafe {
|
if resource.is_none() {
|
||||||
device.raw.CreatePlacedResource(
|
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||||
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 })))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn free_buffer_allocation(
|
device
|
||||||
device: &crate::dx12::Device,
|
.counters
|
||||||
allocation: AllocationWrapper,
|
.texture_memory
|
||||||
allocator: &Mutex<GpuAllocatorWrapper>,
|
.add(allocation.size() as isize);
|
||||||
) {
|
|
||||||
device
|
|
||||||
.counters
|
|
||||||
.buffer_memory
|
|
||||||
.sub(allocation.allocation.size() as isize);
|
|
||||||
match allocator.lock().allocator.free(allocation.allocation) {
|
|
||||||
Ok(_) => (),
|
|
||||||
// TODO: Don't panic here
|
|
||||||
Err(e) => panic!("Failed to destroy dx12 buffer, {e}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn free_texture_allocation(
|
Ok(Some(AllocationWrapper { 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 {
|
pub(crate) fn free_buffer_allocation(
|
||||||
fn from(result: gpu_allocator::AllocationError) -> Self {
|
device: &crate::dx12::Device,
|
||||||
match result {
|
allocation: AllocationWrapper,
|
||||||
gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory,
|
allocator: &Mutex<GpuAllocatorWrapper>,
|
||||||
gpu_allocator::AllocationError::FailedToMap(e) => {
|
) {
|
||||||
log::error!("DX12 gpu-allocator: Failed to map: {}", e);
|
device
|
||||||
Self::Lost
|
.counters
|
||||||
}
|
.buffer_memory
|
||||||
gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => {
|
.sub(allocation.allocation.size() as isize);
|
||||||
log::error!("DX12 gpu-allocator: No Compatible Memory Type Found");
|
match allocator.lock().allocator.free(allocation.allocation) {
|
||||||
Self::Lost
|
Ok(_) => (),
|
||||||
}
|
// TODO: Don't panic here
|
||||||
gpu_allocator::AllocationError::InvalidAllocationCreateDesc => {
|
Err(e) => panic!("Failed to destroy dx12 buffer, {e}"),
|
||||||
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) => {
|
pub(crate) fn free_texture_allocation(
|
||||||
log::error!("DX12 gpu-allocator: Internal Error: {}", e);
|
device: &crate::dx12::Device,
|
||||||
Self::Lost
|
allocation: AllocationWrapper,
|
||||||
}
|
allocator: &Mutex<GpuAllocatorWrapper>,
|
||||||
gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10
|
) {
|
||||||
| gpu_allocator::AllocationError::CastableFormatsRequiresEnhancedBarriers
|
device
|
||||||
| gpu_allocator::AllocationError::CastableFormatsRequiresAtLeastDevice12 => {
|
.counters
|
||||||
unreachable!()
|
.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.
|
pub(crate) fn create_committed_buffer_resource(
|
||||||
// Tracking issue for when it can be removed: https://github.com/gfx-rs/wgpu/issues/3207
|
device: &crate::dx12::Device,
|
||||||
mod committed {
|
desc: &crate::BufferDescriptor,
|
||||||
use crate::dx12::null_comptr_check;
|
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
|
||||||
use d3d12::ComPtr;
|
resource: &mut Option<Direct3D12::ID3D12Resource>,
|
||||||
use parking_lot::Mutex;
|
) -> Result<(), crate::DeviceError> {
|
||||||
use std::ptr;
|
let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
|
||||||
use winapi::{
|
let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
|
||||||
um::{
|
|
||||||
d3d12::{self as d3d12_ty, ID3D12Resource},
|
let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES {
|
||||||
winnt::HRESULT,
|
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
|
unsafe {
|
||||||
const D3D12_HEAP_FLAG_CREATE_NOT_ZEROED: d3d12_ty::D3D12_HEAP_FLAGS = 0x1000;
|
device.raw.CreateCommittedResource(
|
||||||
|
&heap_properties,
|
||||||
// Allocator isn't needed when not suballocating with gpu_allocator
|
if device.private_caps.heap_create_not_zeroed {
|
||||||
#[derive(Debug)]
|
Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
|
||||||
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
|
|
||||||
} else {
|
} else {
|
||||||
d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE
|
Direct3D12::D3D12_HEAP_FLAG_NONE
|
||||||
},
|
},
|
||||||
MemoryPoolPreference: match device.private_caps.memory_architecture {
|
&raw_desc,
|
||||||
crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => {
|
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||||
d3d12_ty::D3D12_MEMORY_POOL_L1
|
None,
|
||||||
}
|
resource,
|
||||||
_ => d3d12_ty::D3D12_MEMORY_POOL_L0,
|
)
|
||||||
},
|
}
|
||||||
CreationNodeMask: 0,
|
.into_device_result("Committed buffer creation")?;
|
||||||
VisibleNodeMask: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let hr = unsafe {
|
if resource.is_none() {
|
||||||
device.raw.CreateCommittedResource(
|
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||||
&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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_texture_resource(
|
Ok(())
|
||||||
device: &crate::dx12::Device,
|
}
|
||||||
_desc: &crate::TextureDescriptor,
|
|
||||||
raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
|
pub(crate) fn create_committed_texture_resource(
|
||||||
resource: &mut ComPtr<ID3D12Resource>,
|
device: &crate::dx12::Device,
|
||||||
) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
|
_desc: &crate::TextureDescriptor,
|
||||||
let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES {
|
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
|
||||||
Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM,
|
resource: &mut Option<Direct3D12::ID3D12Resource>,
|
||||||
CPUPageProperty: d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
) -> Result<(), crate::DeviceError> {
|
||||||
MemoryPoolPreference: match device.private_caps.memory_architecture {
|
let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES {
|
||||||
crate::dx12::MemoryArchitecture::NonUnified => d3d12_ty::D3D12_MEMORY_POOL_L1,
|
Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM,
|
||||||
crate::dx12::MemoryArchitecture::Unified { .. } => d3d12_ty::D3D12_MEMORY_POOL_L0,
|
CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
||||||
},
|
MemoryPoolPreference: match device.private_caps.memory_architecture {
|
||||||
CreationNodeMask: 0,
|
crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1,
|
||||||
VisibleNodeMask: 0,
|
crate::dx12::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0,
|
||||||
};
|
},
|
||||||
|
CreationNodeMask: 0,
|
||||||
let hr = unsafe {
|
VisibleNodeMask: 0,
|
||||||
device.raw.CreateCommittedResource(
|
};
|
||||||
&heap_properties,
|
|
||||||
if device.private_caps.heap_create_not_zeroed {
|
unsafe {
|
||||||
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
|
device.raw.CreateCommittedResource(
|
||||||
} else {
|
&heap_properties,
|
||||||
d3d12_ty::D3D12_HEAP_FLAG_NONE
|
if device.private_caps.heap_create_not_zeroed {
|
||||||
},
|
Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
|
||||||
&raw_desc,
|
} else {
|
||||||
d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
|
Direct3D12::D3D12_HEAP_FLAG_NONE
|
||||||
ptr::null(), // clear value
|
},
|
||||||
&ID3D12Resource::uuidof(),
|
&raw_desc,
|
||||||
resource.mut_void(),
|
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||||
)
|
None, // clear value
|
||||||
};
|
resource,
|
||||||
|
)
|
||||||
null_comptr_check(resource)?;
|
}
|
||||||
|
.into_device_result("Committed texture creation")?;
|
||||||
Ok((hr, None))
|
|
||||||
}
|
if resource.is_none() {
|
||||||
|
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||||
#[allow(unused)]
|
}
|
||||||
pub(crate) fn free_buffer_allocation(
|
|
||||||
_device: &crate::dx12::Device,
|
Ok(())
|
||||||
_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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,83 +1,39 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
// use here so that the recursive RIDL macro can find the crate
|
use windows::Win32::Graphics::Dxgi;
|
||||||
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
|
|
||||||
use winapi::RIDL;
|
|
||||||
|
|
||||||
RIDL! {#[uuid(0x63aad0b8, 0x7c24, 0x40ff, 0x85, 0xa8, 0x64, 0x0d, 0x94, 0x4c, 0xc3, 0x25)]
|
windows_core::imp::define_interface!(
|
||||||
interface ISwapChainPanelNative(ISwapChainPanelNativeVtbl): IUnknown(IUnknownVtbl) {
|
ISwapChainPanelNative,
|
||||||
fn SetSwapChain(swapChain: *const winapi::shared::dxgi1_2::IDXGISwapChain1,) -> winapi::um::winnt::HRESULT,
|
ISwapChainPanelNative_Vtbl,
|
||||||
}}
|
0x63aad0b8_7c24_40ff_85a8_640d944cc325
|
||||||
|
);
|
||||||
winapi::ENUM! {
|
impl core::ops::Deref for ISwapChainPanelNative {
|
||||||
enum D3D12_VIEW_INSTANCING_TIER {
|
type Target = windows_core::IUnknown;
|
||||||
D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0,
|
fn deref(&self) -> &Self::Target {
|
||||||
D3D12_VIEW_INSTANCING_TIER_1 = 1,
|
unsafe { core::mem::transmute(self) }
|
||||||
D3D12_VIEW_INSTANCING_TIER_2 = 2,
|
|
||||||
D3D12_VIEW_INSTANCING_TIER_3 = 3,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
windows_core::imp::interface_hierarchy!(ISwapChainPanelNative, windows_core::IUnknown);
|
||||||
winapi::ENUM! {
|
impl ISwapChainPanelNative {
|
||||||
enum D3D12_COMMAND_LIST_SUPPORT_FLAGS {
|
pub unsafe fn SetSwapChain<P0>(&self, swap_chain: P0) -> windows_core::Result<()>
|
||||||
D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE = 0,
|
where
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT,
|
P0: windows_core::Param<Dxgi::IDXGISwapChain1>,
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_BUNDLE,
|
{
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_COMPUTE,
|
unsafe {
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_COPY,
|
(windows_core::Interface::vtable(self).SetSwapChain)(
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_DECODE,
|
windows_core::Interface::as_raw(self),
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_PROCESS,
|
swap_chain.param().abi(),
|
||||||
// D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_ENCODE,
|
)
|
||||||
|
}
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[repr(C)]
|
||||||
winapi::STRUCT! {
|
pub struct ISwapChainPanelNative_Vtbl {
|
||||||
struct D3D12_FEATURE_DATA_D3D12_OPTIONS3 {
|
pub base__: windows_core::IUnknown_Vtbl,
|
||||||
CopyQueueTimestampQueriesSupported: winapi::shared::minwindef::BOOL,
|
pub SetSwapChain: unsafe extern "system" fn(
|
||||||
CastingFullyTypedFormatSupported: winapi::shared::minwindef::BOOL,
|
swap_chain_panel_native: *mut core::ffi::c_void,
|
||||||
WriteBufferImmediateSupportFlags: D3D12_COMMAND_LIST_SUPPORT_FLAGS,
|
swap_chain: *mut core::ffi::c_void,
|
||||||
ViewInstancingTier: D3D12_VIEW_INSTANCING_TIER,
|
) -> windows_core::HRESULT,
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
use crate::auxil;
|
use windows::Win32::Graphics::{Direct3D12, Dxgi};
|
||||||
use std::mem;
|
|
||||||
use winapi::um::d3d12 as d3d12_ty;
|
|
||||||
|
|
||||||
pub(crate) const D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING: u32 = 0x1688;
|
use crate::auxil;
|
||||||
|
|
||||||
pub(super) struct ViewDescriptor {
|
pub(super) struct ViewDescriptor {
|
||||||
dimension: wgt::TextureViewDimension,
|
dimension: wgt::TextureViewDimension,
|
||||||
pub aspects: crate::FormatAspects,
|
pub aspects: crate::FormatAspects,
|
||||||
pub rtv_dsv_format: d3d12::Format,
|
pub rtv_dsv_format: Dxgi::Common::DXGI_FORMAT,
|
||||||
srv_uav_format: Option<d3d12::Format>,
|
srv_uav_format: Option<Dxgi::Common::DXGI_FORMAT>,
|
||||||
multisampled: bool,
|
multisampled: bool,
|
||||||
array_layer_base: u32,
|
array_layer_base: u32,
|
||||||
array_layer_count: u32,
|
array_layer_count: u32,
|
||||||
@ -44,113 +42,98 @@ fn aspects_to_plane(aspects: crate::FormatAspects) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ViewDescriptor {
|
impl ViewDescriptor {
|
||||||
pub(crate) unsafe fn to_srv(&self) -> Option<d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC> {
|
pub(crate) unsafe fn to_srv(&self) -> Option<Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC> {
|
||||||
let mut desc = d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC {
|
let mut desc = Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC {
|
||||||
Format: self.srv_uav_format?,
|
Format: self.srv_uav_format?,
|
||||||
ViewDimension: 0,
|
ViewDimension: Direct3D12::D3D12_SRV_DIMENSION_UNKNOWN,
|
||||||
Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
Shader4ComponentMapping: Direct3D12::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
||||||
u: unsafe { mem::zeroed() },
|
Anonymous: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.dimension {
|
match self.dimension {
|
||||||
wgt::TextureViewDimension::D1 => {
|
wgt::TextureViewDimension::D1 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE1D;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE1D;
|
||||||
unsafe {
|
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_SRV {
|
||||||
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_SRV {
|
MostDetailedMip: self.mip_level_base,
|
||||||
MostDetailedMip: self.mip_level_base,
|
MipLevels: self.mip_level_count,
|
||||||
MipLevels: self.mip_level_count,
|
ResourceMinLODClamp: 0.0,
|
||||||
ResourceMinLODClamp: 0.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
wgt::TextureViewDimension::D1Array => {
|
wgt::TextureViewDimension::D1Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
|
||||||
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_SRV {
|
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_SRV {
|
||||||
MostDetailedMip: self.mip_level_base,
|
MostDetailedMip: self.mip_level_base,
|
||||||
MipLevels: self.mip_level_count,
|
MipLevels: self.mip_level_count,
|
||||||
FirstArraySlice: self.array_layer_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
ArraySize: self.array_layer_count,
|
ArraySize: self.array_layer_count,
|
||||||
ResourceMinLODClamp: 0.0,
|
ResourceMinLODClamp: 0.0,
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
*/
|
||||||
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DMS;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DMS;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_SRV {
|
||||||
*desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_SRV {
|
UnusedField_NothingToDefine: 0,
|
||||||
UnusedField_NothingToDefine: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2D;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||||
unsafe {
|
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_SRV {
|
||||||
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_SRV {
|
MostDetailedMip: self.mip_level_base,
|
||||||
MostDetailedMip: self.mip_level_base,
|
MipLevels: self.mip_level_count,
|
||||||
MipLevels: self.mip_level_count,
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
ResourceMinLODClamp: 0.0,
|
||||||
ResourceMinLODClamp: 0.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
|
||||||
if self.multisampled =>
|
if self.multisampled =>
|
||||||
{
|
{
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_SRV {
|
||||||
*desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_SRV {
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_SRV {
|
||||||
*desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_SRV {
|
MostDetailedMip: self.mip_level_base,
|
||||||
MostDetailedMip: self.mip_level_base,
|
MipLevels: self.mip_level_count,
|
||||||
MipLevels: self.mip_level_count,
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
ResourceMinLODClamp: 0.0,
|
||||||
ResourceMinLODClamp: 0.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D3 => {
|
wgt::TextureViewDimension::D3 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURE3D;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||||
unsafe {
|
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_SRV {
|
||||||
*desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_SRV {
|
MostDetailedMip: self.mip_level_base,
|
||||||
MostDetailedMip: self.mip_level_base,
|
MipLevels: self.mip_level_count,
|
||||||
MipLevels: self.mip_level_count,
|
ResourceMinLODClamp: 0.0,
|
||||||
ResourceMinLODClamp: 0.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::Cube if self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::Cube if self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURECUBE;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||||
unsafe {
|
desc.Anonymous.TextureCube = Direct3D12::D3D12_TEXCUBE_SRV {
|
||||||
*desc.u.TextureCube_mut() = d3d12_ty::D3D12_TEXCUBE_SRV {
|
MostDetailedMip: self.mip_level_base,
|
||||||
MostDetailedMip: self.mip_level_base,
|
MipLevels: self.mip_level_count,
|
||||||
MipLevels: self.mip_level_count,
|
ResourceMinLODClamp: 0.0,
|
||||||
ResourceMinLODClamp: 0.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
|
||||||
unsafe {
|
desc.Anonymous.TextureCubeArray = Direct3D12::D3D12_TEXCUBE_ARRAY_SRV {
|
||||||
*desc.u.TextureCubeArray_mut() = d3d12_ty::D3D12_TEXCUBE_ARRAY_SRV {
|
MostDetailedMip: self.mip_level_base,
|
||||||
MostDetailedMip: self.mip_level_base,
|
MipLevels: self.mip_level_count,
|
||||||
MipLevels: self.mip_level_count,
|
First2DArrayFace: self.array_layer_base,
|
||||||
First2DArrayFace: self.array_layer_base,
|
NumCubes: if self.array_layer_count == !0 {
|
||||||
NumCubes: if self.array_layer_count == !0 {
|
!0
|
||||||
!0
|
} else {
|
||||||
} else {
|
self.array_layer_count / 6
|
||||||
self.array_layer_count / 6
|
},
|
||||||
},
|
ResourceMinLODClamp: 0.0,
|
||||||
ResourceMinLODClamp: 0.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,59 +141,51 @@ impl ViewDescriptor {
|
|||||||
Some(desc)
|
Some(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn to_uav(&self) -> Option<d3d12_ty::D3D12_UNORDERED_ACCESS_VIEW_DESC> {
|
pub(crate) unsafe fn to_uav(&self) -> Option<Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC> {
|
||||||
let mut desc = d3d12_ty::D3D12_UNORDERED_ACCESS_VIEW_DESC {
|
let mut desc = Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
|
||||||
Format: self.srv_uav_format?,
|
Format: self.srv_uav_format?,
|
||||||
ViewDimension: 0,
|
ViewDimension: Direct3D12::D3D12_UAV_DIMENSION_UNKNOWN,
|
||||||
u: unsafe { mem::zeroed() },
|
Anonymous: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.dimension {
|
match self.dimension {
|
||||||
wgt::TextureViewDimension::D1 => {
|
wgt::TextureViewDimension::D1 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE1D;
|
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1D;
|
||||||
unsafe {
|
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_UAV {
|
||||||
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_UAV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
wgt::TextureViewDimension::D1Array => {
|
wgt::TextureViewDimension::D1Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
|
||||||
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_UAV {
|
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_UAV {
|
||||||
MipSlice: self.mip_level_base,
|
MipSlice: self.mip_level_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
ArraySize,
|
ArraySize,
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE2D;
|
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||||
unsafe {
|
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_UAV {
|
||||||
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_UAV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_UAV {
|
||||||
*desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_UAV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D3 => {
|
wgt::TextureViewDimension::D3 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_UAV_DIMENSION_TEXTURE3D;
|
desc.ViewDimension = Direct3D12::D3D12_UAV_DIMENSION_TEXTURE3D;
|
||||||
unsafe {
|
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_UAV {
|
||||||
*desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_UAV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
FirstWSlice: self.array_layer_base,
|
||||||
FirstWSlice: self.array_layer_base,
|
WSize: self.array_layer_count,
|
||||||
WSize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
||||||
@ -221,78 +196,66 @@ impl ViewDescriptor {
|
|||||||
Some(desc)
|
Some(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn to_rtv(&self) -> d3d12_ty::D3D12_RENDER_TARGET_VIEW_DESC {
|
pub(crate) unsafe fn to_rtv(&self) -> Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC {
|
||||||
let mut desc = d3d12_ty::D3D12_RENDER_TARGET_VIEW_DESC {
|
let mut desc = Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC {
|
||||||
Format: self.rtv_dsv_format,
|
Format: self.rtv_dsv_format,
|
||||||
ViewDimension: 0,
|
ViewDimension: Direct3D12::D3D12_RTV_DIMENSION_UNKNOWN,
|
||||||
u: unsafe { mem::zeroed() },
|
Anonymous: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.dimension {
|
match self.dimension {
|
||||||
wgt::TextureViewDimension::D1 => {
|
wgt::TextureViewDimension::D1 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE1D;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1D;
|
||||||
unsafe {
|
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_RTV {
|
||||||
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_RTV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
wgt::TextureViewDimension::D1Array => {
|
wgt::TextureViewDimension::D1Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
|
||||||
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_RTV {
|
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_RTV {
|
||||||
MipSlice: self.mip_level_base,
|
MipSlice: self.mip_level_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
ArraySize,
|
ArraySize,
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_RTV {
|
||||||
*desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_RTV {
|
UnusedField_NothingToDefine: 0,
|
||||||
UnusedField_NothingToDefine: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2D;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||||
unsafe {
|
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_RTV {
|
||||||
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_RTV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
|
||||||
if self.multisampled =>
|
if self.multisampled =>
|
||||||
{
|
{
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_RTV {
|
||||||
*desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_RTV {
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_RTV {
|
||||||
*desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_RTV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D3 => {
|
wgt::TextureViewDimension::D3 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_RTV_DIMENSION_TEXTURE3D;
|
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE3D;
|
||||||
unsafe {
|
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_RTV {
|
||||||
*desc.u.Texture3D_mut() = d3d12_ty::D3D12_TEX3D_RTV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
FirstWSlice: self.array_layer_base,
|
||||||
FirstWSlice: self.array_layer_base,
|
WSize: self.array_layer_count,
|
||||||
WSize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
||||||
@ -303,78 +266,72 @@ impl ViewDescriptor {
|
|||||||
desc
|
desc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn to_dsv(&self, read_only: bool) -> d3d12_ty::D3D12_DEPTH_STENCIL_VIEW_DESC {
|
pub(crate) unsafe fn to_dsv(
|
||||||
let mut desc = d3d12_ty::D3D12_DEPTH_STENCIL_VIEW_DESC {
|
&self,
|
||||||
|
read_only: bool,
|
||||||
|
) -> Direct3D12::D3D12_DEPTH_STENCIL_VIEW_DESC {
|
||||||
|
let mut desc = Direct3D12::D3D12_DEPTH_STENCIL_VIEW_DESC {
|
||||||
Format: self.rtv_dsv_format,
|
Format: self.rtv_dsv_format,
|
||||||
ViewDimension: 0,
|
ViewDimension: Direct3D12::D3D12_DSV_DIMENSION_UNKNOWN,
|
||||||
Flags: {
|
Flags: {
|
||||||
let mut flags = d3d12_ty::D3D12_DSV_FLAG_NONE;
|
let mut flags = Direct3D12::D3D12_DSV_FLAG_NONE;
|
||||||
if read_only {
|
if read_only {
|
||||||
if self.aspects.contains(crate::FormatAspects::DEPTH) {
|
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) {
|
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
|
flags
|
||||||
},
|
},
|
||||||
u: unsafe { mem::zeroed() },
|
Anonymous: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.dimension {
|
match self.dimension {
|
||||||
wgt::TextureViewDimension::D1 => {
|
wgt::TextureViewDimension::D1 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE1D;
|
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1D;
|
||||||
unsafe {
|
desc.Anonymous.Texture1D = Direct3D12::D3D12_TEX1D_DSV {
|
||||||
*desc.u.Texture1D_mut() = d3d12_ty::D3D12_TEX1D_DSV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
wgt::TextureViewDimension::D1Array => {
|
wgt::TextureViewDimension::D1Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
|
||||||
*desc.u.Texture1DArray_mut() = d3d12_ty::D3D12_TEX1D_ARRAY_DSV {
|
desc.Anonymous.Texture1DArray = Direct3D12::D3D12_TEX1D_ARRAY_DSV {
|
||||||
MipSlice: self.mip_level_base,
|
MipSlice: self.mip_level_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
ArraySize,
|
ArraySize,
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.multisampled && self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DMS;
|
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DMS;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DMS = Direct3D12::D3D12_TEX2DMS_DSV {
|
||||||
*desc.u.Texture2DMS_mut() = d3d12_ty::D3D12_TEX2DMS_DSV {
|
UnusedField_NothingToDefine: 0,
|
||||||
UnusedField_NothingToDefine: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
wgt::TextureViewDimension::D2 if self.array_layer_base == 0 => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2D;
|
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||||
unsafe {
|
|
||||||
*desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_DSV {
|
desc.Anonymous.Texture2D = Direct3D12::D3D12_TEX2D_DSV {
|
||||||
MipSlice: self.mip_level_base,
|
MipSlice: self.mip_level_base,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array
|
||||||
if self.multisampled =>
|
if self.multisampled =>
|
||||||
{
|
{
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DMSArray = Direct3D12::D3D12_TEX2DMS_ARRAY_DSV {
|
||||||
*desc.u.Texture2DMSArray_mut() = d3d12_ty::D3D12_TEX2DMS_ARRAY_DSV {
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
wgt::TextureViewDimension::D2 | wgt::TextureViewDimension::D2Array => {
|
||||||
desc.ViewDimension = d3d12_ty::D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
|
desc.ViewDimension = Direct3D12::D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
|
||||||
unsafe {
|
desc.Anonymous.Texture2DArray = Direct3D12::D3D12_TEX2D_ARRAY_DSV {
|
||||||
*desc.u.Texture2DArray_mut() = d3d12_ty::D3D12_TEX2D_ARRAY_DSV {
|
MipSlice: self.mip_level_base,
|
||||||
MipSlice: self.mip_level_base,
|
FirstArraySlice: self.array_layer_base,
|
||||||
FirstArraySlice: self.array_layer_base,
|
ArraySize: self.array_layer_count,
|
||||||
ArraySize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D3
|
wgt::TextureViewDimension::D3
|
||||||
|
@ -64,29 +64,3 @@ macro_rules! strict_assert_ne {
|
|||||||
debug_assert_ne!( $( $arg )* )
|
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 = [
|
hal = { workspace = true, features = [
|
||||||
"dxc_shader_compiler",
|
"dxc_shader_compiler",
|
||||||
"renderdoc",
|
"renderdoc",
|
||||||
"windows_rs",
|
|
||||||
] }
|
] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies.hal]
|
[target.'cfg(target_arch = "wasm32")'.dependencies.hal]
|
||||||
|
@ -332,15 +332,18 @@ pub enum SurfaceTargetUnsafe {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # 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)]
|
#[cfg(dx12)]
|
||||||
CompositionVisual(*mut std::ffi::c_void),
|
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
|
/// # 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)]
|
#[cfg(dx12)]
|
||||||
SurfaceHandle(*mut std::ffi::c_void),
|
SurfaceHandle(*mut std::ffi::c_void),
|
||||||
|
|
||||||
@ -348,7 +351,7 @@ pub enum SurfaceTargetUnsafe {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # 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)]
|
#[cfg(dx12)]
|
||||||
SwapChainPanel(*mut std::ffi::c_void),
|
SwapChainPanel(*mut std::ffi::c_void),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user