From b1d6410c7d5e46344cebb576fb36ad78806afca2 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 26 Aug 2018 00:47:06 +0200 Subject: [PATCH 01/42] Initial commit --- .gitignore | 10 ++++++++++ README.md | 2 ++ 2 files changed, 12 insertions(+) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..088ba6ba7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# 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 diff --git a/README.md b/README.md new file mode 100644 index 000000000..444700301 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# d3d12-rs +Rust wrapper for D3D12 From a0c95c9462dff1d0574c0f04467bc547776c911e Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 26 Aug 2018 15:59:25 +0200 Subject: [PATCH 02/42] Setup bors and CI --- appveyor.yml | 26 ++++++++++++++++++++++++++ bors.toml | 5 +++++ 2 files changed, 31 insertions(+) create mode 100644 appveyor.yml create mode 100644 bors.toml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..5217fd8a8 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,26 @@ +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: + - C:\MinGW\bin\mingw32-make.exe all diff --git a/bors.toml b/bors.toml new file mode 100644 index 000000000..fc646ce92 --- /dev/null +++ b/bors.toml @@ -0,0 +1,5 @@ +status = [ + "continuous-integration/appveyor/branch" +] + +timeout_sec = 18000 # 5 hours From 4da4b1e9088ee10d7801324d976a8de67d3ac1ac Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 26 Aug 2018 12:53:16 +0200 Subject: [PATCH 03/42] Setup crate structure and wrap first interface --- Cargo.toml | 8 ++ src/com.rs | 98 ++++++++++++++ src/command_allocator.rs | 14 ++ src/command_list.rs | 218 +++++++++++++++++++++++++++++++ src/descriptor.rs | 207 ++++++++++++++++++++++++++++++ src/device.rs | 268 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 74 +++++++++++ src/pso.rs | 164 ++++++++++++++++++++++++ src/query.rs | 15 +++ src/queue.rs | 25 ++++ src/resource.rs | 57 +++++++++ src/sync.rs | 21 +++ 12 files changed, 1169 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/com.rs create mode 100644 src/command_allocator.rs create mode 100644 src/command_list.rs create mode 100644 src/descriptor.rs create mode 100644 src/device.rs create mode 100644 src/lib.rs create mode 100644 src/pso.rs create mode 100644 src/query.rs create mode 100644 src/queue.rs create mode 100644 src/resource.rs create mode 100644 src/sync.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..5e6b53e92 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "d3d12-rs" +version = "0.1.0" +authors = ["msiglreith "] + +[dependencies] +bitflags = "1" +winapi = { version = "0.3", features = ["d3d12","d3dcommon","d3dcompiler","dxgiformat","winerror"] } diff --git a/src/com.rs b/src/com.rs new file mode 100644 index 000000000..9ecc6baba --- /dev/null +++ b/src/com.rs @@ -0,0 +1,98 @@ +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; +use std::ptr; +use winapi::ctypes::c_void; +use winapi::um::unknwnbase::IUnknown; +use winapi::Interface; +use D3DResult; + +#[repr(transparent)] +pub struct WeakPtr(*mut T); + +impl WeakPtr { + pub fn null() -> Self { + WeakPtr(ptr::null_mut()) + } + + 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 unsafe fn mut_void(&mut self) -> *mut *mut c_void { + &mut self.0 as *mut *mut _ as *mut *mut _ + } +} + +impl WeakPtr { + 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(&self) -> D3DResult> + where + U: Interface, + { + let mut obj = WeakPtr::::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 Clone for WeakPtr { + fn clone(&self) -> Self { + WeakPtr(self.0) + } +} + +impl Copy for WeakPtr {} + +impl Deref for WeakPtr { + type Target = T; + fn deref(&self) -> &T { + debug_assert!(!self.is_null()); + unsafe { &*self.0 } + } +} + +impl fmt::Debug for WeakPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "WeakPtr( ptr: {:?} )", self.0) + } +} + +impl PartialEq<*mut T> for WeakPtr { + fn eq(&self, other: &*mut T) -> bool { + self.0 == *other + } +} + +impl PartialEq for WeakPtr { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Hash for WeakPtr { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} diff --git a/src/command_allocator.rs b/src/command_allocator.rs new file mode 100644 index 000000000..93bf38cce --- /dev/null +++ b/src/command_allocator.rs @@ -0,0 +1,14 @@ +//! Command Allocator + +use com::WeakPtr; +use winapi::um::d3d12; + +pub type CommandAllocator = WeakPtr; + +impl CommandAllocator { + pub fn reset(&self) { + unsafe { + self.Reset(); + } + } +} diff --git a/src/command_list.rs b/src/command_list.rs new file mode 100644 index 000000000..77108e532 --- /dev/null +++ b/src/command_list.rs @@ -0,0 +1,218 @@ +//! Graphics command list + +use com::WeakPtr; +use resource::DiscardRegion; +use std::mem; +use winapi::um::d3d12; +use { + CommandAllocator, CpuDescriptor, DescriptorHeap, Format, GpuAddress, GpuDescriptor, IndexCount, + InstanceCount, PipelineState, Rect, Resource, RootSignature, VertexCount, VertexOffset, + WorkGroupCount, HRESULT, +}; + +#[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() } + }) + } + + // TODO: missing variants +} + +pub type CommandSignature = WeakPtr; +pub type GraphicsCommandList = WeakPtr; + +impl GraphicsCommandList { + 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], + ) { + unsafe { + self.ClearDepthStencilView( + dsv, + flags.bits(), + depth, + stencil, + rects.len() as _, + rects.as_ptr(), + ); + } + } + + 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 mut ibv = d3d12::D3D12_INDEX_BUFFER_VIEW { + BufferLocation: gpu_address, + SizeInBytes: size, + Format: format, + }; + unsafe { + self.IASetIndexBuffer(&mut 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: u32, + base_descriptor: GpuDescriptor, + ) { + unsafe { + self.SetComputeRootDescriptorTable(root_index, base_descriptor); + } + } + + pub fn set_graphics_root_descriptor_table( + &self, + root_index: u32, + base_descriptor: GpuDescriptor, + ) { + unsafe { + self.SetGraphicsRootDescriptorTable(root_index, base_descriptor); + } + } +} diff --git a/src/descriptor.rs b/src/descriptor.rs new file mode 100644 index 000000000..d8e139c4a --- /dev/null +++ b/src/descriptor.rs @@ -0,0 +1,207 @@ +use com::WeakPtr; +use std::mem; +use std::ops::Range; +use winapi::um::d3d12; +use {Blob, D3DResult, Error, TextureAddressMode}; + +pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE; +pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE; + +#[repr(u32)] +#[derive(Clone, Copy)] +pub enum HeapType { + 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 HeapFlags: u32 { + const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + } +} + +pub type DescriptorHeap = WeakPtr; + +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)] +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)] +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_register: u32, + register_space: u32, + offset: u32, + ) -> Self { + DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE { + RangeType: ty as _, + NumDescriptors: count, + BaseShaderRegister: base_register, + RegisterSpace: register_space, + OffsetInDescriptorsFromTableStart: offset, + }) + } +} + +#[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, + register: u32, + register_space: u32, + 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: register, + RegisterSpace: register_space, + Num32BitValues: num, + }; + + RootParameter(param) + } +} + +#[repr(u32)] +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, + register: u32, + register_space: u32, + + 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, + ) -> 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: register, + RegisterSpace: register_space, + ShaderVisibility: visibility as _, + }) + } +} + +#[repr(u32)] +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; + +impl RootSignature { + pub fn serialize( + version: RootSignatureVersion, + parameters: &[RootParameter], + static_samplers: &[StaticSampler], + flags: RootSignatureFlags, + ) -> D3DResult<(Blob, Error)> { + 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) + } +} diff --git a/src/device.rs b/src/device.rs new file mode 100644 index 000000000..5ae6a8017 --- /dev/null +++ b/src/device.rs @@ -0,0 +1,268 @@ +//! Device + +use com::WeakPtr; +use command_list::{CmdListType, CommandSignature, IndirectArgument}; +use descriptor::{CpuDescriptor, HeapFlags, HeapType}; +use std::ops::Range; +use winapi::um::d3d12; +use winapi::Interface; +use {pso, query, queue}; +use { + Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, FeatureLevel, + GraphicsCommandList, NodeMask, PipelineState, QueryHeap, RootSignature, Shader, + TextureAddressMode, +}; + +pub type Device = WeakPtr; + +impl Device { + pub fn create( + adapter: WeakPtr, + feature_level: FeatureLevel, + ) -> D3DResult { + 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_command_allocator(&self, list_type: CmdListType) -> D3DResult { + 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 { + 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: HeapType, + flags: HeapFlags, + node_mask: NodeMask, + ) -> D3DResult { + 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: HeapType) -> 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 { + 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::HeapType, + count: u32, + node_mask: NodeMask, + ) -> D3DResult { + 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 { + unimplemented!() + } + + pub fn create_compute_pipeline_state( + &self, + root_signature: RootSignature, + cs: Shader, + node_mask: NodeMask, + cached_pso: CachedPSO, + flags: pso::PipelineStateFlags, + ) -> D3DResult { + 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, + ) { + 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 { + 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 { + 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::ID3D12RootSignature::uuidof(), + signature.mut_void(), + ) + }; + + (signature, hr) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..036ff059e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,74 @@ +extern crate winapi; +#[macro_use] +extern crate bitflags; + +use std::ffi::CStr; +use winapi::shared::dxgiformat; +use winapi::um::{d3d12, d3dcommon}; + +mod com; +pub mod command_allocator; +pub mod command_list; +pub mod descriptor; +pub mod device; +pub mod pso; +pub mod query; +pub mod queue; +pub mod resource; +pub mod sync; + +pub use self::com::WeakPtr; +pub use self::command_allocator::CommandAllocator; +pub use self::command_list::{CommandSignature, GraphicsCommandList}; +pub use self::descriptor::{CpuDescriptor, DescriptorHeap, GpuDescriptor, RootSignature}; +pub use self::device::Device; +pub use self::pso::{CachedPSO, PipelineState, Shader}; +pub use self::query::QueryHeap; +pub use self::queue::CommandQueue; +pub use self::resource::{Heap, Resource}; +pub use self::sync::Fence; + +pub use winapi::shared::winerror::HRESULT; + +pub type D3DResult = (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; + +/// 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]; + +#[repr(u32)] +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, +} + +pub type Blob = self::com::WeakPtr; + +pub type Error = self::com::WeakPtr; +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 _) + } +} diff --git a/src/pso.rs b/src/pso.rs new file mode 100644 index 000000000..9feb379a4 --- /dev/null +++ b/src/pso.rs @@ -0,0 +1,164 @@ +//! Pipeline state + +use com::WeakPtr; +use std::ops::Deref; +use std::{ffi, ptr}; +use winapi::um::{d3d12, d3dcompiler}; +use {Blob, D3DResult, Error}; + +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(), + }) + } + + // `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> for Shader { + fn from(blob: Option) -> 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; + +#[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 { + subobject_align: [usize; 0], // Subobjects must have the same alignment as pointers. + subobject_type: d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE, + subobject: T, +} + +impl PipelineStateSubobject { + pub fn new(subobject_type: Subobject, subobject: T) -> Self { + PipelineStateSubobject { + subobject_align: [], + subobject_type: subobject_type as _, + subobject, + } + } +} diff --git a/src/query.rs b/src/query.rs new file mode 100644 index 000000000..1df33fd2f --- /dev/null +++ b/src/query.rs @@ -0,0 +1,15 @@ +use com::WeakPtr; +use winapi::um::d3d12; + +#[repr(u32)] +#[derive(Debug, Copy, Clone)] +pub enum HeapType { + 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; diff --git a/src/queue.rs b/src/queue.rs new file mode 100644 index 000000000..eb11504ea --- /dev/null +++ b/src/queue.rs @@ -0,0 +1,25 @@ +use com::WeakPtr; +use sync::Fence; +use winapi::um::d3d12; +use HRESULT; + +#[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; + +impl CommandQueue { + pub fn signal(&self, fence: Fence, value: u64) -> HRESULT { + unsafe { self.Signal(fence.as_mut_ptr(), value) } + } +} diff --git a/src/resource.rs b/src/resource.rs new file mode 100644 index 000000000..dd866a9f4 --- /dev/null +++ b/src/resource.rs @@ -0,0 +1,57 @@ +//! GPU Resource + +use com::WeakPtr; +use std::ops::Range; +use std::ptr; +use winapi::um::d3d12; +use {D3DResult, Rect}; + +pub type Subresource = u32; + +pub struct DiscardRegion<'a> { + pub rects: &'a [Rect], + pub subregions: Range, +} + +pub type Heap = WeakPtr; + +pub type Resource = WeakPtr; + +impl Resource { + /// + pub fn map( + &self, + subresource: Subresource, + read_range: Option>, + ) -> 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>) { + 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/src/sync.rs b/src/sync.rs new file mode 100644 index 000000000..c10c73519 --- /dev/null +++ b/src/sync.rs @@ -0,0 +1,21 @@ +use com::WeakPtr; +use winapi::um::d3d12; +use winapi::um::winnt; +use HRESULT; + +pub type Event = winnt::HANDLE; +pub type Fence = WeakPtr; + +impl Fence { + pub fn set_event_on_completion(&self, event: Event, value: u64) -> HRESULT { + unsafe { self.SetEventOnCompletion(value, event) } + } + + pub fn get_value(&self) -> u64 { + unsafe { self.GetCompletedValue() } + } + + pub fn signal(&self, value: u64) -> HRESULT { + unsafe { self.Signal(value) } + } +} From 0d3487960ae434fc0efe029da0fc914d014a53db Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 26 Aug 2018 16:10:27 +0200 Subject: [PATCH 04/42] Fix appveyor build --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5217fd8a8..39dc970a9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,4 +23,4 @@ install: build: false test_script: - - C:\MinGW\bin\mingw32-make.exe all + - cargo check From 5e4b1b879545d41af3e93cd181adb0de11ce871d Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sat, 1 Sep 2018 00:02:39 +0200 Subject: [PATCH 05/42] Fix command signature uuid --- src/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device.rs b/src/device.rs index 5ae6a8017..fc34810b7 100644 --- a/src/device.rs +++ b/src/device.rs @@ -258,7 +258,7 @@ impl Device { self.CreateCommandSignature( &desc, root_signature.as_mut_ptr(), - &d3d12::ID3D12RootSignature::uuidof(), + &d3d12::ID3D12CommandSignature::uuidof(), signature.mut_void(), ) }; From 56770dce927e50bcfc3112dd2626771d7a06c704 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sat, 1 Sep 2018 16:57:38 +0200 Subject: [PATCH 06/42] Add struct for descriptor binding --- src/descriptor.rs | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/descriptor.rs b/src/descriptor.rs index d8e139c4a..97a2e19a6 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -7,6 +7,11 @@ use {Blob, D3DResult, Error, TextureAddressMode}; pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE; pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE; +pub struct Binding { + pub register: u32, + pub space: u32, +} + #[repr(u32)] #[derive(Clone, Copy)] pub enum HeapType { @@ -57,18 +62,12 @@ pub enum DescriptorRangeType { #[repr(transparent)] pub struct DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE); impl DescriptorRange { - pub fn new( - ty: DescriptorRangeType, - count: u32, - base_register: u32, - register_space: u32, - offset: u32, - ) -> Self { + 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_register, - RegisterSpace: register_space, + BaseShaderRegister: base_binding.register, + RegisterSpace: base_binding.space, OffsetInDescriptorsFromTableStart: offset, }) } @@ -93,12 +92,7 @@ impl RootParameter { RootParameter(param) } - pub fn constants( - visibility: ShaderVisibility, - register: u32, - register_space: u32, - num: u32, - ) -> Self { + 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 _, @@ -106,8 +100,8 @@ impl RootParameter { }; *unsafe { param.u.Constants_mut() } = d3d12::D3D12_ROOT_CONSTANTS { - ShaderRegister: register, - RegisterSpace: register_space, + ShaderRegister: binding.register, + RegisterSpace: binding.space, Num32BitValues: num, }; @@ -127,8 +121,7 @@ pub struct StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC); impl StaticSampler { pub fn new( visibility: ShaderVisibility, - register: u32, - register_space: u32, + binding: Binding, filter: d3d12::D3D12_FILTER, address_mode: TextureAddressMode, @@ -149,8 +142,8 @@ impl StaticSampler { BorderColor: border_color as _, MinLOD: lod.start, MaxLOD: lod.end, - ShaderRegister: register, - RegisterSpace: register_space, + ShaderRegister: binding.register, + RegisterSpace: binding.space, ShaderVisibility: visibility as _, }) } From 2aacc3b11bad0886b3e2e541fac6967bf204e42c Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 2 Sep 2018 14:11:18 +0200 Subject: [PATCH 07/42] Add debug interface, factory creation and adapter enumeration --- Cargo.toml | 4 ++-- src/debug.rs | 21 +++++++++++++++++++++ src/dxgi.rs | 35 +++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/debug.rs create mode 100644 src/dxgi.rs diff --git a/Cargo.toml b/Cargo.toml index 5e6b53e92..9e054e3be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "d3d12-rs" +name = "d3d12" version = "0.1.0" authors = ["msiglreith "] [dependencies] bitflags = "1" -winapi = { version = "0.3", features = ["d3d12","d3dcommon","d3dcompiler","dxgiformat","winerror"] } +winapi = { version = "0.3", features = ["dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","winerror"] } diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 000000000..450beeac7 --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,21 @@ +use com::WeakPtr; +use winapi::um::{d3d12, d3d12sdklayers}; +use winapi::Interface; +use D3DResult; + +pub type Debug = WeakPtr; + +impl Debug { + pub fn get_debug_interface() -> D3DResult { + let mut debug = Debug::null(); + let hr = unsafe { + d3d12::D3D12GetDebugInterface(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void()) + }; + + (debug, hr) + } + + pub fn enable_debug_layer(&self) { + unsafe { self.EnableDebugLayer() } + } +} diff --git a/src/dxgi.rs b/src/dxgi.rs new file mode 100644 index 000000000..22d0d7352 --- /dev/null +++ b/src/dxgi.rs @@ -0,0 +1,35 @@ +use com::WeakPtr; +use winapi::shared::{dxgi, dxgi1_3, dxgi1_4}; +use winapi::Interface; +use D3DResult; + +bitflags! { + pub struct FactoryCreationFlags: u32 { + const DEBUG = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG; + } +} + +pub type Adapter1 = WeakPtr; +pub type Factory4 = WeakPtr; + +impl Factory4 { + pub fn create(flags: FactoryCreationFlags) -> D3DResult { + 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 { + let mut adapter = Adapter1::null(); + let hr = unsafe { self.EnumAdapters1(id, adapter.mut_void() as *mut *mut _) }; + + (adapter, hr) + } +} diff --git a/src/lib.rs b/src/lib.rs index 036ff059e..5434912ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,10 @@ use winapi::um::{d3d12, d3dcommon}; mod com; pub mod command_allocator; pub mod command_list; +pub mod debug; pub mod descriptor; pub mod device; +pub mod dxgi; pub mod pso; pub mod query; pub mod queue; @@ -20,6 +22,7 @@ pub mod sync; pub use self::com::WeakPtr; pub use self::command_allocator::CommandAllocator; pub use self::command_list::{CommandSignature, GraphicsCommandList}; +pub use self::debug::Debug; pub use self::descriptor::{CpuDescriptor, DescriptorHeap, GpuDescriptor, RootSignature}; pub use self::device::Device; pub use self::pso::{CachedPSO, PipelineState, Shader}; From 908c29ed7e37bf6119c10b76c4e15eb7d5ce026f Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 2 Sep 2018 18:37:44 +0200 Subject: [PATCH 08/42] Add swapchain handling and 2d RTV creation --- Cargo.toml | 5 +- src/com.rs | 4 ++ src/command_list.rs | 6 +++ src/descriptor.rs | 21 ++++++++ src/device.rs | 15 +++++- src/dxgi.rs | 129 +++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 5 ++ 7 files changed, 180 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e054e3be..451272962 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,7 @@ authors = ["msiglreith "] [dependencies] bitflags = "1" -winapi = { version = "0.3", features = ["dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","winerror"] } + +[dependencies.winapi] +version = "0.3" +features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","winerror"] \ No newline at end of file diff --git a/src/com.rs b/src/com.rs index 9ecc6baba..dc76b6f3c 100644 --- a/src/com.rs +++ b/src/com.rs @@ -15,6 +15,10 @@ impl WeakPtr { 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() } diff --git a/src/command_list.rs b/src/command_list.rs index 77108e532..64fb76a4f 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -103,6 +103,12 @@ impl GraphicsCommandList { } } + pub fn clear_render_target_view(&self, rtv: CpuDescriptor, color: [f32; 4], rects: &[Rect]) { + unsafe { + self.ClearRenderTargetView(rtv, &color, rects.len() as _, rects.as_ptr()); + } + } + pub fn dispatch(&self, count: WorkGroupCount) { unsafe { self.Dispatch(count[0], count[1], count[2]); diff --git a/src/descriptor.rs b/src/descriptor.rs index 97a2e19a6..c5e70d863 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -1,6 +1,7 @@ use com::WeakPtr; use std::mem; use std::ops::Range; +use winapi::shared::dxgiformat; use winapi::um::d3d12; use {Blob, D3DResult, Error, TextureAddressMode}; @@ -198,3 +199,23 @@ impl RootSignature { ((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/src/device.rs b/src/device.rs index fc34810b7..33781064a 100644 --- a/src/device.rs +++ b/src/device.rs @@ -2,14 +2,14 @@ use com::WeakPtr; use command_list::{CmdListType, CommandSignature, IndirectArgument}; -use descriptor::{CpuDescriptor, HeapFlags, HeapType}; +use descriptor::{CpuDescriptor, HeapFlags, HeapType, RenderTargetViewDesc}; use std::ops::Range; use winapi::um::d3d12; use winapi::Interface; use {pso, query, queue}; use { Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, FeatureLevel, - GraphicsCommandList, NodeMask, PipelineState, QueryHeap, RootSignature, Shader, + GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, TextureAddressMode, }; @@ -265,4 +265,15 @@ impl Device { (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); + } + } } diff --git a/src/dxgi.rs b/src/dxgi.rs index 22d0d7352..1dade86b8 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -1,7 +1,10 @@ use com::WeakPtr; -use winapi::shared::{dxgi, dxgi1_3, dxgi1_4}; +use std::ptr; +use winapi::shared::windef::HWND; +use winapi::shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype}; +use winapi::um::d3d12; use winapi::Interface; -use D3DResult; +use {CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; bitflags! { pub struct FactoryCreationFlags: u32 { @@ -9,8 +12,95 @@ bitflags! { } } +#[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 Adapter1 = WeakPtr; +pub type Factory2 = WeakPtr; pub type Factory4 = WeakPtr; +pub type SwapChain = WeakPtr; +pub type SwapChain1 = WeakPtr; +pub type SwapChain3 = WeakPtr; + +// 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 Factory2 { + // TODO: interface not complete + pub fn create_swapchain_for_hwnd( + &self, + queue: CommandQueue, + hwnd: HWND, + desc: &SwapchainDesc, + ) -> D3DResult { + let desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 { + AlphaMode: desc.alpha_mode as _, + BufferCount: desc.buffer_count, + Width: desc.width, + Height: desc.height, + Format: desc.format, + Flags: desc.flags, + BufferUsage: desc.buffer_usage, + SampleDesc: dxgitype::DXGI_SAMPLE_DESC { + Count: desc.sample.count, + Quality: desc.sample.quality, + }, + Scaling: desc.scaling as _, + Stereo: desc.stereo as _, + SwapEffect: desc.swap_effect as _, + }; + + let mut swap_chain = SwapChain1::null(); + let hr = unsafe { + self.CreateSwapChainForHwnd( + queue.as_mut_ptr() as *mut _, + hwnd, + &desc, + ptr::null(), + ptr::null_mut(), + swap_chain.mut_void() as *mut *mut _, + ) + }; + + (swap_chain, hr) + } +} impl Factory4 { pub fn create(flags: FactoryCreationFlags) -> D3DResult { @@ -26,6 +116,10 @@ impl Factory4 { (factory, hr) } + pub fn as2(&self) -> Factory2 { + unsafe { Factory2::from_raw(self.as_mut_ptr() as *mut _) } + } + pub fn enumerate_adapters(&self, id: u32) -> D3DResult { let mut adapter = Adapter1::null(); let hr = unsafe { self.EnumAdapters1(id, adapter.mut_void() as *mut *mut _) }; @@ -33,3 +127,34 @@ impl Factory4 { (adapter, hr) } } + +impl SwapChain { + pub fn get_buffer(&self, id: u32) -> D3DResult { + let mut resource = Resource::null(); + let hr = + unsafe { self.GetBuffer(id, &d3d12::ID3D12Resource::uuidof(), resource.mut_void()) }; + + (resource, hr) + } + + // TODO: present flags + pub fn present(&self, interval: u32, flags: u32) -> HRESULT { + unsafe { self.Present(interval, flags) } + } +} + +impl SwapChain1 { + pub fn as0(&self) -> SwapChain { + unsafe { SwapChain::from_raw(self.as_mut_ptr() as *mut _) } + } +} + +impl SwapChain3 { + pub fn as0(&self) -> SwapChain { + unsafe { SwapChain::from_raw(self.as_mut_ptr() as *mut _) } + } + + pub fn get_current_back_buffer_index(&self) -> u32 { + unsafe { self.GetCurrentBackBufferIndex() } + } +} diff --git a/src/lib.rs b/src/lib.rs index 5434912ff..0712584ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,11 @@ 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)] pub enum FeatureLevel { L9_1 = d3dcommon::D3D_FEATURE_LEVEL_9_1, From e6ba80cb3922f32022adbde16d4963bc7bb2fabf Mon Sep 17 00:00:00 2001 From: msiglreith Date: Tue, 4 Sep 2018 19:09:23 +0200 Subject: [PATCH 09/42] Extend event and fence support --- Cargo.toml | 2 +- src/command_list.rs | 5 +++++ src/device.rs | 19 +++++++++++++++++-- src/sync.rs | 28 ++++++++++++++++++++++++---- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 451272962..1063f5d08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,4 @@ bitflags = "1" [dependencies.winapi] version = "0.3" -features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","winerror"] \ No newline at end of file +features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] \ No newline at end of file diff --git a/src/command_list.rs b/src/command_list.rs index 64fb76a4f..e3725b95b 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -57,9 +57,14 @@ impl IndirectArgument { } pub type CommandSignature = WeakPtr; +pub type CommandList = WeakPtr; pub type GraphicsCommandList = WeakPtr; 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() } } diff --git a/src/device.rs b/src/device.rs index 33781064a..376c30418 100644 --- a/src/device.rs +++ b/src/device.rs @@ -9,8 +9,8 @@ use winapi::Interface; use {pso, query, queue}; use { Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, FeatureLevel, - GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, - TextureAddressMode, + Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, + Shader, TextureAddressMode, }; pub type Device = WeakPtr; @@ -276,4 +276,19 @@ impl Device { self.CreateRenderTargetView(resource.as_mut_ptr(), &desc.0 as *const _, descriptor); } } + + // TODO: interface not complete + pub fn create_fence(&self, initial: u64) -> D3DResult { + 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/src/sync.rs b/src/sync.rs index c10c73519..650fa6d00 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,14 +1,34 @@ use com::WeakPtr; +use std::ptr; use winapi::um::d3d12; -use winapi::um::winnt; +use winapi::um::{synchapi, winnt}; use HRESULT; -pub type Event = winnt::HANDLE; -pub type Fence = WeakPtr; +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct Event(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; impl Fence { pub fn set_event_on_completion(&self, event: Event, value: u64) -> HRESULT { - unsafe { self.SetEventOnCompletion(value, event) } + unsafe { self.SetEventOnCompletion(value, event.0) } } pub fn get_value(&self) -> u64 { From bf7f2e68441f387b83b8bfb2c44654b1a38c8d89 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Mon, 10 Sep 2018 18:17:37 +0200 Subject: [PATCH 10/42] Address review comments --- Cargo.toml | 2 +- src/debug.rs | 4 ++-- src/dxgi.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1063f5d08..393b6cb19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,4 @@ bitflags = "1" [dependencies.winapi] version = "0.3" -features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] \ No newline at end of file +features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] diff --git a/src/debug.rs b/src/debug.rs index 450beeac7..f614a27fa 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -6,7 +6,7 @@ use D3DResult; pub type Debug = WeakPtr; impl Debug { - pub fn get_debug_interface() -> D3DResult { + pub fn get_interface() -> D3DResult { let mut debug = Debug::null(); let hr = unsafe { d3d12::D3D12GetDebugInterface(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void()) @@ -15,7 +15,7 @@ impl Debug { (debug, hr) } - pub fn enable_debug_layer(&self) { + pub fn enable_layer(&self) { unsafe { self.EnableDebugLayer() } } } diff --git a/src/dxgi.rs b/src/dxgi.rs index 1dade86b8..ad8b91e44 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -116,7 +116,7 @@ impl Factory4 { (factory, hr) } - pub fn as2(&self) -> Factory2 { + pub fn as_factory2(&self) -> Factory2 { unsafe { Factory2::from_raw(self.as_mut_ptr() as *mut _) } } @@ -144,13 +144,13 @@ impl SwapChain { } impl SwapChain1 { - pub fn as0(&self) -> SwapChain { + pub fn as_swapchain0(&self) -> SwapChain { unsafe { SwapChain::from_raw(self.as_mut_ptr() as *mut _) } } } impl SwapChain3 { - pub fn as0(&self) -> SwapChain { + pub fn as_swapchain0(&self) -> SwapChain { unsafe { SwapChain::from_raw(self.as_mut_ptr() as *mut _) } } From 4a938bd1d473d674c4991612c02044a70e8be824 Mon Sep 17 00:00:00 2001 From: Attila Dusnoki Date: Tue, 6 Nov 2018 14:39:38 +0100 Subject: [PATCH 11/42] Add rects length check for clears --- src/command_list.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/command_list.rs b/src/command_list.rs index e3725b95b..a9a787b48 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -2,7 +2,7 @@ use com::WeakPtr; use resource::DiscardRegion; -use std::mem; +use std::{mem, ptr}; use winapi::um::d3d12; use { CommandAllocator, CpuDescriptor, DescriptorHeap, Format, GpuAddress, GpuDescriptor, IndexCount, @@ -96,21 +96,33 @@ impl GraphicsCommandList { 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, - rects.len() as _, - rects.as_ptr(), + 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, rects.len() as _, rects.as_ptr()); + self.ClearRenderTargetView(rtv, &color, num_rects, rects); } } From 09d68b3cb987288e075038ef1ca16ceed7d92f62 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Thu, 8 Nov 2018 18:13:37 +0100 Subject: [PATCH 12/42] Expose event internal and Event in root level --- src/lib.rs | 2 +- src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0712584ef..2ea9d576a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ pub use self::pso::{CachedPSO, PipelineState, Shader}; pub use self::query::QueryHeap; pub use self::queue::CommandQueue; pub use self::resource::{Heap, Resource}; -pub use self::sync::Fence; +pub use self::sync::{Event, Fence}; pub use winapi::shared::winerror::HRESULT; diff --git a/src/sync.rs b/src/sync.rs index 650fa6d00..77d8b17c9 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -6,7 +6,7 @@ use HRESULT; #[derive(Copy, Clone)] #[repr(transparent)] -pub struct Event(winnt::HANDLE); +pub struct Event(pub winnt::HANDLE); impl Event { pub fn create(manual_reset: bool, initial_state: bool) -> Self { Event(unsafe { From 3e15f7c86ece6a4915fe34247b4b6f2dac7a2441 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 26 Dec 2018 21:24:41 -0500 Subject: [PATCH 13/42] Add missing cargo metadata for the release --- Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 393b6cb19..f1365b312 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,12 @@ name = "d3d12" version = "0.1.0" authors = ["msiglreith "] +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 = ["memory-management"] [dependencies] bitflags = "1" From 4af1f9d2fd9bd87914cb9bb951ec2c79f13df778 Mon Sep 17 00:00:00 2001 From: David Dubois Date: Thu, 18 Jul 2019 23:35:53 -0700 Subject: [PATCH 14/42] Add ID3D12Heap, and related structs and methods `D3D12_HEAP_TYPE, D3D12_CPU_PAGE_PROPERTY, D3D12_MEMORY_POOL, D3D12_HEAP_FLAGS, D3D12_HEAP_PROPERTIES, and D3D12_HEAP_DESC ID3D12Heap Wrap ID3D12Device::CreateHeap Made a tricky enum because DX12 doesn't follow Rust's rules bump version to 0.2.0 Use bitflags for heap::Flags Fix typo Another typo fix --- .gitignore | 2 ++ Cargo.toml | 2 +- src/device.rs | 26 +++++++++++++++ src/heap.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/heap.rs diff --git a/.gitignore b/.gitignore index 088ba6ba7..cbed4d71a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +.idea/ diff --git a/Cargo.toml b/Cargo.toml index f1365b312..c241090f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.1.0" +version = "0.2.1" authors = ["msiglreith "] description = "Low level D3D12 API wrapper" repository = "https://github.com/gfx-rs/d3d12-rs" diff --git a/src/device.rs b/src/device.rs index 376c30418..0dd175de4 100644 --- a/src/device.rs +++ b/src/device.rs @@ -12,6 +12,7 @@ use { Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, TextureAddressMode, }; +use heap::{Properties, Flags, Heap}; pub type Device = WeakPtr; @@ -33,6 +34,31 @@ impl Device { (device, hr) } + pub fn create_heap(&self, + size_in_bytes: u64, + properties: Properties, + alignment: u64, + flags: Flags) -> D3DResult { + 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 { let mut allocator = CommandAllocator::null(); let hr = unsafe { diff --git a/src/heap.rs b/src/heap.rs new file mode 100644 index 000000000..82f3c5983 --- /dev/null +++ b/src/heap.rs @@ -0,0 +1,87 @@ +use com::WeakPtr; +use winapi::um::d3d12; + +pub type Heap = WeakPtr; + +#[repr(u32)] +#[derive(Clone, Copy)] +pub enum Type { + 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 Flags: 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 Properties(pub d3d12::D3D12_HEAP_PROPERTIES); +impl Properties { + pub fn new( + heap_type: Type, + cpu_page_property: CpuPageProperty, + memory_pool_preference: MemoryPool, + creation_node_mask: u32, + visible_node_mask: u32, + ) -> Self { + Properties(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 Desc(d3d12::D3D12_HEAP_DESC); +impl Desc{ + pub fn new( + size_in_bytes: u64, + properties: Properties, + alignment: u64, + flags: Flags, + ) -> Self { + Desc(d3d12::D3D12_HEAP_DESC{ + SizeInBytes: size_in_bytes, + Properties: properties.0, + Alignment: alignment, + Flags: flags.bits(), + }) + } +} + diff --git a/src/lib.rs b/src/lib.rs index 2ea9d576a..1a9cfee16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ pub mod debug; pub mod descriptor; pub mod device; pub mod dxgi; +pub mod heap; pub mod pso; pub mod query; pub mod queue; @@ -25,6 +26,7 @@ pub use self::command_list::{CommandSignature, GraphicsCommandList}; pub use self::debug::Debug; pub use self::descriptor::{CpuDescriptor, DescriptorHeap, GpuDescriptor, RootSignature}; pub use self::device::Device; +pub use self::heap::Properties; pub use self::pso::{CachedPSO, PipelineState, Shader}; pub use self::query::QueryHeap; pub use self::queue::CommandQueue; From 0a4a86ecbcffd01f3b01cfad57410b610044ba56 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Thu, 3 Oct 2019 19:53:43 +0200 Subject: [PATCH 15/42] Add root descriptor --- src/descriptor.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/descriptor.rs b/src/descriptor.rs index c5e70d863..2b48b752d 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -108,6 +108,33 @@ impl RootParameter { RootParameter(param) } + + 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) + } } #[repr(u32)] From f4043cd1cc1c829dc38cb92f5edbeca74ea75471 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Fri, 4 Oct 2019 00:52:50 +0200 Subject: [PATCH 16/42] Add root descriptor commands and add trait derives --- src/command_list.rs | 69 +++++++++++++++++++++++++++++++++++++++------ src/descriptor.rs | 15 +++++++--- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/command_list.rs b/src/command_list.rs index a9a787b48..7db8d120b 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -103,14 +103,7 @@ impl GraphicsCommandList { ptr::null() }; unsafe { - self.ClearDepthStencilView( - dsv, - flags.bits(), - depth, - stencil, - num_rects, - rects, - ); + self.ClearDepthStencilView(dsv, flags.bits(), depth, stencil, num_rects, rects); } } @@ -229,6 +222,36 @@ impl GraphicsCommandList { } } + pub fn set_compute_root_constant_buffer_view( + &self, + root_index: u32, + buffer_location: GpuAddress, + ) { + unsafe { + self.SetComputeRootConstantBufferView(root_index, buffer_location); + } + } + + pub fn set_compute_root_shader_resource_view( + &self, + root_index: u32, + buffer_location: GpuAddress, + ) { + unsafe { + self.SetComputeRootShaderResourceView(root_index, buffer_location); + } + } + + pub fn set_compute_root_unordered_access_view( + &self, + root_index: u32, + buffer_location: GpuAddress, + ) { + unsafe { + self.SetComputeRootUnorderedAccessView(root_index, buffer_location); + } + } + pub fn set_graphics_root_descriptor_table( &self, root_index: u32, @@ -238,4 +261,34 @@ impl GraphicsCommandList { self.SetGraphicsRootDescriptorTable(root_index, base_descriptor); } } + + pub fn set_graphics_root_constant_buffer_view( + &self, + root_index: u32, + buffer_location: GpuAddress, + ) { + unsafe { + self.SetGraphicsRootConstantBufferView(root_index, buffer_location); + } + } + + pub fn set_graphics_root_shader_resource_view( + &self, + root_index: u32, + buffer_location: GpuAddress, + ) { + unsafe { + self.SetGraphicsRootShaderResourceView(root_index, buffer_location); + } + } + + pub fn set_graphics_root_unordered_access_view( + &self, + root_index: u32, + buffer_location: GpuAddress, + ) { + unsafe { + self.SetGraphicsRootUnorderedAccessView(root_index, buffer_location); + } + } } diff --git a/src/descriptor.rs b/src/descriptor.rs index 2b48b752d..cfe24e2da 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -8,13 +8,14 @@ use {Blob, D3DResult, Error, TextureAddressMode}; pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE; pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE; +#[derive(Clone, Copy, Debug)] pub struct Binding { pub register: u32, pub space: u32, } #[repr(u32)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum HeapType { CbvSrvUav = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Sampler = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, @@ -41,7 +42,7 @@ impl DescriptorHeap { } #[repr(u32)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum ShaderVisibility { All = d3d12::D3D12_SHADER_VISIBILITY_ALL, VS = d3d12::D3D12_SHADER_VISIBILITY_VERTEX, @@ -52,7 +53,7 @@ pub enum ShaderVisibility { } #[repr(u32)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum DescriptorRangeType { SRV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV, UAV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV, @@ -109,7 +110,11 @@ impl RootParameter { RootParameter(param) } - fn descriptor(ty: d3d12::D3D12_ROOT_PARAMETER_TYPE, visibility: ShaderVisibility, binding: Binding) -> Self { + 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 _, @@ -138,6 +143,7 @@ impl RootParameter { } #[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, @@ -178,6 +184,7 @@ impl StaticSampler { } #[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, From 241a6387b833b735d54909bc7cdaa79639525f72 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Fri, 4 Oct 2019 23:25:00 +0200 Subject: [PATCH 17/42] Bump version to 0.2.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c241090f0..886569486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.2.1" +version = "0.2.2" authors = ["msiglreith "] description = "Low level D3D12 API wrapper" repository = "https://github.com/gfx-rs/d3d12-rs" From 8bac8b582f534173086e9758ad0619afb6912e60 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Tue, 15 Oct 2019 20:17:36 +0200 Subject: [PATCH 18/42] Remove one layer of modules and Queue::execute_command_lists --- src/descriptor.rs | 4 ++-- src/device.rs | 10 +++++----- src/lib.rs | 49 ++++++++++++++++++++++++----------------------- src/query.rs | 2 +- src/queue.rs | 9 +++++++++ 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/descriptor.rs b/src/descriptor.rs index cfe24e2da..9fd1e207e 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -16,7 +16,7 @@ pub struct Binding { #[repr(u32)] #[derive(Clone, Copy, Debug)] -pub enum HeapType { +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, @@ -24,7 +24,7 @@ pub enum HeapType { } bitflags! { - pub struct HeapFlags: u32 { + pub struct DescriptorHeapFlags: u32 { const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; } } diff --git a/src/device.rs b/src/device.rs index 0dd175de4..79f1d6a93 100644 --- a/src/device.rs +++ b/src/device.rs @@ -2,7 +2,7 @@ use com::WeakPtr; use command_list::{CmdListType, CommandSignature, IndirectArgument}; -use descriptor::{CpuDescriptor, HeapFlags, HeapType, RenderTargetViewDesc}; +use descriptor::{CpuDescriptor, DescriptorHeapFlags, DescriptorHeapType, RenderTargetViewDesc}; use std::ops::Range; use winapi::um::d3d12; use winapi::Interface; @@ -101,8 +101,8 @@ impl Device { pub fn create_descriptor_heap( &self, num_descriptors: u32, - heap_type: HeapType, - flags: HeapFlags, + heap_type: DescriptorHeapType, + flags: DescriptorHeapFlags, node_mask: NodeMask, ) -> D3DResult { let desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC { @@ -124,7 +124,7 @@ impl Device { (heap, hr) } - pub fn get_descriptor_increment_size(&self, heap_type: HeapType) -> u32 { + pub fn get_descriptor_increment_size(&self, heap_type: DescriptorHeapType) -> u32 { unsafe { self.GetDescriptorHandleIncrementSize(heap_type as _) } } @@ -152,7 +152,7 @@ impl Device { pub fn create_query_heap( &self, - heap_ty: query::HeapType, + heap_ty: query::QueryHeapType, count: u32, node_mask: NodeMask, ) -> D3DResult { diff --git a/src/lib.rs b/src/lib.rs index 1a9cfee16..b681f09a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,31 +7,32 @@ use winapi::shared::dxgiformat; use winapi::um::{d3d12, d3dcommon}; mod com; -pub mod command_allocator; -pub mod command_list; -pub mod debug; -pub mod descriptor; -pub mod device; -pub mod dxgi; -pub mod heap; -pub mod pso; -pub mod query; -pub mod queue; -pub mod resource; -pub mod sync; +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 self::com::WeakPtr; -pub use self::command_allocator::CommandAllocator; -pub use self::command_list::{CommandSignature, GraphicsCommandList}; -pub use self::debug::Debug; -pub use self::descriptor::{CpuDescriptor, DescriptorHeap, GpuDescriptor, RootSignature}; -pub use self::device::Device; -pub use self::heap::Properties; -pub use self::pso::{CachedPSO, PipelineState, Shader}; -pub use self::query::QueryHeap; -pub use self::queue::CommandQueue; -pub use self::resource::{Heap, Resource}; -pub use self::sync::{Event, Fence}; +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; diff --git a/src/query.rs b/src/query.rs index 1df33fd2f..0620b73ea 100644 --- a/src/query.rs +++ b/src/query.rs @@ -3,7 +3,7 @@ use winapi::um::d3d12; #[repr(u32)] #[derive(Debug, Copy, Clone)] -pub enum HeapType { +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, diff --git a/src/queue.rs b/src/queue.rs index eb11504ea..d1bd0f408 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,3 +1,4 @@ +use crate::CommandList; use com::WeakPtr; use sync::Fence; use winapi::um::d3d12; @@ -19,6 +20,14 @@ bitflags! { pub type CommandQueue = WeakPtr; impl CommandQueue { + pub fn execute_command_lists(&self, command_lists: &[CommandList]) { + let command_lists = command_lists + .iter() + .map(CommandList::as_mut_ptr) + .collect::>(); + 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) } } From aa2b674248f7d7281a2c7705aa2d89efa71c83f6 Mon Sep 17 00:00:00 2001 From: msiglreith Date: Thu, 17 Oct 2019 23:47:59 +0200 Subject: [PATCH 19/42] Resource transition barriers and prefix heap types --- src/command_list.rs | 34 ++++++++++++++++++++++++++++++++++ src/device.rs | 24 ++++++++++-------------- src/heap.rs | 25 ++++++++++++------------- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/command_list.rs b/src/command_list.rs index 7db8d120b..d756ced45 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -56,6 +56,34 @@ impl IndirectArgument { // TODO: missing variants } +#[repr(transparent)] +pub struct ResourceBarrier(d3d12::D3D12_RESOURCE_BARRIER); + +impl ResourceBarrier { + pub fn transition( + resource: Resource, + subresource: u32, + 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; pub type CommandList = WeakPtr; pub type GraphicsCommandList = WeakPtr; @@ -291,4 +319,10 @@ impl GraphicsCommandList { self.SetGraphicsRootUnorderedAccessView(root_index, buffer_location); } } + + pub fn resource_barrier(&self, barriers: &[ResourceBarrier]) { + unsafe { + self.ResourceBarrier(barriers.len() as _, barriers.as_ptr() as _) // matches representation + } + } } diff --git a/src/device.rs b/src/device.rs index 79f1d6a93..fd3fa5f59 100644 --- a/src/device.rs +++ b/src/device.rs @@ -3,6 +3,7 @@ use com::WeakPtr; use command_list::{CmdListType, CommandSignature, IndirectArgument}; use descriptor::{CpuDescriptor, DescriptorHeapFlags, DescriptorHeapType, RenderTargetViewDesc}; +use heap::{Heap, HeapFlags, HeapProperties}; use std::ops::Range; use winapi::um::d3d12; use winapi::Interface; @@ -12,7 +13,6 @@ use { Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, TextureAddressMode, }; -use heap::{Properties, Flags, Heap}; pub type Device = WeakPtr; @@ -34,27 +34,23 @@ impl Device { (device, hr) } - pub fn create_heap(&self, - size_in_bytes: u64, - properties: Properties, - alignment: u64, - flags: Flags) -> D3DResult { + pub fn create_heap( + &self, + size_in_bytes: u64, + properties: HeapProperties, + alignment: u64, + flags: HeapFlags, + ) -> D3DResult { let mut heap = Heap::null(); - let desc = d3d12::D3D12_HEAP_DESC{ + 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(), - ) - }; + let hr = unsafe { self.CreateHeap(&desc, &d3d12::ID3D12Heap::uuidof(), heap.mut_void()) }; (heap, hr) } diff --git a/src/heap.rs b/src/heap.rs index 82f3c5983..de97dbf50 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -5,7 +5,7 @@ pub type Heap = WeakPtr; #[repr(u32)] #[derive(Clone, Copy)] -pub enum Type { +pub enum HeapType { Default = d3d12::D3D12_HEAP_TYPE_DEFAULT, Upload = d3d12::D3D12_HEAP_TYPE_UPLOAD, Readback = d3d12::D3D12_HEAP_TYPE_READBACK, @@ -18,7 +18,7 @@ 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, + WriteBack = d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK, } #[repr(u32)] @@ -30,7 +30,7 @@ pub enum MemoryPool { } bitflags! { - pub struct Flags: u32 { + 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; @@ -48,16 +48,16 @@ bitflags! { } #[repr(transparent)] -pub struct Properties(pub d3d12::D3D12_HEAP_PROPERTIES); -impl Properties { +pub struct HeapProperties(pub d3d12::D3D12_HEAP_PROPERTIES); +impl HeapProperties { pub fn new( - heap_type: Type, + heap_type: HeapType, cpu_page_property: CpuPageProperty, memory_pool_preference: MemoryPool, creation_node_mask: u32, visible_node_mask: u32, ) -> Self { - Properties(d3d12::D3D12_HEAP_PROPERTIES { + HeapProperties(d3d12::D3D12_HEAP_PROPERTIES { Type: heap_type as _, CPUPageProperty: cpu_page_property as _, MemoryPoolPreference: memory_pool_preference as _, @@ -68,15 +68,15 @@ impl Properties { } #[repr(transparent)] -pub struct Desc(d3d12::D3D12_HEAP_DESC); -impl Desc{ +pub struct HeapDesc(d3d12::D3D12_HEAP_DESC); +impl HeapDesc { pub fn new( size_in_bytes: u64, - properties: Properties, + properties: HeapProperties, alignment: u64, - flags: Flags, + flags: HeapFlags, ) -> Self { - Desc(d3d12::D3D12_HEAP_DESC{ + HeapDesc(d3d12::D3D12_HEAP_DESC { SizeInBytes: size_in_bytes, Properties: properties.0, Alignment: alignment, @@ -84,4 +84,3 @@ impl Desc{ }) } } - From 14fafbc7bd4ec4e620f0c1acb4ffc0f036ce4a06 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 31 Oct 2019 15:47:44 -0400 Subject: [PATCH 20/42] Dynamic loading for D3D12 device and DXGI --- Cargo.toml | 6 ++++- appveyor.yml | 3 +++ src/debug.rs | 37 ++++++++++++++++++++++++----- src/descriptor.rs | 46 ++++++++++++++++++++++++++++++++++-- src/device.rs | 34 +++++++++++++++++++++++++-- src/dxgi.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 5 ++++ 7 files changed, 179 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 886569486..c7e24f2c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,9 +9,13 @@ license = "MIT OR Apache-2.0" documentation = "https://docs.rs/d3d12" categories = ["memory-management"] +[features] +libstatic = [] + [dependencies] bitflags = "1" +libloading = { version = "0.5", optional = true } [dependencies.winapi] version = "0.3" -features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] +features = ["dxgi1_2","dxgi1_3","dxgi1_4","dxgidebug","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] diff --git a/appveyor.yml b/appveyor.yml index 39dc970a9..f71194b85 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,3 +24,6 @@ install: build: false test_script: - cargo check + - cargo check --features libloading + - cargo check --features libstatic + - cargo check --all-features diff --git a/src/debug.rs b/src/debug.rs index f614a27fa..a5d3d1654 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,15 +1,40 @@ use com::WeakPtr; -use winapi::um::{d3d12, d3d12sdklayers}; -use winapi::Interface; -use D3DResult; +#[cfg(any(feature = "libloading", feature = "libstatic"))] +use winapi::Interface as _; +use winapi::um::d3d12sdklayers; pub type Debug = WeakPtr; -impl Debug { - pub fn get_interface() -> D3DResult { +#[cfg(feature = "libloading")] +impl crate::D3D12Lib { + pub fn get_debug_interface(&self) -> libloading::Result> { + 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 { - d3d12::D3D12GetDebugInterface(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void()) + let func: libloading::Symbol = self.lib.get(b"D3D12GetDebugInterface")?; + func( + &d3d12sdklayers::ID3D12Debug::uuidof(), + debug.mut_void(), + ) + }; + + Ok((debug, hr)) + } +} + +impl Debug { + #[cfg(feature = "libstatic")] + pub fn get_interface() -> crate::D3DResult { + let mut debug = Debug::null(); + let hr = unsafe { + winapi::um::d3d12::D3D12GetDebugInterface( + &d3d12sdklayers::ID3D12Debug::uuidof(), + debug.mut_void(), + ) }; (debug, hr) diff --git a/src/descriptor.rs b/src/descriptor.rs index 9fd1e207e..3403e359d 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -156,7 +156,6 @@ impl StaticSampler { pub fn new( visibility: ShaderVisibility, binding: Binding, - filter: d3d12::D3D12_FILTER, address_mode: TextureAddressMode, mip_lod_bias: f32, @@ -202,14 +201,57 @@ bitflags! { } pub type RootSignature = WeakPtr; +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, + ) -> libloading::Result { + 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 = 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 = "libstatic")] pub fn serialize( version: RootSignatureVersion, parameters: &[RootParameter], static_samplers: &[StaticSampler], flags: RootSignatureFlags, - ) -> D3DResult<(Blob, Error)> { + ) -> BlobResult { let mut blob = Blob::null(); let mut error = Error::null(); diff --git a/src/device.rs b/src/device.rs index fd3fa5f59..4e9307a8e 100644 --- a/src/device.rs +++ b/src/device.rs @@ -9,17 +9,47 @@ use winapi::um::d3d12; use winapi::Interface; use {pso, query, queue}; use { - Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, FeatureLevel, + Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, TextureAddressMode, }; pub type Device = WeakPtr; +#[cfg(feature = "libloading")] +impl crate::D3D12Lib { + pub fn create_device( + &self, + adapter: WeakPtr, + feature_level: crate::FeatureLevel, + ) -> libloading::Result> { + 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 = 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 = "libstatic")] pub fn create( adapter: WeakPtr, - feature_level: FeatureLevel, + feature_level: crate::FeatureLevel, ) -> D3DResult { let mut device = Device::null(); let hr = unsafe { diff --git a/src/dxgi.rs b/src/dxgi.rs index ad8b91e44..14a971e32 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -2,7 +2,7 @@ use com::WeakPtr; use std::ptr; use winapi::shared::windef::HWND; use winapi::shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype}; -use winapi::um::d3d12; +use winapi::um::{dxgidebug, d3d12}; use winapi::Interface; use {CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; @@ -42,10 +42,67 @@ pub enum AlphaMode { pub type Adapter1 = WeakPtr; pub type Factory2 = WeakPtr; pub type Factory4 = WeakPtr; +pub type InfoQueue = WeakPtr; pub type SwapChain = WeakPtr; pub type SwapChain1 = WeakPtr; pub type SwapChain3 = WeakPtr; +#[cfg(feature = "libloading")] +pub struct DxgiLib { + lib: libloading::Library, +} + +#[cfg(feature = "libloading")] +impl DxgiLib { + pub fn new() -> libloading::Result { + libloading::Library::new("dxgi.dll") + .map(|lib| DxgiLib { + lib, + }) + } + + pub fn create_factory2( + &self, flags: FactoryCreationFlags + ) -> libloading::Result> { + 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 = self.lib.get(b"CreateDXGIFactory2")?; + func( + flags.bits(), + &dxgi1_4::IDXGIFactory4::uuidof(), + factory.mut_void(), + ) + }; + + Ok((factory, hr)) + } + + pub fn get_debug_interface1(&self) -> libloading::Result> { + 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 = 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, @@ -103,6 +160,7 @@ impl Factory2 { } impl Factory4 { + #[cfg(feature = "libstatic")] pub fn create(flags: FactoryCreationFlags) -> D3DResult { let mut factory = Factory4::null(); let hr = unsafe { diff --git a/src/lib.rs b/src/lib.rs index b681f09a5..71c7e78f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,3 +83,8 @@ impl Error { CStr::from_ptr(data as *const _ as *const _) } } + +#[cfg(feature = "libloading")] +pub struct D3D12Lib { + lib: libloading::Library, +} From 029c24d9cfaf4347efc157aebe01662b0aafb61b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 31 Oct 2019 21:50:06 -0400 Subject: [PATCH 21/42] Preparations for 0.3 release Including: - rename feature "libstatic" to "implicit-link" - Debug and constructor implementations for the library structs - removal of redundant Heap definition --- Cargo.toml | 9 ++++++--- appveyor.yml | 2 +- src/debug.rs | 4 ++-- src/descriptor.rs | 2 +- src/device.rs | 2 +- src/dxgi.rs | 3 ++- src/lib.rs | 11 +++++++++++ src/resource.rs | 2 -- 8 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7e24f2c0..8f83d845b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "d3d12" -version = "0.2.2" -authors = ["msiglreith "] +version = "0.3.0" +authors = [ + "msiglreith ", + "Dzmitry Malyshau ", +] description = "Low level D3D12 API wrapper" repository = "https://github.com/gfx-rs/d3d12-rs" keywords = ["windows", "graphics"] @@ -10,7 +13,7 @@ documentation = "https://docs.rs/d3d12" categories = ["memory-management"] [features] -libstatic = [] +implicit-link = [] [dependencies] bitflags = "1" diff --git a/appveyor.yml b/appveyor.yml index f71194b85..b947c526b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,5 +25,5 @@ build: false test_script: - cargo check - cargo check --features libloading - - cargo check --features libstatic + - cargo check --features implicit-link - cargo check --all-features diff --git a/src/debug.rs b/src/debug.rs index a5d3d1654..00ec52219 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,5 +1,5 @@ use com::WeakPtr; -#[cfg(any(feature = "libloading", feature = "libstatic"))] +#[cfg(any(feature = "libloading", feature = "implicit-link"))] use winapi::Interface as _; use winapi::um::d3d12sdklayers; @@ -27,7 +27,7 @@ impl crate::D3D12Lib { } impl Debug { - #[cfg(feature = "libstatic")] + #[cfg(feature = "implicit-link")] pub fn get_interface() -> crate::D3DResult { let mut debug = Debug::null(); let hr = unsafe { diff --git a/src/descriptor.rs b/src/descriptor.rs index 3403e359d..ecf4eed2f 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -245,7 +245,7 @@ impl crate::D3D12Lib { } impl RootSignature { - #[cfg(feature = "libstatic")] + #[cfg(feature = "implicit-link")] pub fn serialize( version: RootSignatureVersion, parameters: &[RootParameter], diff --git a/src/device.rs b/src/device.rs index 4e9307a8e..6393d9bd7 100644 --- a/src/device.rs +++ b/src/device.rs @@ -46,7 +46,7 @@ impl crate::D3D12Lib { } impl Device { - #[cfg(feature = "libstatic")] + #[cfg(feature = "implicit-link")] pub fn create( adapter: WeakPtr, feature_level: crate::FeatureLevel, diff --git a/src/dxgi.rs b/src/dxgi.rs index 14a971e32..fe6c961a0 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -48,6 +48,7 @@ pub type SwapChain1 = WeakPtr; pub type SwapChain3 = WeakPtr; #[cfg(feature = "libloading")] +#[derive(Debug)] pub struct DxgiLib { lib: libloading::Library, } @@ -160,7 +161,7 @@ impl Factory2 { } impl Factory4 { - #[cfg(feature = "libstatic")] + #[cfg(feature = "implicit-link")] pub fn create(flags: FactoryCreationFlags) -> D3DResult { let mut factory = Factory4::null(); let hr = unsafe { diff --git a/src/lib.rs b/src/lib.rs index 71c7e78f9..d1e88e860 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,6 +85,17 @@ impl Error { } #[cfg(feature = "libloading")] +#[derive(Debug)] pub struct D3D12Lib { lib: libloading::Library, } + +#[cfg(feature = "libloading")] +impl D3D12Lib { + pub fn new() -> libloading::Result { + libloading::Library::new("d3d12.dll") + .map(|lib| D3D12Lib { + lib, + }) + } +} diff --git a/src/resource.rs b/src/resource.rs index dd866a9f4..f87b8768d 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -13,8 +13,6 @@ pub struct DiscardRegion<'a> { pub subregions: Range, } -pub type Heap = WeakPtr; - pub type Resource = WeakPtr; impl Resource { From b721376bba6bc5225f8a4d767fbd8b888ce083cb Mon Sep 17 00:00:00 2001 From: msiglreith Date: Fri, 1 Nov 2019 11:46:42 +0100 Subject: [PATCH 22/42] Use windows as default doc target --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index c7e24f2c0..d7d0f4296 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,6 @@ libloading = { version = "0.5", optional = true } [dependencies.winapi] version = "0.3" features = ["dxgi1_2","dxgi1_3","dxgi1_4","dxgidebug","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] + +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" From 65c9326b2258d7c6a3518e8b0e74f808809d4c4a Mon Sep 17 00:00:00 2001 From: msiglreith Date: Sun, 3 Nov 2019 17:38:41 +0100 Subject: [PATCH 23/42] Shader from raw IL --- src/pso.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pso.rs b/src/pso.rs index 9feb379a4..365f4ad94 100644 --- a/src/pso.rs +++ b/src/pso.rs @@ -34,6 +34,13 @@ impl Shader { }) } + 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 { From 832f1243a4f67e1383ea0ef8599a03f5f65c8e58 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 29 Jun 2020 17:29:09 -0400 Subject: [PATCH 24/42] Bump libloading to 0.6 --- Cargo.toml | 2 +- src/debug.rs | 2 +- src/descriptor.rs | 2 +- src/device.rs | 2 +- src/dxgi.rs | 6 +++--- src/lib.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 34ca18019..55bd80d87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ implicit-link = [] [dependencies] bitflags = "1" -libloading = { version = "0.5", optional = true } +libloading = { version = "0.6", optional = true } [dependencies.winapi] version = "0.3" diff --git a/src/debug.rs b/src/debug.rs index 00ec52219..50f675fa2 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -7,7 +7,7 @@ pub type Debug = WeakPtr; #[cfg(feature = "libloading")] impl crate::D3D12Lib { - pub fn get_debug_interface(&self) -> libloading::Result> { + pub fn get_debug_interface(&self) -> Result, libloading::Error> { type Fun = extern "system" fn( winapi::shared::guiddef::REFIID, *mut *mut winapi::ctypes::c_void, diff --git a/src/descriptor.rs b/src/descriptor.rs index ecf4eed2f..7a3cd8095 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -211,7 +211,7 @@ impl crate::D3D12Lib { parameters: &[RootParameter], static_samplers: &[StaticSampler], flags: RootSignatureFlags, - ) -> libloading::Result { + ) -> Result { use winapi::um::d3dcommon::ID3DBlob; type Fun = extern "system" fn( *const d3d12::D3D12_ROOT_SIGNATURE_DESC, diff --git a/src/device.rs b/src/device.rs index 6393d9bd7..61e2573a0 100644 --- a/src/device.rs +++ b/src/device.rs @@ -22,7 +22,7 @@ impl crate::D3D12Lib { &self, adapter: WeakPtr, feature_level: crate::FeatureLevel, - ) -> libloading::Result> { + ) -> Result, libloading::Error> { type Fun = extern "system" fn( *mut winapi::um::unknwnbase::IUnknown, winapi::um::d3dcommon::D3D_FEATURE_LEVEL, diff --git a/src/dxgi.rs b/src/dxgi.rs index fe6c961a0..dee9a5bca 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -55,7 +55,7 @@ pub struct DxgiLib { #[cfg(feature = "libloading")] impl DxgiLib { - pub fn new() -> libloading::Result { + pub fn new() -> Result { libloading::Library::new("dxgi.dll") .map(|lib| DxgiLib { lib, @@ -64,7 +64,7 @@ impl DxgiLib { pub fn create_factory2( &self, flags: FactoryCreationFlags - ) -> libloading::Result> { + ) -> Result, libloading::Error> { type Fun = extern "system" fn( winapi::shared::minwindef::UINT, winapi::shared::guiddef::REFIID, @@ -84,7 +84,7 @@ impl DxgiLib { Ok((factory, hr)) } - pub fn get_debug_interface1(&self) -> libloading::Result> { + pub fn get_debug_interface1(&self) -> Result, libloading::Error> { type Fun = extern "system" fn( winapi::shared::minwindef::UINT, winapi::shared::guiddef::REFIID, diff --git a/src/lib.rs b/src/lib.rs index d1e88e860..b18c54c5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,7 +92,7 @@ pub struct D3D12Lib { #[cfg(feature = "libloading")] impl D3D12Lib { - pub fn new() -> libloading::Result { + pub fn new() -> Result { libloading::Library::new("d3d12.dll") .map(|lib| D3D12Lib { lib, From 9017c8db013ac998d964302d2f388d2cb62ce5d6 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 7 Jul 2020 10:01:53 -0400 Subject: [PATCH 25/42] Rustfmt pass --- src/debug.rs | 9 +++------ src/device.rs | 8 ++++---- src/dxgi.rs | 16 +++++----------- src/lib.rs | 5 +---- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/debug.rs b/src/debug.rs index 50f675fa2..5f8445be6 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,7 +1,7 @@ use com::WeakPtr; +use winapi::um::d3d12sdklayers; #[cfg(any(feature = "libloading", feature = "implicit-link"))] use winapi::Interface as _; -use winapi::um::d3d12sdklayers; pub type Debug = WeakPtr; @@ -16,14 +16,11 @@ impl crate::D3D12Lib { let mut debug = Debug::null(); let hr = unsafe { let func: libloading::Symbol = self.lib.get(b"D3D12GetDebugInterface")?; - func( - &d3d12sdklayers::ID3D12Debug::uuidof(), - debug.mut_void(), - ) + func(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void()) }; Ok((debug, hr)) - } + } } impl Debug { diff --git a/src/device.rs b/src/device.rs index 61e2573a0..9a5235650 100644 --- a/src/device.rs +++ b/src/device.rs @@ -9,9 +9,9 @@ use winapi::um::d3d12; use winapi::Interface; use {pso, query, queue}; use { - Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, - Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, - Shader, TextureAddressMode, + Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, Fence, + GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, + TextureAddressMode, }; pub type Device = WeakPtr; @@ -27,7 +27,7 @@ impl crate::D3D12Lib { *mut winapi::um::unknwnbase::IUnknown, winapi::um::d3dcommon::D3D_FEATURE_LEVEL, winapi::shared::guiddef::REFGUID, - *mut *mut winapi::ctypes::c_void, + *mut *mut winapi::ctypes::c_void, ) -> crate::HRESULT; let mut device = Device::null(); diff --git a/src/dxgi.rs b/src/dxgi.rs index dee9a5bca..2db54049e 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -2,7 +2,7 @@ use com::WeakPtr; use std::ptr; use winapi::shared::windef::HWND; use winapi::shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype}; -use winapi::um::{dxgidebug, d3d12}; +use winapi::um::{d3d12, dxgidebug}; use winapi::Interface; use {CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; @@ -56,14 +56,12 @@ pub struct DxgiLib { #[cfg(feature = "libloading")] impl DxgiLib { pub fn new() -> Result { - libloading::Library::new("dxgi.dll") - .map(|lib| DxgiLib { - lib, - }) + libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) } pub fn create_factory2( - &self, flags: FactoryCreationFlags + &self, + flags: FactoryCreationFlags, ) -> Result, libloading::Error> { type Fun = extern "system" fn( winapi::shared::minwindef::UINT, @@ -94,11 +92,7 @@ impl DxgiLib { let mut queue = InfoQueue::null(); let hr = unsafe { let func: libloading::Symbol = self.lib.get(b"DXGIGetDebugInterface1")?; - func( - 0, - &dxgidebug::IDXGIInfoQueue::uuidof(), - queue.mut_void(), - ) + func(0, &dxgidebug::IDXGIInfoQueue::uuidof(), queue.mut_void()) }; Ok((queue, hr)) } diff --git a/src/lib.rs b/src/lib.rs index b18c54c5d..0fe470205 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,9 +93,6 @@ pub struct D3D12Lib { #[cfg(feature = "libloading")] impl D3D12Lib { pub fn new() -> Result { - libloading::Library::new("d3d12.dll") - .map(|lib| D3D12Lib { - lib, - }) + libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) } } From 9a2b5bdb00574c7385a654399694dba28338a313 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 7 Jul 2020 10:09:50 -0400 Subject: [PATCH 26/42] Convert to Rust2018 --- Cargo.toml | 3 ++- src/com.rs | 16 ++++++++-------- src/command_allocator.rs | 2 +- src/command_list.rs | 12 +++++------- src/debug.rs | 2 +- src/descriptor.rs | 9 +++------ src/device.rs | 22 ++++++++++------------ src/dxgi.rs | 12 ++++++------ src/heap.rs | 2 +- src/lib.rs | 7 ++++--- src/pso.rs | 6 ++---- src/query.rs | 2 +- src/queue.rs | 5 +---- src/resource.rs | 6 ++---- src/sync.rs | 6 ++---- 15 files changed, 49 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 55bd80d87..aa2d305d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ repository = "https://github.com/gfx-rs/d3d12-rs" keywords = ["windows", "graphics"] license = "MIT OR Apache-2.0" documentation = "https://docs.rs/d3d12" -categories = ["memory-management"] +categories = ["api-bindings", "graphics", "memory-management", "os::windows-apis"] +edition = "2018" [features] implicit-link = [] diff --git a/src/com.rs b/src/com.rs index dc76b6f3c..7007060a1 100644 --- a/src/com.rs +++ b/src/com.rs @@ -1,11 +1,11 @@ -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::ptr; -use winapi::ctypes::c_void; -use winapi::um::unknwnbase::IUnknown; -use winapi::Interface; -use D3DResult; +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(*mut T); diff --git a/src/command_allocator.rs b/src/command_allocator.rs index 93bf38cce..15b373583 100644 --- a/src/command_allocator.rs +++ b/src/command_allocator.rs @@ -1,6 +1,6 @@ //! Command Allocator -use com::WeakPtr; +use crate::com::WeakPtr; use winapi::um::d3d12; pub type CommandAllocator = WeakPtr; diff --git a/src/command_list.rs b/src/command_list.rs index d756ced45..4fc3f6ea4 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -1,14 +1,12 @@ //! Graphics command list -use com::WeakPtr; -use resource::DiscardRegion; +use crate::{ + com::WeakPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format, + GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, + RootSignature, VertexCount, VertexOffset, WorkGroupCount, HRESULT, +}; use std::{mem, ptr}; use winapi::um::d3d12; -use { - CommandAllocator, CpuDescriptor, DescriptorHeap, Format, GpuAddress, GpuDescriptor, IndexCount, - InstanceCount, PipelineState, Rect, Resource, RootSignature, VertexCount, VertexOffset, - WorkGroupCount, HRESULT, -}; #[repr(u32)] #[derive(Clone, Copy)] diff --git a/src/debug.rs b/src/debug.rs index 5f8445be6..d7768191b 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,4 +1,4 @@ -use com::WeakPtr; +use crate::com::WeakPtr; use winapi::um::d3d12sdklayers; #[cfg(any(feature = "libloading", feature = "implicit-link"))] use winapi::Interface as _; diff --git a/src/descriptor.rs b/src/descriptor.rs index 7a3cd8095..2304e259c 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -1,9 +1,6 @@ -use com::WeakPtr; -use std::mem; -use std::ops::Range; -use winapi::shared::dxgiformat; -use winapi::um::d3d12; -use {Blob, D3DResult, Error, TextureAddressMode}; +use crate::{com::WeakPtr, Blob, D3DResult, Error, TextureAddressMode}; +use std::{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; diff --git a/src/device.rs b/src/device.rs index 9a5235650..188eb40b1 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,18 +1,16 @@ //! Device -use com::WeakPtr; -use command_list::{CmdListType, CommandSignature, IndirectArgument}; -use descriptor::{CpuDescriptor, DescriptorHeapFlags, DescriptorHeapType, RenderTargetViewDesc}; -use heap::{Heap, HeapFlags, HeapProperties}; -use std::ops::Range; -use winapi::um::d3d12; -use winapi::Interface; -use {pso, query, queue}; -use { - Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, Fence, - GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, Shader, - TextureAddressMode, +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; diff --git a/src/dxgi.rs b/src/dxgi.rs index 2db54049e..04c00afb0 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -1,10 +1,10 @@ -use com::WeakPtr; +use crate::{com::WeakPtr, CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; use std::ptr; -use winapi::shared::windef::HWND; -use winapi::shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype}; -use winapi::um::{d3d12, dxgidebug}; -use winapi::Interface; -use {CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; +use winapi::{ + shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype, windef::HWND}, + um::{d3d12, dxgidebug}, + Interface, +}; bitflags! { pub struct FactoryCreationFlags: u32 { diff --git a/src/heap.rs b/src/heap.rs index de97dbf50..9c23bcf08 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -1,4 +1,4 @@ -use com::WeakPtr; +use crate::com::WeakPtr; use winapi::um::d3d12; pub type Heap = WeakPtr; diff --git a/src/lib.rs b/src/lib.rs index 0fe470205..37e1f2ee2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,11 @@ -extern crate winapi; #[macro_use] extern crate bitflags; use std::ffi::CStr; -use winapi::shared::dxgiformat; -use winapi::um::{d3d12, d3dcommon}; +use winapi::{ + shared::dxgiformat, + um::{d3d12, d3dcommon}, +}; mod com; mod command_allocator; diff --git a/src/pso.rs b/src/pso.rs index 365f4ad94..e7dbc0a34 100644 --- a/src/pso.rs +++ b/src/pso.rs @@ -1,10 +1,8 @@ //! Pipeline state -use com::WeakPtr; -use std::ops::Deref; -use std::{ffi, ptr}; +use crate::{com::WeakPtr, Blob, D3DResult, Error}; +use std::{ffi, ops::Deref, ptr}; use winapi::um::{d3d12, d3dcompiler}; -use {Blob, D3DResult, Error}; bitflags! { pub struct PipelineStateFlags: u32 { diff --git a/src/query.rs b/src/query.rs index 0620b73ea..b5925c860 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,4 +1,4 @@ -use com::WeakPtr; +use crate::com::WeakPtr; use winapi::um::d3d12; #[repr(u32)] diff --git a/src/queue.rs b/src/queue.rs index d1bd0f408..0f3a865c9 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,8 +1,5 @@ -use crate::CommandList; -use com::WeakPtr; -use sync::Fence; +use crate::{com::WeakPtr, sync::Fence, CommandList, HRESULT}; use winapi::um::d3d12; -use HRESULT; #[repr(u32)] pub enum Priority { diff --git a/src/resource.rs b/src/resource.rs index f87b8768d..a1242228c 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -1,10 +1,8 @@ //! GPU Resource -use com::WeakPtr; -use std::ops::Range; -use std::ptr; +use crate::{com::WeakPtr, D3DResult, Rect}; +use std::{ops::Range, ptr}; use winapi::um::d3d12; -use {D3DResult, Rect}; pub type Subresource = u32; diff --git a/src/sync.rs b/src/sync.rs index 77d8b17c9..f1f3bb9bc 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,8 +1,6 @@ -use com::WeakPtr; +use crate::{com::WeakPtr, HRESULT}; use std::ptr; -use winapi::um::d3d12; -use winapi::um::{synchapi, winnt}; -use HRESULT; +use winapi::um::{d3d12, synchapi, winnt}; #[derive(Copy, Clone)] #[repr(transparent)] From 5bf5f258e720e8ee7b1270d75bbc386ecfe85c7c Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 7 Jul 2020 10:38:38 -0400 Subject: [PATCH 27/42] Debug implementations for root descriptors --- src/descriptor.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/descriptor.rs b/src/descriptor.rs index 2304e259c..393f94391 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -1,5 +1,5 @@ use crate::{com::WeakPtr, Blob, D3DResult, Error, TextureAddressMode}; -use std::{mem, ops::Range}; +use std::{fmt, mem, ops::Range}; use winapi::{shared::dxgiformat, um::d3d12}; pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE; @@ -7,8 +7,8 @@ pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE; #[derive(Clone, Copy, Debug)] pub struct Binding { - pub register: u32, pub space: u32, + pub register: u32, } #[repr(u32)] @@ -72,6 +72,19 @@ impl DescriptorRange { } } +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 { @@ -139,6 +152,57 @@ impl RootParameter { } } +impl fmt::Debug for RootParameter { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + #[derive(Debug)] + 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 { From 416fb75e656ce72fd5114d0ab1b563899d0e6b15 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 7 Jul 2020 10:01:03 -0400 Subject: [PATCH 28/42] Bump version, add changelog --- CHANGELOG.md | 17 +++++++++++++++++ Cargo.toml | 2 +- README.md | 6 +++++- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..edfb57dd6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Change Log + +## 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 diff --git a/Cargo.toml b/Cargo.toml index aa2d305d7..8664962e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.3.0" +version = "0.3.1" authors = [ "msiglreith ", "Dzmitry Malyshau ", diff --git a/README.md b/README.md index 444700301..a1e1fd661 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # d3d12-rs -Rust wrapper for D3D12 +[![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. From 2fc7340731620e184ee2d7ccf7ae4610bce053a6 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 19 Aug 2020 00:11:41 -0400 Subject: [PATCH 29/42] Add present flags --- Cargo.toml | 2 +- rustfmt.toml | 0 src/command_list.rs | 26 +++++++++++++------------- src/dxgi.rs | 20 +++++++++++++++++++- src/lib.rs | 6 ++++-- 5 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 rustfmt.toml diff --git a/Cargo.toml b/Cargo.toml index 8664962e1..dbbd5f70a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.3.1" +version = "0.3.2" authors = [ "msiglreith ", "Dzmitry Malyshau ", diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..e69de29bb diff --git a/src/command_list.rs b/src/command_list.rs index 4fc3f6ea4..f562bc707 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -2,8 +2,8 @@ use crate::{ com::WeakPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format, - GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, - RootSignature, VertexCount, VertexOffset, WorkGroupCount, HRESULT, + GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, RootIndex, + RootSignature, Subresource, VertexCount, VertexOffset, WorkGroupCount, HRESULT, }; use std::{mem, ptr}; use winapi::um::d3d12; @@ -60,7 +60,7 @@ pub struct ResourceBarrier(d3d12::D3D12_RESOURCE_BARRIER); impl ResourceBarrier { pub fn transition( resource: Resource, - subresource: u32, + subresource: Subresource, state_before: d3d12::D3D12_RESOURCE_STATES, state_after: d3d12::D3D12_RESOURCE_STATES, flags: d3d12::D3D12_RESOURCE_BARRIER_FLAGS, @@ -183,13 +183,13 @@ impl GraphicsCommandList { } pub fn set_index_buffer(&self, gpu_address: GpuAddress, size: u32, format: Format) { - let mut ibv = d3d12::D3D12_INDEX_BUFFER_VIEW { + let ibv = d3d12::D3D12_INDEX_BUFFER_VIEW { BufferLocation: gpu_address, SizeInBytes: size, Format: format, }; unsafe { - self.IASetIndexBuffer(&mut ibv); + self.IASetIndexBuffer(&ibv); } } @@ -240,7 +240,7 @@ impl GraphicsCommandList { pub fn set_compute_root_descriptor_table( &self, - root_index: u32, + root_index: RootIndex, base_descriptor: GpuDescriptor, ) { unsafe { @@ -250,7 +250,7 @@ impl GraphicsCommandList { pub fn set_compute_root_constant_buffer_view( &self, - root_index: u32, + root_index: RootIndex, buffer_location: GpuAddress, ) { unsafe { @@ -260,7 +260,7 @@ impl GraphicsCommandList { pub fn set_compute_root_shader_resource_view( &self, - root_index: u32, + root_index: RootIndex, buffer_location: GpuAddress, ) { unsafe { @@ -270,7 +270,7 @@ impl GraphicsCommandList { pub fn set_compute_root_unordered_access_view( &self, - root_index: u32, + root_index: RootIndex, buffer_location: GpuAddress, ) { unsafe { @@ -280,7 +280,7 @@ impl GraphicsCommandList { pub fn set_graphics_root_descriptor_table( &self, - root_index: u32, + root_index: RootIndex, base_descriptor: GpuDescriptor, ) { unsafe { @@ -290,7 +290,7 @@ impl GraphicsCommandList { pub fn set_graphics_root_constant_buffer_view( &self, - root_index: u32, + root_index: RootIndex, buffer_location: GpuAddress, ) { unsafe { @@ -300,7 +300,7 @@ impl GraphicsCommandList { pub fn set_graphics_root_shader_resource_view( &self, - root_index: u32, + root_index: RootIndex, buffer_location: GpuAddress, ) { unsafe { @@ -310,7 +310,7 @@ impl GraphicsCommandList { pub fn set_graphics_root_unordered_access_view( &self, - root_index: u32, + root_index: RootIndex, buffer_location: GpuAddress, ) { unsafe { diff --git a/src/dxgi.rs b/src/dxgi.rs index 04c00afb0..47e1ec43b 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -181,6 +181,20 @@ impl Factory4 { } } +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 { let mut resource = Resource::null(); @@ -190,10 +204,14 @@ impl SwapChain { (resource, hr) } - // TODO: present flags + //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 SwapChain1 { diff --git a/src/lib.rs b/src/lib.rs index 37e1f2ee2..ff9a10606 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,8 @@ 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. @@ -74,9 +76,9 @@ pub enum FeatureLevel { L12_1 = d3dcommon::D3D_FEATURE_LEVEL_12_1, } -pub type Blob = self::com::WeakPtr; +pub type Blob = WeakPtr; -pub type Error = self::com::WeakPtr; +pub type Error = WeakPtr; impl Error { pub unsafe fn as_c_str(&self) -> &CStr { debug_assert!(!self.is_null()); From d6ad98b025397245e6cbad1c426ace21cfc37ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zsolt=20B=C3=B6l=C3=B6ny?= Date: Tue, 9 Feb 2021 12:35:51 +0100 Subject: [PATCH 30/42] Update libloading to 0.7 --- Cargo.toml | 2 +- src/dxgi.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbbd5f70a..5c897dbe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ implicit-link = [] [dependencies] bitflags = "1" -libloading = { version = "0.6", optional = true } +libloading = { version = "0.7", optional = true } [dependencies.winapi] version = "0.3" diff --git a/src/dxgi.rs b/src/dxgi.rs index 47e1ec43b..67c7489b3 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -56,7 +56,7 @@ pub struct DxgiLib { #[cfg(feature = "libloading")] impl DxgiLib { pub fn new() -> Result { - libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) + unsafe { libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) } } pub fn create_factory2( diff --git a/src/lib.rs b/src/lib.rs index ff9a10606..49efc7ebc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,6 @@ pub struct D3D12Lib { #[cfg(feature = "libloading")] impl D3D12Lib { pub fn new() -> Result { - libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) + unsafe { libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) } } } From ea188634c6c16ef34d3eccd60d1c41d8dada91d4 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 29 Apr 2021 10:50:08 -0400 Subject: [PATCH 31/42] Bump version to 0.4.0 --- CHANGELOG.md | 3 +++ Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edfb57dd6..32b5bee88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## 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 diff --git a/Cargo.toml b/Cargo.toml index 5c897dbe1..b85d5f09c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.3.2" +version = "0.4.0" authors = [ "msiglreith ", "Dzmitry Malyshau ", From 2061f6a893706623a29e47986e5e2368ef3277f4 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 26 Jul 2021 13:41:12 -0400 Subject: [PATCH 32/42] Expose all indirect argument types --- CHANGELOG.md | 3 +++ src/command_list.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32b5bee88..1432689f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## Unreleased + - expose all indirect argument types + ## v0.4.0 (2021-04-29) - update `libloading` to 0.7 diff --git a/src/command_list.rs b/src/command_list.rs index f562bc707..3209d6948 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -51,7 +51,64 @@ impl IndirectArgument { }) } - // TODO: missing variants + 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)] From 3e88f3dc63de37186dc97c474e2a01c3f8cac9db Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 27 Jul 2021 01:28:56 -0400 Subject: [PATCH 33/42] Setting root constants --- src/command_list.rs | 22 ++++++++++++++++++++++ src/descriptor.rs | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/command_list.rs b/src/command_list.rs index 3209d6948..c426d9549 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -335,6 +335,17 @@ impl GraphicsCommandList { } } + 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, @@ -375,6 +386,17 @@ impl GraphicsCommandList { } } + 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/src/descriptor.rs b/src/descriptor.rs index 393f94391..bfa020412 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -120,7 +120,8 @@ impl RootParameter { RootParameter(param) } - fn descriptor( + //TODO: should this be unsafe? + pub fn descriptor( ty: d3d12::D3D12_ROOT_PARAMETER_TYPE, visibility: ShaderVisibility, binding: Binding, From 15ef1507fd07be420c5dc0aed5461ebf1115244b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 18 Aug 2021 00:35:05 -0400 Subject: [PATCH 34/42] Version bump to 0.4.1 --- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1432689f3..0aa9a4af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Change Log -## Unreleased +## 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 diff --git a/Cargo.toml b/Cargo.toml index b85d5f09c..7e41e6d83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.4.0" +version = "0.4.1" authors = [ "msiglreith ", "Dzmitry Malyshau ", From ffe5e261da0a6cb85332b82ab310abd2a7e849f6 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 8 Mar 2022 23:15:03 -0500 Subject: [PATCH 35/42] Adds D3D11 DXGI Support and COM Helper Chain (#37) * Add older dxgi methods * Add create_swapchain_for_composition * Add DXGIFactory6 * Write COM inheritance chain macro * Add DXGIAdapter chain * Make accessing base of inheritance chain easy * Add `mut_self` to WeakPtr * Add TryFrom for FeatureLevel * Fix compile error on 1.51 * Comments --- Cargo.toml | 2 +- src/com.rs | 163 +++++++++++++++++++++++++++++++++++++++- src/descriptor.rs | 1 + src/dxgi.rs | 184 ++++++++++++++++++++++++++++++++++++---------- src/lib.rs | 22 +++++- 5 files changed, 329 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7e41e6d83..0a41a3d75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ libloading = { version = "0.7", optional = true } [dependencies.winapi] version = "0.3" -features = ["dxgi1_2","dxgi1_3","dxgi1_4","dxgidebug","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] +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" diff --git a/src/com.rs b/src/com.rs index 7007060a1..f3a85789c 100644 --- a/src/com.rs +++ b/src/com.rs @@ -31,9 +31,13 @@ impl WeakPtr { self.0 } - pub unsafe fn mut_void(&mut self) -> *mut *mut c_void { + 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 WeakPtr { @@ -100,3 +104,160 @@ impl Hash for WeakPtr { 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 -> Self`) +/// - the as function (`&self -> Option>`) +/// - the unwrap function (`&self -> WeakPtr` 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 and se cast to &WeakPtr + 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 and se cast to &WeakPtr + unsafe { std::mem::transmute(v) } + } + )* + } + } + }; +} diff --git a/src/descriptor.rs b/src/descriptor.rs index bfa020412..02ca2e83c 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -156,6 +156,7 @@ impl RootParameter { 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 }, diff --git a/src/dxgi.rs b/src/dxgi.rs index 67c7489b3..0a66dcd02 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -1,8 +1,11 @@ -use crate::{com::WeakPtr, CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; +use crate::{com::WeakPtr, D3DResult, Resource, SampleDesc, HRESULT}; use std::ptr; use winapi::{ - shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype, windef::HWND}, - um::{d3d12, dxgidebug}, + shared::{ + dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgi1_5, dxgi1_6, dxgiformat, dxgitype, minwindef::TRUE, + windef::HWND, + }, + um::{d3d12, dxgidebug, unknwnbase::IUnknown}, Interface, }; @@ -39,13 +42,53 @@ pub enum AlphaMode { ForceDword = dxgi1_2::DXGI_ALPHA_MODE_FORCE_DWORD, } -pub type Adapter1 = WeakPtr; -pub type Factory2 = WeakPtr; -pub type Factory4 = WeakPtr; pub type InfoQueue = WeakPtr; + +pub type Adapter1 = WeakPtr; +pub type Adapter2 = WeakPtr; +pub type Adapter3 = WeakPtr; +pub type Adapter4 = WeakPtr; +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; +pub type Factory2 = WeakPtr; +pub type Factory3 = WeakPtr; +pub type Factory4 = WeakPtr; +pub type Factory5 = WeakPtr; +pub type Factory6 = WeakPtr; +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 SwapChain = WeakPtr; pub type SwapChain1 = WeakPtr; +pub type SwapChain2 = WeakPtr; pub type SwapChain3 = WeakPtr; +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)] @@ -82,6 +125,21 @@ impl DxgiLib { Ok((factory, hr)) } + pub fn create_factory1(&self) -> Result, 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 = self.lib.get(b"CreateDXGIFactory1")?; + func(&dxgi::IDXGIFactory1::uuidof(), factory.mut_void()) + }; + + Ok((factory, hr)) + } + pub fn get_debug_interface1(&self) -> Result, libloading::Error> { type Fun = extern "system" fn( winapi::shared::minwindef::UINT, @@ -112,38 +170,80 @@ pub struct SwapchainDesc { 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 { + 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: CommandQueue, + queue: *mut IUnknown, hwnd: HWND, desc: &SwapchainDesc, ) -> D3DResult { - let desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 { - AlphaMode: desc.alpha_mode as _, - BufferCount: desc.buffer_count, - Width: desc.width, - Height: desc.height, - Format: desc.format, - Flags: desc.flags, - BufferUsage: desc.buffer_usage, - SampleDesc: dxgitype::DXGI_SAMPLE_DESC { - Count: desc.sample.count, - Quality: desc.sample.quality, - }, - Scaling: desc.scaling as _, - Stereo: desc.stereo as _, - SwapEffect: desc.swap_effect as _, - }; - let mut swap_chain = SwapChain1::null(); let hr = unsafe { self.CreateSwapChainForHwnd( - queue.as_mut_ptr() as *mut _, + queue, hwnd, - &desc, + &desc.to_desc1(), ptr::null(), ptr::null_mut(), swap_chain.mut_void() as *mut *mut _, @@ -152,6 +252,24 @@ impl Factory2 { (swap_chain, hr) } + + pub fn create_swapchain_for_composition( + &self, + queue: *mut IUnknown, + desc: &SwapchainDesc, + ) -> D3DResult { + 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 { @@ -169,10 +287,6 @@ impl Factory4 { (factory, hr) } - pub fn as_factory2(&self) -> Factory2 { - unsafe { Factory2::from_raw(self.as_mut_ptr() as *mut _) } - } - pub fn enumerate_adapters(&self, id: u32) -> D3DResult { let mut adapter = Adapter1::null(); let hr = unsafe { self.EnumAdapters1(id, adapter.mut_void() as *mut *mut _) }; @@ -214,17 +328,7 @@ impl SwapChain { } } -impl SwapChain1 { - pub fn as_swapchain0(&self) -> SwapChain { - unsafe { SwapChain::from_raw(self.as_mut_ptr() as *mut _) } - } -} - impl SwapChain3 { - pub fn as_swapchain0(&self) -> SwapChain { - unsafe { SwapChain::from_raw(self.as_mut_ptr() as *mut _) } - } - pub fn get_current_back_buffer_index(&self) -> u32 { unsafe { self.GetCurrentBackBufferIndex() } } diff --git a/src/lib.rs b/src/lib.rs index 49efc7ebc..e52f9d9d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate bitflags; -use std::ffi::CStr; +use std::{convert::TryFrom, ffi::CStr}; use winapi::{ shared::dxgiformat, um::{d3d12, d3dcommon}, @@ -64,6 +64,7 @@ pub struct SampleDesc { } #[repr(u32)] +#[non_exhaustive] pub enum FeatureLevel { L9_1 = d3dcommon::D3D_FEATURE_LEVEL_9_1, L9_2 = d3dcommon::D3D_FEATURE_LEVEL_9_2, @@ -76,6 +77,25 @@ pub enum FeatureLevel { L12_1 = d3dcommon::D3D_FEATURE_LEVEL_12_1, } +impl TryFrom for FeatureLevel { + type Error = (); + + fn try_from(value: u32) -> Result { + 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; pub type Error = WeakPtr; From 3761d8a3ff84af1a59d6a024eab2d9cf8139bdf8 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 1 Jul 2022 10:05:54 -0400 Subject: [PATCH 36/42] Bump version to 0.5.0 --- CHANGELOG.md | 4 ++++ Cargo.toml | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aa9a4af4..d64b41e7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 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 diff --git a/Cargo.toml b/Cargo.toml index 0a41a3d75..f62076f06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "d3d12" -version = "0.4.1" +version = "0.5.0" authors = [ - "msiglreith ", - "Dzmitry Malyshau ", + "gfx-rs developers", ] description = "Low level D3D12 API wrapper" repository = "https://github.com/gfx-rs/d3d12-rs" From bd2290f4acb9a6793b909c1e4ce0838075084f24 Mon Sep 17 00:00:00 2001 From: Xiaopeng Li Date: Thu, 10 Nov 2022 17:38:01 +0800 Subject: [PATCH 37/42] Add FactoryMedia --- src/dxgi.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/dxgi.rs b/src/dxgi.rs index 0a66dcd02..01bbafc02 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -5,7 +5,7 @@ use winapi::{ dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgi1_5, dxgi1_6, dxgiformat, dxgitype, minwindef::TRUE, windef::HWND, }, - um::{d3d12, dxgidebug, unknwnbase::IUnknown}, + um::{d3d12, dxgidebug, unknwnbase::IUnknown, winnt::HANDLE}, Interface, }; @@ -64,6 +64,7 @@ pub type Factory3 = WeakPtr; pub type Factory4 = WeakPtr; pub type Factory5 = WeakPtr; pub type Factory6 = WeakPtr; +pub type FactoryMedia = WeakPtr; crate::weak_com_inheritance_chain! { #[derive(Debug, Copy, Clone, PartialEq, Hash)] pub enum DxgiFactory { @@ -73,6 +74,7 @@ crate::weak_com_inheritance_chain! { 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; + FactoryMedia(dxgi1_3::IDXGIFactoryMedia), from_factory_media, as_factory_media, unwrap_factory_media; } } @@ -295,6 +297,28 @@ impl Factory4 { } } +impl FactoryMedia { + pub fn create_swapchain_for_composition_surface_handle( + &self, + queue: *mut IUnknown, + surface_handle: HANDLE, + desc: &SwapchainDesc, + ) -> D3DResult { + 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; From fd0df189eff79ab2d7b91f48f5d5d38a9adfe3b5 Mon Sep 17 00:00:00 2001 From: Xiaopeng Li Date: Fri, 25 Nov 2022 15:21:08 +0800 Subject: [PATCH 38/42] Create IDXGIFactoryMedia by CreateDXGIFactory1 --- src/dxgi.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/dxgi.rs b/src/dxgi.rs index 01bbafc02..3c0396e88 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -64,7 +64,6 @@ pub type Factory3 = WeakPtr; pub type Factory4 = WeakPtr; pub type Factory5 = WeakPtr; pub type Factory6 = WeakPtr; -pub type FactoryMedia = WeakPtr; crate::weak_com_inheritance_chain! { #[derive(Debug, Copy, Clone, PartialEq, Hash)] pub enum DxgiFactory { @@ -74,10 +73,11 @@ crate::weak_com_inheritance_chain! { 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; - FactoryMedia(dxgi1_3::IDXGIFactoryMedia), from_factory_media, as_factory_media, unwrap_factory_media; } } +pub type FactoryMedia = WeakPtr; + pub type SwapChain = WeakPtr; pub type SwapChain1 = WeakPtr; pub type SwapChain2 = WeakPtr; @@ -142,6 +142,22 @@ impl DxgiLib { Ok((factory, hr)) } + pub fn create_factory_media(&self) -> Result, 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 = self.lib.get(b"CreateDXGIFactory1")?; + func(&dxgi1_3::IDXGIFactoryMedia::uuidof(), factory.mut_void()) + }; + + Ok((factory, hr)) + } + pub fn get_debug_interface1(&self) -> Result, libloading::Error> { type Fun = extern "system" fn( winapi::shared::minwindef::UINT, From 7f9735fda6056f49373a91ffb40e25d6fa5e4bfe Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 25 Jan 2023 16:00:25 -0500 Subject: [PATCH 39/42] Release 0.6 --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d64b41e7d..6af566ae6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # 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 diff --git a/Cargo.toml b/Cargo.toml index f62076f06..c7c6c37f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.5.0" +version = "0.6.0" authors = [ "gfx-rs developers", ] From 777c5c1cdd41f3dc140e55be10273a2f56a3c162 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 3 Jun 2023 20:42:28 +0200 Subject: [PATCH 40/42] Bump `bitflags` to v2 (#44) --- Cargo.toml | 2 +- src/command_list.rs | 1 + src/descriptor.rs | 2 ++ src/dxgi.rs | 2 ++ src/heap.rs | 1 + src/pso.rs | 2 ++ src/queue.rs | 1 + 7 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c7c6c37f4..252ac0ad1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ edition = "2018" implicit-link = [] [dependencies] -bitflags = "1" +bitflags = "2" libloading = { version = "0.7", optional = true } [dependencies.winapi] diff --git a/src/command_list.rs b/src/command_list.rs index c426d9549..5ea04db80 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -20,6 +20,7 @@ pub enum CmdListType { } 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; diff --git a/src/descriptor.rs b/src/descriptor.rs index 02ca2e83c..be9825f91 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -21,6 +21,7 @@ pub enum DescriptorHeapType { } bitflags! { + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct DescriptorHeapFlags: u32 { const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; } @@ -253,6 +254,7 @@ pub enum RootSignatureVersion { } 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; diff --git a/src/dxgi.rs b/src/dxgi.rs index 3c0396e88..d66e0a86a 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -10,6 +10,7 @@ use winapi::{ }; bitflags! { + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct FactoryCreationFlags: u32 { const DEBUG = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG; } @@ -336,6 +337,7 @@ impl FactoryMedia { } 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; diff --git a/src/heap.rs b/src/heap.rs index 9c23bcf08..02e68bf27 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -30,6 +30,7 @@ pub enum MemoryPool { } 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; diff --git a/src/pso.rs b/src/pso.rs index e7dbc0a34..13f8ad82e 100644 --- a/src/pso.rs +++ b/src/pso.rs @@ -5,12 +5,14 @@ use std::{ffi, ops::Deref, ptr}; 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; diff --git a/src/queue.rs b/src/queue.rs index 0f3a865c9..c3869f0cd 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -9,6 +9,7 @@ pub enum Priority { } 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; } From 7e8051e9cf997c77e006194e6fc722a2462a1757 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 4 Jun 2023 03:45:52 +0200 Subject: [PATCH 41/42] Bump `libloading` to v0.8 (#43) --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 252ac0ad1..2033e5d36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ implicit-link = [] [dependencies] bitflags = "2" -libloading = { version = "0.7", optional = true } +# libloading 0.8 switches from `winapi` to `windows-sys`; permit either +libloading = { version = ">=0.7,<0.9", optional = true } [dependencies.winapi] version = "0.3" From a6fa6896ea5d6c5c394bfb100495e20f26b8882d Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 13 Jul 2023 20:45:45 -0400 Subject: [PATCH 42/42] Change from WeakPtr to ComPtr which has proper ownership semantics This makes it a lot easier to avoid making memory management mistakes. It also is closer to the semantics that windows-rs exposes for it's bindings. --- Cargo.toml | 2 +- src/com.rs | 82 +++++++++++++++++++--------------------- src/command_allocator.rs | 4 +- src/command_list.rs | 16 ++++---- src/debug.rs | 4 +- src/descriptor.rs | 6 +-- src/device.rs | 14 +++---- src/dxgi.rs | 40 ++++++++++---------- src/heap.rs | 4 +- src/lib.rs | 4 +- src/pso.rs | 43 +++++++++------------ src/query.rs | 4 +- src/queue.rs | 6 +-- src/resource.rs | 4 +- src/sync.rs | 4 +- 15 files changed, 112 insertions(+), 125 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2033e5d36..dbb116eb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.6.0" +version = "0.7.0" authors = [ "gfx-rs developers", ] diff --git a/src/com.rs b/src/com.rs index f3a85789c..66b338c9e 100644 --- a/src/com.rs +++ b/src/com.rs @@ -8,15 +8,18 @@ use std::{ use winapi::{ctypes::c_void, um::unknwnbase::IUnknown, Interface}; #[repr(transparent)] -pub struct WeakPtr(*mut T); +pub struct ComPtr(*mut T); -impl WeakPtr { +impl ComPtr { pub fn null() -> Self { - WeakPtr(ptr::null_mut()) + ComPtr(ptr::null_mut()) } pub unsafe fn from_raw(raw: *mut T) -> Self { - WeakPtr(raw) + if !raw.is_null() { + (&*(raw as *mut IUnknown)).AddRef(); + } + ComPtr(raw) } pub fn is_null(&self) -> bool { @@ -40,40 +43,42 @@ impl WeakPtr { } } -impl WeakPtr { +impl ComPtr { 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(&self) -> D3DResult> + pub unsafe fn cast(&self) -> D3DResult> where U: Interface, { - let mut obj = WeakPtr::::null(); + debug_assert!(!self.is_null()); + let mut obj = ComPtr::::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 Clone for WeakPtr { +impl Clone for ComPtr { fn clone(&self) -> Self { - WeakPtr(self.0) + debug_assert!(!self.is_null()); + unsafe { self.as_unknown().AddRef(); } + ComPtr(self.0) } } -impl Copy for WeakPtr {} +impl Drop for ComPtr { + fn drop(&mut self) { + if !self.0.is_null() { + unsafe { self.as_unknown().Release(); } + } + } +} -impl Deref for WeakPtr { +impl Deref for ComPtr { type Target = T; fn deref(&self) -> &T { debug_assert!(!self.is_null()); @@ -81,25 +86,25 @@ impl Deref for WeakPtr { } } -impl fmt::Debug for WeakPtr { +impl fmt::Debug for ComPtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "WeakPtr( ptr: {:?} )", self.0) + write!(f, "ComPtr( ptr: {:?} )", self.0) } } -impl PartialEq<*mut T> for WeakPtr { +impl PartialEq<*mut T> for ComPtr { fn eq(&self, other: &*mut T) -> bool { self.0 == *other } } -impl PartialEq for WeakPtr { +impl PartialEq for ComPtr { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } -impl Hash for WeakPtr { +impl Hash for ComPtr { fn hash(&self, state: &mut H) { self.0.hash(state); } @@ -110,9 +115,9 @@ impl Hash for WeakPtr { /// 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 -> Self`) -/// - the as function (`&self -> Option>`) -/// - the unwrap function (`&self -> WeakPtr` panicing on failure to cast) +/// - the from function (`ComPtr -> Self`) +/// - the as function (`&self -> Option>`) +/// - the unwrap function (`&self -> ComPtr` panicing on failure to cast) /// /// ```rust /// # pub use d3d12::weak_com_inheritance_chain; @@ -145,21 +150,12 @@ macro_rules! weak_com_inheritance_chain { ) => { $(#[$meta])* $vis enum $name { - $first_variant($crate::WeakPtr<$first_type>), + $first_variant($crate::ComPtr<$first_type>), $( - $variant($crate::WeakPtr<$type>) + $variant($crate::ComPtr<$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, @@ -170,7 +166,7 @@ macro_rules! weak_com_inheritance_chain { } impl std::ops::Deref for $name { - type Target = $crate::WeakPtr<$first_type>; + type Target = $crate::ComPtr<$first_type>; fn deref(&self) -> &Self::Target { self.$first_unwrap_name() } @@ -223,12 +219,12 @@ macro_rules! weak_com_inheritance_chain { $($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 { + $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::WeakPtr<$type>> { + $vis fn $as_name(&self) -> Option<&$crate::ComPtr<$type>> { match *self { $( Self::$prev_variant(_) => None, @@ -236,7 +232,7 @@ macro_rules! weak_com_inheritance_chain { Self::$variant(ref v) => Some(v), $( Self::$next_variant(ref v) => { - // v is &WeakPtr and se cast to &WeakPtr + // v is &ComPtr and se cast to &ComPtr Some(unsafe { std::mem::transmute(v) }) } )* @@ -245,7 +241,7 @@ macro_rules! weak_com_inheritance_chain { // Returns the interface if the value implements it, otherwise panics. #[track_caller] - $vis fn $unwrap_name(&self) -> &$crate::WeakPtr<$type> { + $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))), @@ -253,7 +249,7 @@ macro_rules! weak_com_inheritance_chain { Self::$variant(ref v) => &*v, $( Self::$next_variant(ref v) => { - // v is &WeakPtr and se cast to &WeakPtr + // v is &ComPtr and se cast to &ComPtr unsafe { std::mem::transmute(v) } } )* diff --git a/src/command_allocator.rs b/src/command_allocator.rs index 15b373583..b50ec00d4 100644 --- a/src/command_allocator.rs +++ b/src/command_allocator.rs @@ -1,9 +1,9 @@ //! Command Allocator -use crate::com::WeakPtr; +use crate::com::ComPtr; use winapi::um::d3d12; -pub type CommandAllocator = WeakPtr; +pub type CommandAllocator = ComPtr; impl CommandAllocator { pub fn reset(&self) { diff --git a/src/command_list.rs b/src/command_list.rs index 5ea04db80..015d5788b 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -1,7 +1,7 @@ //! Graphics command list use crate::{ - com::WeakPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format, + com::ComPtr, resource::DiscardRegion, CommandAllocator, CpuDescriptor, DescriptorHeap, Format, GpuAddress, GpuDescriptor, IndexCount, InstanceCount, PipelineState, Rect, Resource, RootIndex, RootSignature, Subresource, VertexCount, VertexOffset, WorkGroupCount, HRESULT, }; @@ -140,9 +140,9 @@ impl ResourceBarrier { } } -pub type CommandSignature = WeakPtr; -pub type CommandList = WeakPtr; -pub type GraphicsCommandList = WeakPtr; +pub type CommandSignature = ComPtr; +pub type CommandList = ComPtr; +pub type GraphicsCommandList = ComPtr; impl GraphicsCommandList { pub fn as_list(&self) -> CommandList { @@ -153,7 +153,7 @@ impl GraphicsCommandList { unsafe { self.Close() } } - pub fn reset(&self, allocator: CommandAllocator, initial_pso: PipelineState) -> HRESULT { + pub fn reset(&self, allocator: &CommandAllocator, initial_pso: PipelineState) -> HRESULT { unsafe { self.Reset(allocator.as_mut_ptr(), initial_pso.as_mut_ptr()) } } @@ -263,7 +263,7 @@ impl GraphicsCommandList { } } - pub fn set_pipeline_state(&self, pso: PipelineState) { + pub fn set_pipeline_state(&self, pso:&PipelineState) { unsafe { self.SetPipelineState(pso.as_mut_ptr()); } @@ -284,13 +284,13 @@ impl GraphicsCommandList { } } - pub fn set_compute_root_signature(&self, signature: RootSignature) { + 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) { + pub fn set_graphics_root_signature(&self, signature: &RootSignature) { unsafe { self.SetGraphicsRootSignature(signature.as_mut_ptr()); } diff --git a/src/debug.rs b/src/debug.rs index d7768191b..3a6abc46b 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,9 +1,9 @@ -use crate::com::WeakPtr; +use crate::com::ComPtr; use winapi::um::d3d12sdklayers; #[cfg(any(feature = "libloading", feature = "implicit-link"))] use winapi::Interface as _; -pub type Debug = WeakPtr; +pub type Debug = ComPtr; #[cfg(feature = "libloading")] impl crate::D3D12Lib { diff --git a/src/descriptor.rs b/src/descriptor.rs index be9825f91..5bb1b5b35 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -1,4 +1,4 @@ -use crate::{com::WeakPtr, Blob, D3DResult, Error, TextureAddressMode}; +use crate::{com::ComPtr, Blob, D3DResult, Error, TextureAddressMode}; use std::{fmt, mem, ops::Range}; use winapi::{shared::dxgiformat, um::d3d12}; @@ -27,7 +27,7 @@ bitflags! { } } -pub type DescriptorHeap = WeakPtr; +pub type DescriptorHeap = ComPtr; impl DescriptorHeap { pub fn start_cpu_descriptor(&self) -> CpuDescriptor { @@ -265,7 +265,7 @@ bitflags! { } } -pub type RootSignature = WeakPtr; +pub type RootSignature = ComPtr; pub type BlobResult = D3DResult<(Blob, Error)>; #[cfg(feature = "libloading")] diff --git a/src/device.rs b/src/device.rs index 188eb40b1..517b858bb 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,7 +1,7 @@ //! Device use crate::{ - com::WeakPtr, + com::ComPtr, command_list::{CmdListType, CommandSignature, IndirectArgument}, descriptor::{CpuDescriptor, DescriptorHeapFlags, DescriptorHeapType, RenderTargetViewDesc}, heap::{Heap, HeapFlags, HeapProperties}, @@ -12,13 +12,13 @@ use crate::{ use std::ops::Range; use winapi::{um::d3d12, Interface}; -pub type Device = WeakPtr; +pub type Device = ComPtr; #[cfg(feature = "libloading")] impl crate::D3D12Lib { - pub fn create_device( +pub fn create_device( &self, - adapter: WeakPtr, + adapter: &ComPtr, feature_level: crate::FeatureLevel, ) -> Result, libloading::Error> { type Fun = extern "system" fn( @@ -46,7 +46,7 @@ impl crate::D3D12Lib { impl Device { #[cfg(feature = "implicit-link")] pub fn create( - adapter: WeakPtr, + adapter: ComPtr, feature_level: crate::FeatureLevel, ) -> D3DResult { let mut device = Device::null(); @@ -155,7 +155,7 @@ impl Device { pub fn create_graphics_command_list( &self, list_type: CmdListType, - allocator: CommandAllocator, + allocator: &CommandAllocator, initial: PipelineState, node_mask: NodeMask, ) -> D3DResult { @@ -215,7 +215,7 @@ impl Device { pub fn create_compute_pipeline_state( &self, - root_signature: RootSignature, + root_signature: &RootSignature, cs: Shader, node_mask: NodeMask, cached_pso: CachedPSO, diff --git a/src/dxgi.rs b/src/dxgi.rs index d66e0a86a..81e2aaa1e 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -1,4 +1,4 @@ -use crate::{com::WeakPtr, D3DResult, Resource, SampleDesc, HRESULT}; +use crate::{com::ComPtr, D3DResult, Resource, SampleDesc, HRESULT}; use std::ptr; use winapi::{ shared::{ @@ -43,14 +43,14 @@ pub enum AlphaMode { ForceDword = dxgi1_2::DXGI_ALPHA_MODE_FORCE_DWORD, } -pub type InfoQueue = WeakPtr; +pub type InfoQueue = ComPtr; -pub type Adapter1 = WeakPtr; -pub type Adapter2 = WeakPtr; -pub type Adapter3 = WeakPtr; -pub type Adapter4 = WeakPtr; +pub type Adapter1 = ComPtr; +pub type Adapter2 = ComPtr; +pub type Adapter3 = ComPtr; +pub type Adapter4 = ComPtr; crate::weak_com_inheritance_chain! { - #[derive(Debug, Copy, Clone, PartialEq, Hash)] + #[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; @@ -59,14 +59,14 @@ crate::weak_com_inheritance_chain! { } } -pub type Factory1 = WeakPtr; -pub type Factory2 = WeakPtr; -pub type Factory3 = WeakPtr; -pub type Factory4 = WeakPtr; -pub type Factory5 = WeakPtr; -pub type Factory6 = WeakPtr; +pub type Factory1 = ComPtr; +pub type Factory2 = ComPtr; +pub type Factory3 = ComPtr; +pub type Factory4 = ComPtr; +pub type Factory5 = ComPtr; +pub type Factory6 = ComPtr; crate::weak_com_inheritance_chain! { - #[derive(Debug, Copy, Clone, PartialEq, Hash)] + #[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; @@ -77,14 +77,14 @@ crate::weak_com_inheritance_chain! { } } -pub type FactoryMedia = WeakPtr; +pub type FactoryMedia = ComPtr; -pub type SwapChain = WeakPtr; -pub type SwapChain1 = WeakPtr; -pub type SwapChain2 = WeakPtr; -pub type SwapChain3 = WeakPtr; +pub type SwapChain = ComPtr; +pub type SwapChain1 = ComPtr; +pub type SwapChain2 = ComPtr; +pub type SwapChain3 = ComPtr; crate::weak_com_inheritance_chain! { - #[derive(Debug, Copy, Clone, PartialEq, Hash)] + #[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; diff --git a/src/heap.rs b/src/heap.rs index 02e68bf27..8d081a213 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -1,7 +1,7 @@ -use crate::com::WeakPtr; +use crate::com::ComPtr; use winapi::um::d3d12; -pub type Heap = WeakPtr; +pub type Heap = ComPtr; #[repr(u32)] #[derive(Clone, Copy)] diff --git a/src/lib.rs b/src/lib.rs index e52f9d9d4..8a68475de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,9 +96,9 @@ impl TryFrom for FeatureLevel { } } -pub type Blob = WeakPtr; +pub type Blob = ComPtr; -pub type Error = WeakPtr; +pub type Error = ComPtr; impl Error { pub unsafe fn as_c_str(&self) -> &CStr { debug_assert!(!self.is_null()); diff --git a/src/pso.rs b/src/pso.rs index 13f8ad82e..2c19bd48d 100644 --- a/src/pso.rs +++ b/src/pso.rs @@ -1,7 +1,7 @@ //! Pipeline state -use crate::{com::WeakPtr, Blob, D3DResult, Error}; -use std::{ffi, ops::Deref, ptr}; +use crate::{com::ComPtr, Blob, D3DResult, Error}; +use std::{ffi::{self, c_void}, ops::Deref, ptr, marker::PhantomData}; use winapi::um::{d3d12, d3dcompiler}; bitflags! { @@ -25,28 +25,28 @@ bitflags! { } #[derive(Copy, Clone)] -pub struct Shader(d3d12::D3D12_SHADER_BYTECODE); -impl Shader { +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: &[u8]) -> Self { + 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: Blob) -> Self { + 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. @@ -81,49 +81,40 @@ impl Shader { } } -impl Deref for Shader { +impl<'a> Deref for Shader<'a> { type Target = d3d12::D3D12_SHADER_BYTECODE; fn deref(&self) -> &Self::Target { &self.0 } } -impl From> for Shader { - fn from(blob: Option) -> 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 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: Blob) -> Self { + pub fn from_blob(blob: &'a Blob) -> Self { CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE { CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() }, pCachedBlob: unsafe { blob.GetBufferPointer() }, - }) + }, PhantomData) } } -impl Deref for CachedPSO { +impl<'a> Deref for CachedPSO<'a> { type Target = d3d12::D3D12_CACHED_PIPELINE_STATE; fn deref(&self) -> &Self::Target { &self.0 } } -pub type PipelineState = WeakPtr; +pub type PipelineState = ComPtr; #[repr(u32)] pub enum Subobject { diff --git a/src/query.rs b/src/query.rs index b5925c860..a9dca262b 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,4 +1,4 @@ -use crate::com::WeakPtr; +use crate::com::ComPtr; use winapi::um::d3d12; #[repr(u32)] @@ -12,4 +12,4 @@ pub enum QueryHeapType { // CopyQueueTimestamp = d3d12::D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP, } -pub type QueryHeap = WeakPtr; +pub type QueryHeap = ComPtr; diff --git a/src/queue.rs b/src/queue.rs index c3869f0cd..944cb6f32 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,4 +1,4 @@ -use crate::{com::WeakPtr, sync::Fence, CommandList, HRESULT}; +use crate::{com::ComPtr, sync::Fence, CommandList, HRESULT}; use winapi::um::d3d12; #[repr(u32)] @@ -15,7 +15,7 @@ bitflags! { } } -pub type CommandQueue = WeakPtr; +pub type CommandQueue = ComPtr; impl CommandQueue { pub fn execute_command_lists(&self, command_lists: &[CommandList]) { @@ -26,7 +26,7 @@ impl CommandQueue { unsafe { self.ExecuteCommandLists(command_lists.len() as _, command_lists.as_ptr()) } } - pub fn signal(&self, fence: Fence, value: u64) -> HRESULT { + pub fn signal(&self, fence: &Fence, value: u64) -> HRESULT { unsafe { self.Signal(fence.as_mut_ptr(), value) } } } diff --git a/src/resource.rs b/src/resource.rs index a1242228c..bdc669dd3 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -1,6 +1,6 @@ //! GPU Resource -use crate::{com::WeakPtr, D3DResult, Rect}; +use crate::{com::ComPtr, D3DResult, Rect}; use std::{ops::Range, ptr}; use winapi::um::d3d12; @@ -11,7 +11,7 @@ pub struct DiscardRegion<'a> { pub subregions: Range, } -pub type Resource = WeakPtr; +pub type Resource = ComPtr; impl Resource { /// diff --git a/src/sync.rs b/src/sync.rs index f1f3bb9bc..fa5f09040 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,4 +1,4 @@ -use crate::{com::WeakPtr, HRESULT}; +use crate::{com::ComPtr, HRESULT}; use std::ptr; use winapi::um::{d3d12, synchapi, winnt}; @@ -23,7 +23,7 @@ impl Event { } } -pub type Fence = WeakPtr; +pub type Fence = ComPtr; impl Fence { pub fn set_event_on_completion(&self, event: Event, value: u64) -> HRESULT { unsafe { self.SetEventOnCompletion(value, event.0) }