From 9a3ce029d75e722e1c039f1db4f74221d0729870 Mon Sep 17 00:00:00 2001 From: chyyran Date: Tue, 24 Jan 2023 23:15:43 -0500 Subject: [PATCH] d3d12: partially implement lut texture --- librashader-runtime-d3d12/src/error.rs | 13 ++ librashader-runtime-d3d12/src/filter_chain.rs | 95 +++++++++-- librashader-runtime-d3d12/src/heap.rs | 94 ++++++++--- .../src/hello_triangle.rs | 70 ++++---- librashader-runtime-d3d12/src/samplers.rs | 26 +-- librashader-runtime-d3d12/src/texture.rs | 159 +++++++++++++++++- librashader-runtime-d3d12/src/util.rs | 142 ++++++++++++++++ 7 files changed, 508 insertions(+), 91 deletions(-) create mode 100644 librashader-runtime-d3d12/src/util.rs diff --git a/librashader-runtime-d3d12/src/error.rs b/librashader-runtime-d3d12/src/error.rs index fa138cb..b0bf0ec 100644 --- a/librashader-runtime-d3d12/src/error.rs +++ b/librashader-runtime-d3d12/src/error.rs @@ -1,3 +1,16 @@ use std::error::Error; pub type Result = std::result::Result>; + +// todo: make this return error +macro_rules! assume_d3d12_init { + ($value:ident, $call:literal) => { + let $value = $value.expect($call); + }; + (mut $value:ident, $call:literal) => { + let mut $value = $value.expect($call); + }; +} + +/// Macro for unwrapping result of a D3D function. +pub(crate) use assume_d3d12_init; diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 90f7f03..79f030a 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -1,14 +1,23 @@ -use std::error::Error; -use std::path::Path; -use rustc_hash::FxHashMap; -use windows::Win32::Graphics::Direct3D12::ID3D12Device; +use crate::error; +use crate::heap::{D3D12DescriptorHeap, LutTextureHeap}; +use crate::samplers::SamplerSet; +use crate::texture::LutTexture; 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; +use librashader_runtime::image::{Image, UVDirection}; +use rustc_hash::FxHashMap; +use std::error::Error; +use std::path::Path; +use windows::core::Interface; +use windows::Win32::Graphics::Direct3D12::{ + ID3D12CommandAllocator, ID3D12CommandList, ID3D12CommandQueue, ID3D12Device, ID3D12Fence, + ID3D12GraphicsCommandList, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, + D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE, +}; +use windows::Win32::System::Threading::{CreateEventA, WaitForSingleObject}; +use windows::Win32::System::WindowsProgramming::INFINITE; pub struct FilterChainD3D12 { pub(crate) common: FilterCommon, @@ -28,6 +37,8 @@ pub(crate) struct FilterCommon { // pub history_textures: Box<[Option]>, // pub config: FilterMutable, // pub disable_mipmaps: bool, + lut_heap: D3D12DescriptorHeap, + luts: FxHashMap, } impl FilterChainD3D12 { @@ -44,9 +55,59 @@ impl FilterChainD3D12 { fn load_luts( device: &ID3D12Device, + heap: &mut D3D12DescriptorHeap, textures: &[TextureConfig], ) -> error::Result> { - todo!() + unsafe { + // 1 time queue infrastructure for lut uploads + let command_pool: ID3D12CommandAllocator = + device.CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT)?; + let cmd: ID3D12GraphicsCommandList = + device.CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, &command_pool, None)?; + let queue: ID3D12CommandQueue = + device.CreateCommandQueue(&D3D12_COMMAND_QUEUE_DESC { + Type: D3D12_COMMAND_LIST_TYPE_DIRECT, + Priority: 0, + Flags: D3D12_COMMAND_QUEUE_FLAG_NONE, + NodeMask: 0, + })?; + + let fence_event = unsafe { CreateEventA(None, false, false, None)? }; + let fence: ID3D12Fence = device.CreateFence(0, D3D12_FENCE_FLAG_NONE)?; + + let mut luts = FxHashMap::default(); + + for (index, texture) in textures.iter().enumerate() { + let image = Image::load(&texture.path, UVDirection::TopLeft)?; + + let texture = LutTexture::new( + device, + heap, + &cmd, + &image, + texture.filter_mode, + texture.wrap_mode, + // todo: mipmaps + false, + )?; + luts.insert(index, texture); + } + + cmd.Close()?; + + queue.ExecuteCommandLists(&[cmd.cast()?]); + queue.Signal(&fence, 1)?; + + // Wait until the previous frame is finished. + if unsafe { fence.GetCompletedValue() } < 1 { + unsafe { fence.SetEventOnCompletion(1, fence_event) } + .ok() + .unwrap(); + + unsafe { WaitForSingleObject(fence_event, INFINITE) }; + } + Ok(luts) + } } /// Load a filter chain from a pre-parsed `ShaderPreset`. @@ -55,17 +116,23 @@ impl FilterChainD3D12 { preset: ShaderPreset, options: Option<&()>, ) -> error::Result { - let (passes, semantics) = HLSL::compile_preset_passes::< - GlslangCompilation, - Box, - >(preset.shaders, &preset.textures)?; + let (passes, semantics) = HLSL::compile_preset_passes::>( + preset.shaders, + &preset.textures, + )?; + + let samplers = SamplerSet::new(device)?; + let mut lut_heap = D3D12DescriptorHeap::new(device, preset.textures.len())?; + + let luts = FilterChainD3D12::load_luts(device, &mut lut_heap, &preset.textures)?; - let samplers = SamplerSet::new(&device)?; Ok(FilterChainD3D12 { common: FilterCommon { d3d12: device.clone(), samplers, + lut_heap, + luts, }, }) } -} \ No newline at end of file +} diff --git a/librashader-runtime-d3d12/src/heap.rs b/librashader-runtime-d3d12/src/heap.rs index f7a5647..ad7cdc0 100644 --- a/librashader-runtime-d3d12/src/heap.rs +++ b/librashader-runtime-d3d12/src/heap.rs @@ -1,17 +1,28 @@ +use crate::error; 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; +use windows::Win32::Graphics::Direct3D12::{ + ID3D12DescriptorHeap, ID3D12Device, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC, + D3D12_DESCRIPTOR_HEAP_FLAG_NONE, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + D3D12_GPU_DESCRIPTOR_HANDLE, +}; #[const_trait] pub trait D3D12HeapType { fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC; } -pub struct SamplerHeap; -impl const D3D12HeapType for SamplerHeap -{ +pub trait D3D12ShaderVisibleHeapType: D3D12HeapType {} + +pub struct SamplerPaletteHeap; +pub struct LutTextureHeap; + +impl D3D12ShaderVisibleHeapType for SamplerPaletteHeap {} + +impl const D3D12HeapType for SamplerPaletteHeap { + // sampler palettes just get set directly fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC { D3D12_DESCRIPTOR_HEAP_DESC { Type: D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, @@ -22,12 +33,24 @@ impl const D3D12HeapType for SamplerHeap } } +impl const D3D12HeapType for LutTextureHeap { + // Lut texture heaps are CPU only and get bound to the descriptor heap of the shader. + fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC { + D3D12_DESCRIPTOR_HEAP_DESC { + Type: D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + NumDescriptors: size as u32, + Flags: D3D12_DESCRIPTOR_HEAP_FLAG_NONE, + NodeMask: 0, + } + } +} + pub struct D3D12DescriptorHeapSlot { cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE, - gpu_handle: D3D12_GPU_DESCRIPTOR_HANDLE, + gpu_handle: Option, heap: Arc>, slot: usize, - _pd: PhantomData + _pd: PhantomData, } impl D3D12DescriptorHeapSlot { @@ -43,9 +66,11 @@ impl AsRef for D3D12DescriptorHeapSlot { } } -impl AsRef for D3D12DescriptorHeapSlot { +impl AsRef + for D3D12DescriptorHeapSlot +{ fn as_ref(&self) -> &D3D12_GPU_DESCRIPTOR_HANDLE { - &self.gpu_handle + self.gpu_handle.as_ref().unwrap() } } @@ -53,7 +78,7 @@ struct D3D12DescriptorHeapInner { heap: ID3D12DescriptorHeap, desc: D3D12_DESCRIPTOR_HEAP_DESC, cpu_start: D3D12_CPU_DESCRIPTOR_HANDLE, - gpu_start: D3D12_GPU_DESCRIPTOR_HANDLE, + gpu_start: Option, handle_size: usize, start: usize, // Bit flag representation of available handles in the heap. @@ -65,30 +90,40 @@ struct D3D12DescriptorHeapInner { pub struct D3D12DescriptorHeap(Arc>, PhantomData); -impl D3D12DescriptorHeap { +impl D3D12DescriptorHeap { pub fn new(device: &ID3D12Device, size: usize) -> error::Result> { let desc = T::get_desc(size); - unsafe { - D3D12DescriptorHeap::new_with_desc(device, desc) - } + unsafe { D3D12DescriptorHeap::new_with_desc(device, desc) } } } impl D3D12DescriptorHeap { - pub unsafe fn new_with_desc(device: &ID3D12Device, desc: D3D12_DESCRIPTOR_HEAP_DESC) -> error::Result> { + 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())) + + let gpu_start = if (desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE).0 != 0 { + Some(heap.GetGPUDescriptorHandleForHeapStart()) + } else { + None + }; + + 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(), + )) } } @@ -102,9 +137,12 @@ impl D3D12DescriptorHeap { 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), - }; + let gpu_handle = inner + .gpu_start + .map(|gpu_start| D3D12_GPU_DESCRIPTOR_HANDLE { + ptr: (handle.ptr as u64 - inner.cpu_start.ptr as u64 + gpu_start.ptr), + }); + return Ok(D3D12DescriptorHeapSlot { cpu_handle: handle, slot: i, diff --git a/librashader-runtime-d3d12/src/hello_triangle.rs b/librashader-runtime-d3d12/src/hello_triangle.rs index ce6567c..6e571ac 100644 --- a/librashader-runtime-d3d12/src/hello_triangle.rs +++ b/librashader-runtime-d3d12/src/hello_triangle.rs @@ -32,8 +32,8 @@ use std::path::Path; pub trait DXSample { fn new(filter: impl AsRef, command_line: &SampleCommandLine) -> Result - where - Self: Sized; + where + Self: Sized; fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>; @@ -69,8 +69,8 @@ fn build_command_line() -> SampleCommandLine { } fn run_sample(mut sample: S) -> Result<()> - where - S: DXSample, +where + S: DXSample, { let instance = unsafe { GetModuleHandleA(None)? }; @@ -214,7 +214,7 @@ fn get_hardware_adapter(factory: &IDXGIFactory4) -> Result { std::ptr::null_mut::>(), ) } - .is_ok() + .is_ok() { return Ok(adapter); } @@ -223,18 +223,23 @@ 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 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::*; + use crate::filter_chain::FilterChainD3D12; + use std::path::Path; const FRAME_COUNT: u32 = 2; @@ -274,10 +279,17 @@ pub mod d3d12_hello_triangle { 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 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 { @@ -321,7 +333,7 @@ pub mod d3d12_hello_triangle { None, )? } - .cast()?; + .cast()?; // This sample does not support fullscreen transitions unsafe { @@ -496,11 +508,7 @@ pub mod d3d12_hello_triangle { // Record commands. unsafe { // TODO: workaround for https://github.com/microsoft/win32metadata/issues/1006 - command_list.ClearRenderTargetView( - rtv_handle, - &*[0.3, 0.4, 0.6, 1.0].as_ptr(), - &[], - ); + command_list.ClearRenderTargetView(rtv_handle, &*[0.3, 0.4, 0.6, 1.0].as_ptr(), &[]); command_list.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); command_list.IASetVertexBuffers(0, Some(&[resources.vbv])); command_list.DrawInstanced(3, 1, 0, 0); @@ -536,14 +544,13 @@ pub mod d3d12_hello_triangle { } fn create_device(command_line: &SampleCommandLine) -> Result<(IDXGIFactory4, ID3D12Device)> { - // unsafe { - // let mut debug: Option = None; - // if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(debug) { - // eprintln!("enabling 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 = DXGI_CREATE_FACTORY_DEBUG; @@ -571,7 +578,7 @@ pub mod d3d12_hello_triangle { let signature = unsafe { D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &mut signature, None) } - .map(|()| signature.unwrap())?; + .map(|()| signature.unwrap())?; unsafe { device.CreateRootSignature( @@ -609,7 +616,7 @@ pub mod d3d12_hello_triangle { device: &ID3D12Device, root_signature: &ID3D12RootSignature, ) -> Result { - let compile_flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; + 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")?; @@ -791,8 +798,8 @@ pub mod d3d12_hello_triangle { .fence .SetEventOnCompletion(fence, resources.fence_event) } - .ok() - .unwrap(); + .ok() + .unwrap(); unsafe { WaitForSingleObject(resources.fence_event, INFINITE) }; } @@ -801,7 +808,6 @@ pub mod d3d12_hello_triangle { } } - pub fn main(sample: S) -> Result<()> { run_sample(sample)?; diff --git a/librashader-runtime-d3d12/src/samplers.rs b/librashader-runtime-d3d12/src/samplers.rs index 8d44019..593ead5 100644 --- a/librashader-runtime-d3d12/src/samplers.rs +++ b/librashader-runtime-d3d12/src/samplers.rs @@ -1,20 +1,26 @@ -use rustc_hash::FxHashMap; -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; +use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, SamplerPaletteHeap}; +use librashader_common::{FilterMode, WrapMode}; +use rustc_hash::FxHashMap; +use windows::Win32::Graphics::Direct3D12::{ + ID3D12Device, D3D12_COMPARISON_FUNC_NEVER, D3D12_FLOAT32_MAX, D3D12_SAMPLER_DESC, + D3D12_TEXTURE_ADDRESS_MODE, +}; pub struct SamplerSet { - samplers: FxHashMap<(WrapMode, FilterMode), D3D12DescriptorHeapSlot>, - heap: D3D12DescriptorHeap + samplers: FxHashMap<(WrapMode, FilterMode), D3D12DescriptorHeapSlot>, + heap: D3D12DescriptorHeap, } impl SamplerSet { - pub fn get(&self, wrap: WrapMode, filter: FilterMode) -> &D3D12DescriptorHeapSlot { + 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, @@ -23,7 +29,7 @@ impl SamplerSet { WrapMode::MirroredRepeat, ]; - let mut heap = D3D12DescriptorHeap::new(&device, (2 * wrap_modes.len()))?; + let mut heap = D3D12DescriptorHeap::new(&device, 2 * wrap_modes.len())?; for wrap_mode in wrap_modes { unsafe { @@ -58,7 +64,7 @@ impl SamplerSet { MinLOD: -D3D12_FLOAT32_MAX, MaxLOD: D3D12_FLOAT32_MAX, }, - *nearest.as_ref() + *nearest.as_ref(), ); samplers.insert((*wrap_mode, FilterMode::Linear), linear); diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs index fc20bf9..d718710 100644 --- a/librashader-runtime-d3d12/src/texture.rs +++ b/librashader-runtime-d3d12/src/texture.rs @@ -1,20 +1,165 @@ -use windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_DESC, ID3D12Device, ID3D12Resource}; -use librashader_common::{FilterMode, WrapMode}; +use crate::error; +use crate::error::assume_d3d12_init; +use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, LutTextureHeap}; +use crate::util::d3d12_get_closest_format; +use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_runtime::image::Image; +use windows::Win32::Graphics::Direct3D12::{ID3D12CommandList, ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_TYPE_UPLOAD, D3D12_MEMORY_POOL_UNKNOWN, D3D12_PLACED_SUBRESOURCE_FOOTPRINT, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_SRV, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RANGE}; +use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; pub struct LutTexture { - handle: ID3D12Resource, - + resource: ID3D12Resource, + descriptor: D3D12DescriptorHeapSlot, + size: Size, + filter: FilterMode, + wrap_mode: WrapMode, } impl LutTexture { pub fn new( device: &ID3D12Device, + heap: &mut D3D12DescriptorHeap, + cmd: &ID3D12GraphicsCommandList, source: &Image, - desc: D3D12_RESOURCE_DESC, filter: FilterMode, wrap_mode: WrapMode, - ) { + mipmap: bool, + ) -> error::Result { // todo: d3d12:800 + let mut desc = D3D12_RESOURCE_DESC { + Dimension: D3D12_RESOURCE_DIMENSION_TEXTURE2D, + Alignment: 0, + Width: source.size.width as u64, + Height: source.size.height, + DepthOrArraySize: 1, + MipLevels: 1, // todo: mipmaps + // MipLevels: if mipmap { u16::MAX } else { 1 }, + Format: ImageFormat::R8G8B8A8Unorm.into(), + SampleDesc: DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + Layout: Default::default(), + Flags: Default::default(), + }; + + let format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT { + Format: desc.Format, + Support1: D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, + ..Default::default() + }; + + desc.Format = d3d12_get_closest_format(device, desc.Format, format_support); + let descriptor = heap.alloc_slot()?; + + // create handles on GPU + let mut resource: Option = None; + unsafe { + device.CreateCommittedResource( + &D3D12_HEAP_PROPERTIES { + Type: D3D12_HEAP_TYPE_DEFAULT, + CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, + CreationNodeMask: 1, + VisibleNodeMask: 1, + }, + D3D12_HEAP_FLAG_NONE, + &desc, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + None, + &mut resource, + )?; + } + assume_d3d12_init!(resource, "CreateCommittedResource"); + unsafe { + let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC { + Format: desc.Format, + ViewDimension: D3D12_SRV_DIMENSION_TEXTURE2D, + Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, + Anonymous: D3D12_SHADER_RESOURCE_VIEW_DESC_0 { + Texture2D: D3D12_TEX2D_SRV { + MipLevels: desc.MipLevels as u32, + ..Default::default() + }, + }, + }; + + device.CreateShaderResourceView(&resource, Some(&srv_desc), *descriptor.as_ref()); + } + + let mut buffer_desc = D3D12_RESOURCE_DESC { + Dimension: D3D12_RESOURCE_DIMENSION_BUFFER, + ..Default::default() + }; + + let mut layout = D3D12_PLACED_SUBRESOURCE_FOOTPRINT::default(); + let mut numrows = 0; + let mut rowsize = 0; + let mut total = 0; + // texture upload + unsafe { + device.GetCopyableFootprints( + &desc, + 0, + 1, + 0, + Some(&mut layout), + Some(&mut numrows), + Some(&mut rowsize), + Some(&mut total), + ); + + buffer_desc.Width = total; + buffer_desc.Height = 1; + buffer_desc.DepthOrArraySize = 1; + buffer_desc.MipLevels = 1; + buffer_desc.SampleDesc.Count = 1; + buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + } + let mut upload: Option = None; + + unsafe { + device.CreateCommittedResource( + &D3D12_HEAP_PROPERTIES { + Type: D3D12_HEAP_TYPE_UPLOAD, + CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, + CreationNodeMask: 1, + VisibleNodeMask: 1, + }, + D3D12_HEAP_FLAG_NONE, + &buffer_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, + None, + &mut upload, + )?; + } + assume_d3d12_init!(upload, "CreateCommittedResource"); + + unsafe { + let mut range = D3D12_RANGE { + Begin: 0, + End: 0 + }; + + let mut buf = std::ptr::null_mut(); + + upload.Map(0, Some(&range), Some(&mut buf))?; + + upload.Unmap(0, None); + + } + // todo: upload image data to textur + + Ok(LutTexture { + resource, + descriptor, + size: source.size, + filter, + wrap_mode, + }) } -} \ No newline at end of file +} + + +// todo https://github.com/microsoft/DirectX-Graphics-Samples/blob/master/Libraries/D3D12RaytracingFallback/Include/d3dx12.h#L1893 \ No newline at end of file diff --git a/librashader-runtime-d3d12/src/util.rs b/librashader-runtime-d3d12/src/util.rs new file mode 100644 index 0000000..87ce95f --- /dev/null +++ b/librashader-runtime-d3d12/src/util.rs @@ -0,0 +1,142 @@ +use crate::error; +use windows::core::PCSTR; +use windows::Win32::Graphics::Direct3D::Fxc::{ + D3DCompile, D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, +}; +use windows::Win32::Graphics::Direct3D::ID3DBlob; +use windows::Win32::Graphics::Direct3D12::{ + ID3D12Device, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FEATURE_FORMAT_SUPPORT, +}; +use windows::Win32::Graphics::Dxgi::Common::*; + +/// wtf retroarch? +const DXGI_FORMAT_EX_A4R4G4B4_UNORM: DXGI_FORMAT = DXGI_FORMAT(1000); + +const fn d3d12_format_fallback_list(format: DXGI_FORMAT) -> Option<&'static [DXGI_FORMAT]> { + match format { + DXGI_FORMAT_R32G32B32A32_FLOAT => Some(&[ + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_R16G16B16A16_FLOAT => Some(&[ + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_R8G8B8A8_UNORM => Some(&[ + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8X8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => Some(&[ + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8X8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_B8G8R8A8_UNORM => Some(&[ + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_B8G8R8X8_UNORM => Some(&[ + DXGI_FORMAT_B8G8R8X8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_B5G6R5_UNORM => Some(&[ + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B8G8R8X8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_EX_A4R4G4B4_UNORM | DXGI_FORMAT_B4G4R4A4_UNORM => Some(&[ + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_A8_UNORM => Some(&[ + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + DXGI_FORMAT_R8_UNORM => Some(&[ + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + ]), + _ => None, + } +} + +pub fn d3d12_get_closest_format( + device: &ID3D12Device, + format: DXGI_FORMAT, + format_support: D3D12_FEATURE_DATA_FORMAT_SUPPORT, +) -> DXGI_FORMAT { + let default_list = [format, DXGI_FORMAT_UNKNOWN]; + let format_support_list = d3d12_format_fallback_list(format).unwrap_or(&default_list); + + for supported in format_support_list { + unsafe { + let mut support = D3D12_FEATURE_DATA_FORMAT_SUPPORT { + Format: format, + ..Default::default() + }; + if device + .CheckFeatureSupport( + D3D12_FEATURE_FORMAT_SUPPORT, + &mut support as *mut _ as *mut _, + std::mem::size_of::() as u32, + ) + .is_ok() + && (support.Support1 & format_support.Support1) == format_support.Support1 + && (support.Support2 & format_support.Support2) == format_support.Support2 + { + return *supported; + } + } + } + DXGI_FORMAT_UNKNOWN +} + +pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error::Result { + unsafe { + let mut blob = None; + D3DCompile( + source.as_ptr().cast(), + source.len(), + None, + None, + None, + PCSTR(entry.as_ptr()), + PCSTR(version.as_ptr()), + if cfg!(feature = "debug-shader") { + D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION + } else { + 0 + }, + 0, + &mut blob, + None, + )?; + + Ok(blob.unwrap()) + } +}