mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Add 'd3d12/' from commit '661dcee3f9b72c787b7aac33e4e492d9f887dc7b'
git-subtree-dir: d3d12 git-subtree-mainline:ca7ac86ccd
git-subtree-split:661dcee3f9
This commit is contained in:
commit
5663caa4a0
12
d3d12/.gitignore
vendored
Normal file
12
d3d12/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
.idea/
|
32
d3d12/CHANGELOG.md
Normal file
32
d3d12/CHANGELOG.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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
|
28
d3d12/Cargo.toml
Normal file
28
d3d12/Cargo.toml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
[package]
|
||||||
|
name = "d3d12"
|
||||||
|
version = "0.7.0"
|
||||||
|
authors = [
|
||||||
|
"gfx-rs developers",
|
||||||
|
]
|
||||||
|
description = "Low level D3D12 API wrapper"
|
||||||
|
repository = "https://github.com/gfx-rs/d3d12-rs"
|
||||||
|
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 = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags = "2"
|
||||||
|
# libloading 0.8 switches from `winapi` to `windows-sys`; permit either
|
||||||
|
libloading = { version = ">=0.7,<0.9", optional = true }
|
||||||
|
|
||||||
|
[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]
|
||||||
|
default-target = "x86_64-pc-windows-msvc"
|
6
d3d12/README.md
Normal file
6
d3d12/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# 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)
|
||||||
|
[![Matrix](https://img.shields.io/matrix/gfx:matrix.org)](https://matrix.to/#/#gfx:matrix.org)
|
||||||
|
|
||||||
|
Rust wrapper for raw D3D12 access.
|
29
d3d12/appveyor.yml
Normal file
29
d3d12/appveyor.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
skip_branch_with_pr: true
|
||||||
|
branches:
|
||||||
|
except:
|
||||||
|
- staging.tmp
|
||||||
|
environment:
|
||||||
|
global:
|
||||||
|
PATH: '%PATH%;C:\msys64\mingw64\bin;C:\msys64\usr\bin;%USERPROFILE%\.cargo\bin'
|
||||||
|
RUST_BACKTRACE: full
|
||||||
|
matrix:
|
||||||
|
- CHANNEL: stable
|
||||||
|
TARGET: x86_64-pc-windows-msvc
|
||||||
|
|
||||||
|
skip_commits:
|
||||||
|
files:
|
||||||
|
- bors.toml
|
||||||
|
- '*.md'
|
||||||
|
|
||||||
|
install:
|
||||||
|
- curl -sSf -o rustup-init.exe https://win.rustup.rs
|
||||||
|
- rustup-init -yv --default-toolchain %CHANNEL% --default-host %TARGET%
|
||||||
|
- rustc -vV
|
||||||
|
- cargo -vV
|
||||||
|
|
||||||
|
build: false
|
||||||
|
test_script:
|
||||||
|
- cargo check
|
||||||
|
- cargo check --features libloading
|
||||||
|
- cargo check --features implicit-link
|
||||||
|
- cargo check --all-features
|
5
d3d12/bors.toml
Normal file
5
d3d12/bors.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
status = [
|
||||||
|
"continuous-integration/appveyor/branch"
|
||||||
|
]
|
||||||
|
|
||||||
|
timeout_sec = 18000 # 5 hours
|
0
d3d12/rustfmt.toml
Normal file
0
d3d12/rustfmt.toml
Normal file
259
d3d12/src/com.rs
Normal file
259
d3d12/src/com.rs
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
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>` panicing 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) }
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
14
d3d12/src/command_allocator.rs
Normal file
14
d3d12/src/command_allocator.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//! 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
406
d3d12/src/command_list.rs
Normal file
406
d3d12/src/command_list.rs
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
//! 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! {
|
||||||
|
#[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,
|
||||||
|
start_vertex: VertexCount,
|
||||||
|
start_instance: InstanceCount,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
self.DrawInstanced(num_vertices, num_instances, start_vertex, start_instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_indexed(
|
||||||
|
&self,
|
||||||
|
num_indices: IndexCount,
|
||||||
|
num_instances: InstanceCount,
|
||||||
|
start_index: IndexCount,
|
||||||
|
base_vertex: VertexOffset,
|
||||||
|
start_instance: InstanceCount,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
self.DrawIndexedInstanced(
|
||||||
|
num_indices,
|
||||||
|
num_instances,
|
||||||
|
start_index,
|
||||||
|
base_vertex,
|
||||||
|
start_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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
d3d12/src/debug.rs
Normal file
43
d3d12/src/debug.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use crate::com::ComPtr;
|
||||||
|
use winapi::um::d3d12sdklayers;
|
||||||
|
#[cfg(any(feature = "libloading", feature = "implicit-link"))]
|
||||||
|
use winapi::Interface as _;
|
||||||
|
|
||||||
|
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() }
|
||||||
|
}
|
||||||
|
}
|
362
d3d12/src/descriptor.rs
Normal file
362
d3d12/src/descriptor.rs
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
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! {
|
||||||
|
#[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! {
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
|
}
|
344
d3d12/src/device.rs
Normal file
344
d3d12/src/device.rs
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
//! 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)
|
||||||
|
}
|
||||||
|
}
|
377
d3d12/src/dxgi.rs
Normal file
377
d3d12/src/dxgi.rs
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
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! {
|
||||||
|
#[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! {
|
||||||
|
#[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() }
|
||||||
|
}
|
||||||
|
}
|
87
d3d12/src/heap.rs
Normal file
87
d3d12/src/heap.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
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! {
|
||||||
|
#[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(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
121
d3d12/src/lib.rs
Normal file
121
d3d12/src/lib.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
|
|
||||||
|
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 }) }
|
||||||
|
}
|
||||||
|
}
|
162
d3d12/src/pso.rs
Normal file
162
d3d12/src/pso.rs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
//! Pipeline state
|
||||||
|
|
||||||
|
use crate::{com::ComPtr, Blob, D3DResult, Error};
|
||||||
|
use std::{ffi::{self, c_void}, ops::Deref, ptr, marker::PhantomData};
|
||||||
|
use winapi::um::{d3d12, d3dcompiler};
|
||||||
|
|
||||||
|
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! {
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
d3d12/src/query.rs
Normal file
15
d3d12/src/query.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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,
|
||||||
|
// VideoDecodeStatistcs = d3d12::D3D12_QUERY_HEAP_TYPE_VIDEO_DECODE_STATISTICS,
|
||||||
|
// CopyQueueTimestamp = d3d12::D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type QueryHeap = ComPtr<d3d12::ID3D12QueryHeap>;
|
32
d3d12/src/queue.rs
Normal file
32
d3d12/src/queue.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
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! {
|
||||||
|
#[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) }
|
||||||
|
}
|
||||||
|
}
|
53
d3d12/src/resource.rs
Normal file
53
d3d12/src/resource.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//! 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() }
|
||||||
|
}
|
||||||
|
}
|
39
d3d12/src/sync.rs
Normal file
39
d3d12/src/sync.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
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) }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user