diff --git a/Cargo.toml b/Cargo.toml index 5e6b53e92..393b6cb19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,11 @@ [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"] } + +[dependencies.winapi] +version = "0.3" +features = ["dxgi1_2","dxgi1_3","dxgi1_4","d3d12","d3d12sdklayers","d3dcommon","d3dcompiler","dxgiformat","synchapi","winerror"] 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..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() } } @@ -103,6 +108,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/debug.rs b/src/debug.rs new file mode 100644 index 000000000..f614a27fa --- /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_interface() -> D3DResult { + let mut debug = Debug::null(); + let hr = unsafe { + d3d12::D3D12GetDebugInterface(&d3d12sdklayers::ID3D12Debug::uuidof(), debug.mut_void()) + }; + + (debug, hr) + } + + pub fn enable_layer(&self) { + unsafe { self.EnableDebugLayer() } + } +} 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..376c30418 100644 --- a/src/device.rs +++ b/src/device.rs @@ -2,15 +2,15 @@ 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, - TextureAddressMode, + Fence, GraphicsCommandList, NodeMask, PipelineState, QueryHeap, Resource, RootSignature, + Shader, TextureAddressMode, }; pub type Device = WeakPtr; @@ -265,4 +265,30 @@ 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); + } + } + + // 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/dxgi.rs b/src/dxgi.rs new file mode 100644 index 000000000..ad8b91e44 --- /dev/null +++ b/src/dxgi.rs @@ -0,0 +1,160 @@ +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::Interface; +use {CommandQueue, D3DResult, Resource, SampleDesc, HRESULT}; + +bitflags! { + pub struct FactoryCreationFlags: u32 { + const DEBUG = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG; + } +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone)] +pub enum Scaling { + Stretch = dxgi1_2::DXGI_SCALING_STRETCH, + Identity = dxgi1_2::DXGI_SCALING_NONE, + Aspect = dxgi1_2::DXGI_SCALING_ASPECT_RATIO_STRETCH, +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone)] +pub enum SwapEffect { + Discard = dxgi::DXGI_SWAP_EFFECT_DISCARD, + Sequential = dxgi::DXGI_SWAP_EFFECT_SEQUENTIAL, + FlipDiscard = dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD, + FlipSequential = dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone)] +pub enum AlphaMode { + Unspecified = dxgi1_2::DXGI_ALPHA_MODE_UNSPECIFIED, + Premultiplied = dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED, + Straight = dxgi1_2::DXGI_ALPHA_MODE_STRAIGHT, + Ignore = dxgi1_2::DXGI_ALPHA_MODE_IGNORE, + ForceDword = dxgi1_2::DXGI_ALPHA_MODE_FORCE_DWORD, +} + +pub type 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 { + let mut factory = Factory4::null(); + let hr = unsafe { + dxgi1_3::CreateDXGIFactory2( + flags.bits(), + &dxgi1_4::IDXGIFactory4::uuidof(), + factory.mut_void(), + ) + }; + + (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 _) }; + + (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 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 036ff059e..0712584ef 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}; @@ -49,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, 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 {