summaryrefslogtreecommitdiffstats
path: root/third_party/rust/d3d12/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/d3d12/src
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/d3d12/src')
-rw-r--r--third_party/rust/d3d12/src/com.rs263
-rw-r--r--third_party/rust/d3d12/src/command_allocator.rs14
-rw-r--r--third_party/rust/d3d12/src/command_list.rs405
-rw-r--r--third_party/rust/d3d12/src/debug.rs43
-rw-r--r--third_party/rust/d3d12/src/descriptor.rs360
-rw-r--r--third_party/rust/d3d12/src/device.rs344
-rw-r--r--third_party/rust/d3d12/src/dxgi.rs375
-rw-r--r--third_party/rust/d3d12/src/heap.rs86
-rw-r--r--third_party/rust/d3d12/src/lib.rs121
-rw-r--r--third_party/rust/d3d12/src/pso.rs169
-rw-r--r--third_party/rust/d3d12/src/query.rs15
-rw-r--r--third_party/rust/d3d12/src/queue.rs31
-rw-r--r--third_party/rust/d3d12/src/resource.rs53
-rw-r--r--third_party/rust/d3d12/src/sync.rs39
14 files changed, 2318 insertions, 0 deletions
diff --git a/third_party/rust/d3d12/src/com.rs b/third_party/rust/d3d12/src/com.rs
new file mode 100644
index 0000000000..f3a85789ce
--- /dev/null
+++ b/third_party/rust/d3d12/src/com.rs
@@ -0,0 +1,263 @@
+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 WeakPtr<T>(*mut T);
+
+impl<T> WeakPtr<T> {
+ pub fn null() -> Self {
+ WeakPtr(ptr::null_mut())
+ }
+
+ pub unsafe fn from_raw(raw: *mut T) -> Self {
+ WeakPtr(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> WeakPtr<T> {
+ pub unsafe fn as_unknown(&self) -> &IUnknown {
+ debug_assert!(!self.is_null());
+ &*(self.0 as *mut IUnknown)
+ }
+
+ // Cast creates a new WeakPtr requiring explicit destroy call.
+ pub unsafe fn cast<U>(&self) -> D3DResult<WeakPtr<U>>
+ where
+ U: Interface,
+ {
+ let mut obj = WeakPtr::<U>::null();
+ let hr = self
+ .as_unknown()
+ .QueryInterface(&U::uuidof(), obj.mut_void());
+ (obj, hr)
+ }
+
+ // Destroying one instance of the WeakPtr will invalidate all
+ // copies and clones.
+ pub unsafe fn destroy(&self) {
+ self.as_unknown().Release();
+ }
+}
+
+impl<T> Clone for WeakPtr<T> {
+ fn clone(&self) -> Self {
+ WeakPtr(self.0)
+ }
+}
+
+impl<T> Copy for WeakPtr<T> {}
+
+impl<T> Deref for WeakPtr<T> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ debug_assert!(!self.is_null());
+ unsafe { &*self.0 }
+ }
+}
+
+impl<T> fmt::Debug for WeakPtr<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "WeakPtr( ptr: {:?} )", self.0)
+ }
+}
+
+impl<T> PartialEq<*mut T> for WeakPtr<T> {
+ fn eq(&self, other: &*mut T) -> bool {
+ self.0 == *other
+ }
+}
+
+impl<T> PartialEq for WeakPtr<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+}
+
+impl<T> Hash for WeakPtr<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 (`WeakPtr<actual::ComObject1> -> Self`)
+/// - the as function (`&self -> Option<WeakPtr<actual::ComObject1>>`)
+/// - the unwrap function (`&self -> WeakPtr<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::WeakPtr<$first_type>),
+ $(
+ $variant($crate::WeakPtr<$type>)
+ ),+
+ }
+ impl $name {
+ $vis unsafe fn destroy(&self) {
+ match *self {
+ Self::$first_variant(v) => v.destroy(),
+ $(
+ Self::$variant(v) => v.destroy(),
+ )*
+ }
+ }
+
+ $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::WeakPtr<$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::WeakPtr<$type>) -> Self {
+ Self::$variant(value)
+ }
+
+ // Returns Some if the value implements the interface otherwise returns None.
+ $vis fn $as_name(&self) -> Option<&$crate::WeakPtr<$type>> {
+ match *self {
+ $(
+ Self::$prev_variant(_) => None,
+ )*
+ Self::$variant(ref v) => Some(v),
+ $(
+ Self::$next_variant(ref v) => {
+ // v is &WeakPtr<NextType> and se cast to &WeakPtr<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::WeakPtr<$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 &WeakPtr<NextType> and se cast to &WeakPtr<Type>
+ unsafe { std::mem::transmute(v) }
+ }
+ )*
+ }
+ }
+ };
+}
diff --git a/third_party/rust/d3d12/src/command_allocator.rs b/third_party/rust/d3d12/src/command_allocator.rs
new file mode 100644
index 0000000000..15b373583e
--- /dev/null
+++ b/third_party/rust/d3d12/src/command_allocator.rs
@@ -0,0 +1,14 @@
+//! Command Allocator
+
+use crate::com::WeakPtr;
+use winapi::um::d3d12;
+
+pub type CommandAllocator = WeakPtr<d3d12::ID3D12CommandAllocator>;
+
+impl CommandAllocator {
+ pub fn reset(&self) {
+ unsafe {
+ self.Reset();
+ }
+ }
+}
diff --git a/third_party/rust/d3d12/src/command_list.rs b/third_party/rust/d3d12/src/command_list.rs
new file mode 100644
index 0000000000..c426d95490
--- /dev/null
+++ b/third_party/rust/d3d12/src/command_list.rs
@@ -0,0 +1,405 @@
+//! Graphics command list
+
+use crate::{
+ com::WeakPtr, 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! {
+ 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 = WeakPtr<d3d12::ID3D12CommandSignature>;
+pub type CommandList = WeakPtr<d3d12::ID3D12CommandList>;
+pub type GraphicsCommandList = WeakPtr<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
+ }
+ }
+}
diff --git a/third_party/rust/d3d12/src/debug.rs b/third_party/rust/d3d12/src/debug.rs
new file mode 100644
index 0000000000..d7768191b7
--- /dev/null
+++ b/third_party/rust/d3d12/src/debug.rs
@@ -0,0 +1,43 @@
+use crate::com::WeakPtr;
+use winapi::um::d3d12sdklayers;
+#[cfg(any(feature = "libloading", feature = "implicit-link"))]
+use winapi::Interface as _;
+
+pub type Debug = WeakPtr<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() }
+ }
+}
diff --git a/third_party/rust/d3d12/src/descriptor.rs b/third_party/rust/d3d12/src/descriptor.rs
new file mode 100644
index 0000000000..02ca2e83c5
--- /dev/null
+++ b/third_party/rust/d3d12/src/descriptor.rs
@@ -0,0 +1,360 @@
+use crate::{com::WeakPtr, 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! {
+ pub struct DescriptorHeapFlags: u32 {
+ const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ }
+}
+
+pub type DescriptorHeap = WeakPtr<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! {
+ 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 = WeakPtr<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)
+ }
+}
diff --git a/third_party/rust/d3d12/src/device.rs b/third_party/rust/d3d12/src/device.rs
new file mode 100644
index 0000000000..188eb40b1d
--- /dev/null
+++ b/third_party/rust/d3d12/src/device.rs
@@ -0,0 +1,344 @@
+//! Device
+
+use crate::{
+ com::WeakPtr,
+ 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 = WeakPtr<d3d12::ID3D12Device>;
+
+#[cfg(feature = "libloading")]
+impl crate::D3D12Lib {
+ pub fn create_device<I: Interface>(
+ &self,
+ adapter: WeakPtr<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: WeakPtr<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)
+ }
+}
diff --git a/third_party/rust/d3d12/src/dxgi.rs b/third_party/rust/d3d12/src/dxgi.rs
new file mode 100644
index 0000000000..3c0396e88e
--- /dev/null
+++ b/third_party/rust/d3d12/src/dxgi.rs
@@ -0,0 +1,375 @@
+use crate::{com::WeakPtr, 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! {
+ 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 = WeakPtr<dxgidebug::IDXGIInfoQueue>;
+
+pub type Adapter1 = WeakPtr<dxgi::IDXGIAdapter1>;
+pub type Adapter2 = WeakPtr<dxgi1_2::IDXGIAdapter2>;
+pub type Adapter3 = WeakPtr<dxgi1_4::IDXGIAdapter3>;
+pub type Adapter4 = WeakPtr<dxgi1_6::IDXGIAdapter4>;
+crate::weak_com_inheritance_chain! {
+ #[derive(Debug, Copy, 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 = WeakPtr<dxgi::IDXGIFactory1>;
+pub type Factory2 = WeakPtr<dxgi1_2::IDXGIFactory2>;
+pub type Factory3 = WeakPtr<dxgi1_3::IDXGIFactory3>;
+pub type Factory4 = WeakPtr<dxgi1_4::IDXGIFactory4>;
+pub type Factory5 = WeakPtr<dxgi1_5::IDXGIFactory5>;
+pub type Factory6 = WeakPtr<dxgi1_6::IDXGIFactory6>;
+crate::weak_com_inheritance_chain! {
+ #[derive(Debug, Copy, 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 = WeakPtr<dxgi1_3::IDXGIFactoryMedia>;
+
+pub type SwapChain = WeakPtr<dxgi::IDXGISwapChain>;
+pub type SwapChain1 = WeakPtr<dxgi1_2::IDXGISwapChain1>;
+pub type SwapChain2 = WeakPtr<dxgi1_3::IDXGISwapChain2>;
+pub type SwapChain3 = WeakPtr<dxgi1_4::IDXGISwapChain3>;
+crate::weak_com_inheritance_chain! {
+ #[derive(Debug, Copy, 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! {
+ 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() }
+ }
+}
diff --git a/third_party/rust/d3d12/src/heap.rs b/third_party/rust/d3d12/src/heap.rs
new file mode 100644
index 0000000000..9c23bcf082
--- /dev/null
+++ b/third_party/rust/d3d12/src/heap.rs
@@ -0,0 +1,86 @@
+use crate::com::WeakPtr;
+use winapi::um::d3d12;
+
+pub type Heap = WeakPtr<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! {
+ 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(),
+ })
+ }
+}
diff --git a/third_party/rust/d3d12/src/lib.rs b/third_party/rust/d3d12/src/lib.rs
new file mode 100644
index 0000000000..e52f9d9d46
--- /dev/null
+++ b/third_party/rust/d3d12/src/lib.rs
@@ -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 = WeakPtr<d3dcommon::ID3DBlob>;
+
+pub type Error = WeakPtr<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 }) }
+ }
+}
diff --git a/third_party/rust/d3d12/src/pso.rs b/third_party/rust/d3d12/src/pso.rs
new file mode 100644
index 0000000000..e7dbc0a34b
--- /dev/null
+++ b/third_party/rust/d3d12/src/pso.rs
@@ -0,0 +1,169 @@
+//! Pipeline state
+
+use crate::{com::WeakPtr, Blob, D3DResult, Error};
+use std::{ffi, ops::Deref, ptr};
+use winapi::um::{d3d12, d3dcompiler};
+
+bitflags! {
+ pub struct PipelineStateFlags: u32 {
+ const TOOL_DEBUG = d3d12::D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG;
+ }
+}
+
+bitflags! {
+ 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(d3d12::D3D12_SHADER_BYTECODE);
+impl Shader {
+ pub fn null() -> Self {
+ Shader(d3d12::D3D12_SHADER_BYTECODE {
+ BytecodeLength: 0,
+ pShaderBytecode: ptr::null(),
+ })
+ }
+
+ pub fn from_raw(data: &[u8]) -> Self {
+ Shader(d3d12::D3D12_SHADER_BYTECODE {
+ BytecodeLength: data.len() as _,
+ pShaderBytecode: data.as_ptr() as _,
+ })
+ }
+
+ // `blob` may not be null.
+ pub fn from_blob(blob: Blob) -> Self {
+ Shader(d3d12::D3D12_SHADER_BYTECODE {
+ BytecodeLength: unsafe { blob.GetBufferSize() },
+ pShaderBytecode: unsafe { blob.GetBufferPointer() },
+ })
+ }
+
+ /// 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 Deref for Shader {
+ type Target = d3d12::D3D12_SHADER_BYTECODE;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl From<Option<Blob>> for Shader {
+ fn from(blob: Option<Blob>) -> Self {
+ match blob {
+ Some(b) => Shader::from_blob(b),
+ None => Shader::null(),
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE);
+impl CachedPSO {
+ pub fn null() -> Self {
+ CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE {
+ CachedBlobSizeInBytes: 0,
+ pCachedBlob: ptr::null(),
+ })
+ }
+
+ // `blob` may not be null.
+ pub fn from_blob(blob: Blob) -> Self {
+ CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE {
+ CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() },
+ pCachedBlob: unsafe { blob.GetBufferPointer() },
+ })
+ }
+}
+
+impl Deref for CachedPSO {
+ type Target = d3d12::D3D12_CACHED_PIPELINE_STATE;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+pub type PipelineState = WeakPtr<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,
+ }
+ }
+}
diff --git a/third_party/rust/d3d12/src/query.rs b/third_party/rust/d3d12/src/query.rs
new file mode 100644
index 0000000000..b5925c860b
--- /dev/null
+++ b/third_party/rust/d3d12/src/query.rs
@@ -0,0 +1,15 @@
+use crate::com::WeakPtr;
+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 = WeakPtr<d3d12::ID3D12QueryHeap>;
diff --git a/third_party/rust/d3d12/src/queue.rs b/third_party/rust/d3d12/src/queue.rs
new file mode 100644
index 0000000000..0f3a865c97
--- /dev/null
+++ b/third_party/rust/d3d12/src/queue.rs
@@ -0,0 +1,31 @@
+use crate::{com::WeakPtr, 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! {
+ pub struct CommandQueueFlags: u32 {
+ const DISABLE_GPU_TIMEOUT = d3d12::D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT;
+ }
+}
+
+pub type CommandQueue = WeakPtr<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) }
+ }
+}
diff --git a/third_party/rust/d3d12/src/resource.rs b/third_party/rust/d3d12/src/resource.rs
new file mode 100644
index 0000000000..a1242228cd
--- /dev/null
+++ b/third_party/rust/d3d12/src/resource.rs
@@ -0,0 +1,53 @@
+//! GPU Resource
+
+use crate::{com::WeakPtr, 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 = WeakPtr<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() }
+ }
+}
diff --git a/third_party/rust/d3d12/src/sync.rs b/third_party/rust/d3d12/src/sync.rs
new file mode 100644
index 0000000000..f1f3bb9bca
--- /dev/null
+++ b/third_party/rust/d3d12/src/sync.rs
@@ -0,0 +1,39 @@
+use crate::{com::WeakPtr, 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 = WeakPtr<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) }
+ }
+}