diff --git a/Cargo.lock b/Cargo.lock index 6b0878c..a342bf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -746,6 +746,7 @@ name = "librashader-runtime-d3d12" version = "0.1.0-beta.8" dependencies = [ "array-init", + "bit-set", "bytemuck", "gfx-maths", "librashader-common", diff --git a/librashader-common/Cargo.toml b/librashader-common/Cargo.toml index 054eeb8..8aec754 100644 --- a/librashader-common/Cargo.toml +++ b/librashader-common/Cargo.toml @@ -15,6 +15,7 @@ description = "RetroArch shaders for all." default = [] opengl = ["gl"] d3d11 = ["windows", "dxgi"] +d3d12 = ["windows", "dxgi"] dxgi = ["windows"] vulkan = ["ash"] @@ -32,4 +33,5 @@ features = [ "Win32_Graphics_Dxgi_Common", "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D11", + "Win32_Graphics_Direct3D12", ] diff --git a/librashader-common/src/d3d12.rs b/librashader-common/src/d3d12.rs new file mode 100644 index 0000000..744ff7a --- /dev/null +++ b/librashader-common/src/d3d12.rs @@ -0,0 +1,22 @@ +use crate::{FilterMode, WrapMode}; +use windows::Win32::Graphics::Direct3D12; + +impl From for Direct3D12::D3D12_TEXTURE_ADDRESS_MODE { + fn from(value: WrapMode) -> Self { + match value { + WrapMode::ClampToBorder => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_BORDER, + WrapMode::ClampToEdge => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + WrapMode::Repeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_WRAP, + WrapMode::MirroredRepeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR, + } + } +} + +impl From for Direct3D12::D3D12_FILTER { + fn from(value: FilterMode) -> Self { + match value { + FilterMode::Linear => Direct3D12::D3D12_FILTER_MIN_MAG_MIP_LINEAR, + _ => Direct3D12::D3D12_FILTER_MIN_MAG_MIP_POINT, + } + } +} diff --git a/librashader-common/src/lib.rs b/librashader-common/src/lib.rs index 3ed9acd..60917c8 100644 --- a/librashader-common/src/lib.rs +++ b/librashader-common/src/lib.rs @@ -16,6 +16,10 @@ pub mod dxgi; #[cfg(all(target_os = "windows", feature = "d3d11"))] pub mod d3d11; +/// Direct3D 12 common conversions. +#[cfg(all(target_os = "windows", feature = "d3d12"))] +pub mod d3d12; + mod viewport; pub use viewport::Viewport; diff --git a/librashader-runtime-d3d12/src/d3d12_primitives.rs b/librashader-runtime-d3d12/src/d3d12_primitives.rs deleted file mode 100644 index 789a6bc..0000000 --- a/librashader-runtime-d3d12/src/d3d12_primitives.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::sync::Arc; -use windows::Win32::Graphics::Direct3D12::{D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC, D3D12_GPU_DESCRIPTOR_HANDLE, ID3D12DescriptorHeap, ID3D12Device}; -use crate::error; - -pub struct D3D12DescriptorHeapSlot { - cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE, - heap: Arc -} - -pub struct D3D12DescriptorHeap { - heap: ID3D12DescriptorHeap, - desc: D3D12_DESCRIPTOR_HEAP_DESC, - cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE, - gpu_handle: D3D12_GPU_DESCRIPTOR_HANDLE, - alignment: u32, - map: Box<[bool]>, - start: usize -} - -impl D3D12DescriptorHeap { - pub fn new(device: &ID3D12Device, desc: D3D12_DESCRIPTOR_HEAP_DESC) -> error::Result> { - unsafe { - let heap: ID3D12DescriptorHeap = device.CreateDescriptorHeap(&desc)?; - let cpu_handle = heap.GetCPUDescriptorHandleForHeapStart(); - let gpu_handle = heap.GetGPUDescriptorHandleForHeapStart(); - let alignment = device.GetDescriptorHandleIncrementSize(desc.Type); - let mut map = Vec::new(); - map.resize(desc.NumDescriptors as usize, false); - - Ok(Arc::new(D3D12DescriptorHeap { - heap, - desc, - cpu_handle, - gpu_handle, - alignment, - map: Box::new([]), - start: 0, - })) - } - } - - pub fn allocate_slot(self: &Arc) -> error::Result { - let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 }; - - for i in self.start..self.desc.NumDescriptors as usize { - if !self.map[i] { - self.map[i] = true; - handle.ptr = self.cpu_handle.ptr + (i * self.alignment) as u64; - self.start = i + 1; - return Ok(D3D12DescriptorHeapSlot { - cpu_handle: handle, - heap: Arc::clone(self), - }); - } - } - - todo!("error need to fail"); - } - - pub fn free_slot(&mut self) -> error::Result { - let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 }; - - for i in self.start..self.desc.NumDescriptors as usize { - if !self.map[i] { - self.map[i] = true; - handle.ptr = self.cpu_handle.ptr + (i * self.alignment) as u64; - self.start = i + 1; - return Ok(handle); - } - } - - todo!("error need to fail"); - } - -} - -impl Drop \ No newline at end of file diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 0dcacb9..90f7f03 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -2,11 +2,13 @@ use std::error::Error; use std::path::Path; use rustc_hash::FxHashMap; use windows::Win32::Graphics::Direct3D12::ID3D12Device; -use librashader_presets::ShaderPreset; +use librashader_presets::{ShaderPreset, TextureConfig}; use librashader_reflect::back::targets::HLSL; use librashader_reflect::front::GlslangCompilation; use librashader_reflect::reflect::presets::CompilePresetTarget; use crate::error; +use crate::samplers::SamplerSet; +use crate::texture::LutTexture; pub struct FilterChainD3D12 { pub(crate) common: FilterCommon, @@ -20,7 +22,7 @@ pub struct FilterChainD3D12 { pub(crate) struct FilterCommon { pub(crate) d3d12: ID3D12Device, // pub(crate) luts: FxHashMap, - // pub samplers: SamplerSet, + pub samplers: SamplerSet, // pub output_textures: Box<[Option]>, // pub feedback_textures: Box<[Option]>, // pub history_textures: Box<[Option]>, @@ -31,16 +33,25 @@ pub(crate) struct FilterCommon { impl FilterChainD3D12 { /// Load the shader preset at the given path into a filter chain. pub fn load_from_path( + device: &ID3D12Device, path: impl AsRef, options: Option<&()>, ) -> error::Result { // load passes from preset let preset = ShaderPreset::try_parse(path)?; - Self::load_from_preset(preset, options) + Self::load_from_preset(device, preset, options) + } + + fn load_luts( + device: &ID3D12Device, + textures: &[TextureConfig], + ) -> error::Result> { + todo!() } /// Load a filter chain from a pre-parsed `ShaderPreset`. pub fn load_from_preset( + device: &ID3D12Device, preset: ShaderPreset, options: Option<&()>, ) -> error::Result { @@ -49,7 +60,12 @@ impl FilterChainD3D12 { Box, >(preset.shaders, &preset.textures)?; - - todo!() + let samplers = SamplerSet::new(&device)?; + Ok(FilterChainD3D12 { + common: FilterCommon { + d3d12: device.clone(), + samplers, + }, + }) } } \ No newline at end of file diff --git a/librashader-runtime-d3d12/src/heap.rs b/librashader-runtime-d3d12/src/heap.rs new file mode 100644 index 0000000..f7a5647 --- /dev/null +++ b/librashader-runtime-d3d12/src/heap.rs @@ -0,0 +1,130 @@ +use std::cell::RefCell; +use std::marker::PhantomData; +use std::sync::Arc; +use windows::Win32::Graphics::Direct3D12::{D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_GPU_DESCRIPTOR_HANDLE, ID3D12DescriptorHeap, ID3D12Device}; +use crate::error; + +#[const_trait] +pub trait D3D12HeapType { + fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC; +} +pub struct SamplerHeap; + +impl const D3D12HeapType for SamplerHeap +{ + fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC { + D3D12_DESCRIPTOR_HEAP_DESC { + Type: D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + NumDescriptors: size as u32, + Flags: D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + NodeMask: 0, + } + } +} + +pub struct D3D12DescriptorHeapSlot { + cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE, + gpu_handle: D3D12_GPU_DESCRIPTOR_HANDLE, + heap: Arc>, + slot: usize, + _pd: PhantomData +} + +impl D3D12DescriptorHeapSlot { + /// Get the index of the resource within the heap. + pub fn index(&self) -> usize { + self.slot + } +} + +impl AsRef for D3D12DescriptorHeapSlot { + fn as_ref(&self) -> &D3D12_CPU_DESCRIPTOR_HANDLE { + &self.cpu_handle + } +} + +impl AsRef for D3D12DescriptorHeapSlot { + fn as_ref(&self) -> &D3D12_GPU_DESCRIPTOR_HANDLE { + &self.gpu_handle + } +} + +struct D3D12DescriptorHeapInner { + heap: ID3D12DescriptorHeap, + desc: D3D12_DESCRIPTOR_HEAP_DESC, + cpu_start: D3D12_CPU_DESCRIPTOR_HANDLE, + gpu_start: D3D12_GPU_DESCRIPTOR_HANDLE, + handle_size: usize, + start: usize, + // Bit flag representation of available handles in the heap. + // + // 0 - Occupied + // 1 - free + map: Box<[bool]>, +} + +pub struct D3D12DescriptorHeap(Arc>, PhantomData); + +impl D3D12DescriptorHeap { + pub fn new(device: &ID3D12Device, size: usize) -> error::Result> { + let desc = T::get_desc(size); + unsafe { + D3D12DescriptorHeap::new_with_desc(device, desc) + } + } +} + +impl D3D12DescriptorHeap { + pub unsafe fn new_with_desc(device: &ID3D12Device, desc: D3D12_DESCRIPTOR_HEAP_DESC) -> error::Result> { + unsafe { + let heap: ID3D12DescriptorHeap = device.CreateDescriptorHeap(&desc)?; + let cpu_start = heap.GetCPUDescriptorHandleForHeapStart(); + let gpu_start = heap.GetGPUDescriptorHandleForHeapStart(); + Ok(D3D12DescriptorHeap(Arc::new(RefCell::new(D3D12DescriptorHeapInner { + heap, + desc, + cpu_start, + gpu_start, + handle_size: device.GetDescriptorHandleIncrementSize(desc.Type) as usize, + start: 0, + map: vec![false; desc.NumDescriptors as usize].into_boxed_slice(), + })), PhantomData::default())) + } + } + + pub fn alloc_slot(&mut self) -> error::Result> { + let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 }; + + let mut inner = self.0.borrow_mut(); + for i in inner.start..inner.desc.NumDescriptors as usize { + if !inner.map[i] { + inner.map[i] = true; + handle.ptr = inner.cpu_start.ptr + (i * inner.handle_size); + inner.start = i + 1; + + let gpu_handle = D3D12_GPU_DESCRIPTOR_HANDLE { + ptr: (handle.ptr as u64 - inner.cpu_start.ptr as u64 + inner.gpu_start.ptr), + }; + return Ok(D3D12DescriptorHeapSlot { + cpu_handle: handle, + slot: i, + heap: Arc::clone(&self.0), + gpu_handle, + _pd: Default::default(), + }); + } + } + + todo!("error need to fail"); + } +} + +impl Drop for D3D12DescriptorHeapSlot { + fn drop(&mut self) { + let mut inner = self.heap.borrow_mut(); + inner.map[self.slot] = false; + if inner.start > self.slot { + inner.start = self.slot + } + } +} diff --git a/librashader-runtime-d3d12/src/hello_triangle.rs b/librashader-runtime-d3d12/src/hello_triangle.rs index 5fa982e..ce6567c 100644 --- a/librashader-runtime-d3d12/src/hello_triangle.rs +++ b/librashader-runtime-d3d12/src/hello_triangle.rs @@ -1,3 +1,4 @@ +use std::ffi::CStr; use windows::{ core::*, Win32::Foundation::*, Win32::Graphics::Direct3D::Fxc::*, Win32::Graphics::Direct3D::*, Win32::Graphics::Direct3D12::*, Win32::Graphics::Dxgi::Common::*, Win32::Graphics::Dxgi::*, @@ -27,9 +28,10 @@ float4 PSMain(PSInput input) : SV_TARGET }\0"; use std::mem::transmute; +use std::path::Path; pub trait DXSample { - fn new(command_line: &SampleCommandLine) -> Result + fn new(filter: impl AsRef, command_line: &SampleCommandLine) -> Result where Self: Sized; @@ -221,7 +223,17 @@ fn get_hardware_adapter(factory: &IDXGIFactory4) -> Result { unreachable!() } +unsafe extern "system" fn debug_log(category: D3D12_MESSAGE_CATEGORY, severity: D3D12_MESSAGE_SEVERITY, id: D3D12_MESSAGE_ID, pdescription: ::windows::core::PCSTR, pcontext: *mut ::core::ffi::c_void) { + unsafe { + let desc = CStr::from_ptr(pdescription.as_ptr().cast()); + eprintln!("[{severity:?}-{category:?}] {desc:?}") + + } +} + pub mod d3d12_hello_triangle { + use std::path::Path; + use crate::filter_chain::FilterChainD3D12; use super::*; const FRAME_COUNT: u32 = 2; @@ -230,6 +242,7 @@ pub mod d3d12_hello_triangle { dxgi_factory: IDXGIFactory4, device: ID3D12Device, resources: Option, + pub filter: FilterChainD3D12, } struct Resources { @@ -258,13 +271,20 @@ pub mod d3d12_hello_triangle { } impl DXSample for Sample { - fn new(command_line: &SampleCommandLine) -> Result { + fn new(filter: impl AsRef, command_line: &SampleCommandLine) -> Result { let (dxgi_factory, device) = create_device(command_line)?; + // + // let queue = device.cast::()?; + // unsafe { + // queue.RegisterMessageCallback(Some(debug_log), D3D12_MESSAGE_CALLBACK_FLAG_NONE, std::ptr::null_mut(), &mut 0).expect("could not register message callback"); + // } + let filter = FilterChainD3D12::load_from_path(&device, filter, None).unwrap(); Ok(Sample { dxgi_factory, device, resources: None, + filter, }) } @@ -516,20 +536,16 @@ pub mod d3d12_hello_triangle { } fn create_device(command_line: &SampleCommandLine) -> Result<(IDXGIFactory4, ID3D12Device)> { - if cfg!(debug_assertions) { - unsafe { - let mut debug: Option = None; - if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(debug) { - debug.EnableDebugLayer(); - } - } - } + // unsafe { + // let mut debug: Option = None; + // if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(debug) { + // eprintln!("enabling debug"); + // debug.EnableDebugLayer(); + // } + // } - let dxgi_factory_flags = if cfg!(debug_assertions) { - DXGI_CREATE_FACTORY_DEBUG - } else { - 0 - }; + + let dxgi_factory_flags = DXGI_CREATE_FACTORY_DEBUG; let dxgi_factory: IDXGIFactory4 = unsafe { CreateDXGIFactory2(dxgi_factory_flags) }?; @@ -540,7 +556,7 @@ pub mod d3d12_hello_triangle { }?; let mut device: Option = None; - unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_11_0, &mut device) }?; + unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_12_2, &mut device) }?; Ok((dxgi_factory, device.unwrap())) } @@ -593,11 +609,7 @@ pub mod d3d12_hello_triangle { device: &ID3D12Device, root_signature: &ID3D12RootSignature, ) -> Result { - let compile_flags = if cfg!(debug_assertions) { - D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION - } else { - 0 - }; + let compile_flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; let vertex_shader = compile_shader(SHADER, b"VSMain\0", b"vs_5_0\0")?; let pixel_shader = compile_shader(SHADER, b"PSMain\0", b"ps_5_0\0")?; diff --git a/librashader-runtime-d3d12/src/samplers.rs b/librashader-runtime-d3d12/src/samplers.rs index 7074394..8d44019 100644 --- a/librashader-runtime-d3d12/src/samplers.rs +++ b/librashader-runtime-d3d12/src/samplers.rs @@ -1,7 +1,71 @@ use rustc_hash::FxHashMap; -use windows::Win32::Graphics::Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE; +use windows::Win32::Graphics::Direct3D12::{D3D12_COMPARISON_FUNC_NEVER, D3D12_FLOAT32_MAX, D3D12_SAMPLER_DESC, D3D12_TEXTURE_ADDRESS_MODE, ID3D12Device}; use librashader_common::{FilterMode, WrapMode}; +use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, SamplerHeap}; +use crate::error; pub struct SamplerSet { - samplers: FxHashMap<(WrapMode, FilterMode), D3D12_GPU_DESCRIPTOR_HANDLE>, + samplers: FxHashMap<(WrapMode, FilterMode), D3D12DescriptorHeapSlot>, + heap: D3D12DescriptorHeap +} + +impl SamplerSet { + pub fn get(&self, wrap: WrapMode, filter: FilterMode) -> &D3D12DescriptorHeapSlot { + self.samplers.get(&(wrap, filter)).unwrap() + } + pub fn new(device: &ID3D12Device) -> error::Result { + + let mut samplers = FxHashMap::default(); + let wrap_modes = &[ + WrapMode::ClampToBorder, + WrapMode::ClampToEdge, + WrapMode::Repeat, + WrapMode::MirroredRepeat, + ]; + + let mut heap = D3D12DescriptorHeap::new(&device, (2 * wrap_modes.len()))?; + + for wrap_mode in wrap_modes { + unsafe { + let mut linear = heap.alloc_slot()?; + device.CreateSampler( + &D3D12_SAMPLER_DESC { + Filter: FilterMode::Linear.into(), + AddressU: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode), + AddressV: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode), + AddressW: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode), + MipLODBias: 0.0, + MaxAnisotropy: 1, + ComparisonFunc: D3D12_COMPARISON_FUNC_NEVER, + BorderColor: [0.0, 0.0, 0.0, 0.0], + MinLOD: -D3D12_FLOAT32_MAX, + MaxLOD: D3D12_FLOAT32_MAX, + }, + *linear.as_ref(), + ); + + let mut nearest = heap.alloc_slot()?; + device.CreateSampler( + &D3D12_SAMPLER_DESC { + Filter: FilterMode::Nearest.into(), + AddressU: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode), + AddressV: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode), + AddressW: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode), + MipLODBias: 0.0, + MaxAnisotropy: 1, + ComparisonFunc: D3D12_COMPARISON_FUNC_NEVER, + BorderColor: [0.0, 0.0, 0.0, 0.0], + MinLOD: -D3D12_FLOAT32_MAX, + MaxLOD: D3D12_FLOAT32_MAX, + }, + *nearest.as_ref() + ); + + samplers.insert((*wrap_mode, FilterMode::Linear), linear); + samplers.insert((*wrap_mode, FilterMode::Nearest), nearest); + } + } + + Ok(SamplerSet { samplers, heap }) + } } diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs new file mode 100644 index 0000000..fc20bf9 --- /dev/null +++ b/librashader-runtime-d3d12/src/texture.rs @@ -0,0 +1,20 @@ +use windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_DESC, ID3D12Device, ID3D12Resource}; +use librashader_common::{FilterMode, WrapMode}; +use librashader_runtime::image::Image; + +pub struct LutTexture { + handle: ID3D12Resource, + +} + +impl LutTexture { + pub fn new( + device: &ID3D12Device, + source: &Image, + desc: D3D12_RESOURCE_DESC, + filter: FilterMode, + wrap_mode: WrapMode, + ) { + // todo: d3d12:800 + } +} \ No newline at end of file