diff --git a/Cargo.lock b/Cargo.lock index a342bf7..de7ce69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,6 +102,20 @@ name = "bytemuck" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "byteorder" diff --git a/librashader-runtime-d3d12/Cargo.toml b/librashader-runtime-d3d12/Cargo.toml index bc9def5..2083ebf 100644 --- a/librashader-runtime-d3d12/Cargo.toml +++ b/librashader-runtime-d3d12/Cargo.toml @@ -21,7 +21,7 @@ thiserror = "1.0.37" spirv_cross = { package = "librashader-spirv-cross", version = "0.23" } rustc-hash = "1.1.0" -bytemuck = "1.12.3" +bytemuck = { version = "1.12.3", features = ["derive"] } array-init = "2.1.0" bit-set = "0.5.3" diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 4b7e986..80affcc 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -1,5 +1,6 @@ +use std::borrow::Borrow; use crate::error; -use crate::heap::{D3D12DescriptorHeap, LutTextureHeap}; +use crate::heap::{D3D12DescriptorHeap, LutTextureHeap, ResourceWorkHeap}; use crate::samplers::SamplerSet; use crate::texture::LutTexture; use librashader_presets::{ShaderPreset, TextureConfig}; @@ -11,12 +12,14 @@ use rustc_hash::FxHashMap; use std::error::Error; use std::path::Path; use windows::core::Interface; +use windows::w; +use windows::Win32::Foundation::CloseHandle; 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::Threading::{CreateEventA, ResetEvent, WaitForSingleObject}; use windows::Win32::System::WindowsProgramming::INFINITE; use crate::mipmap::D3D12MipmapGen; @@ -59,7 +62,9 @@ impl FilterChainD3D12 { device: &ID3D12Device, heap: &mut D3D12DescriptorHeap, textures: &[TextureConfig], + mipmap_gen: &D3D12MipmapGen ) -> error::Result> { + let mut work_heap: D3D12DescriptorHeap = D3D12DescriptorHeap::new(device, u16::MAX as usize)?; unsafe { // 1 time queue infrastructure for lut uploads let command_pool: ID3D12CommandAllocator = @@ -74,12 +79,15 @@ impl FilterChainD3D12 { NodeMask: 0, })?; + queue.SetName(w!("LutQueue"))?; + let fence_event = unsafe { CreateEventA(None, false, false, None)? }; let fence: ID3D12Fence = device.CreateFence(0, D3D12_FENCE_FLAG_NONE)?; let mut residuals = Vec::new(); let mut luts = FxHashMap::default(); + for (index, texture) in textures.iter().enumerate() { let image = Image::load(&texture.path, UVDirection::TopLeft)?; @@ -101,15 +109,40 @@ impl FilterChainD3D12 { queue.ExecuteCommandLists(&[cmd.cast()?]); queue.Signal(&fence, 1)?; - // Wait until the previous frame is finished. + // Wait until finished if unsafe { fence.GetCompletedValue() } < 1 { unsafe { fence.SetEventOnCompletion(1, fence_event) } .ok() .unwrap(); unsafe { WaitForSingleObject(fence_event, INFINITE) }; + unsafe { ResetEvent(fence_event) }; } + cmd.Reset(&command_pool, None).unwrap(); + + let residuals = mipmap_gen + .mipmapping_context(&cmd, &mut work_heap, |context| { + for lut in luts.values() { + lut.generate_mipmaps(context).unwrap() + } + })?; + + // + cmd.Close()?; + queue.ExecuteCommandLists(&[cmd.cast()?]); + queue.Signal(&fence, 2)?; + // + if unsafe { fence.GetCompletedValue() } < 2 { + unsafe { fence.SetEventOnCompletion(2, fence_event) } + .ok() + .unwrap(); + + unsafe { WaitForSingleObject(fence_event, INFINITE) }; + unsafe { CloseHandle(fence_event) }; + } + + std::mem::forget(residuals); Ok(luts) } } @@ -126,10 +159,10 @@ impl FilterChainD3D12 { )?; let samplers = SamplerSet::new(device)?; - let mipmap_gen = D3D12MipmapGen::new(device)?; + let mipmap_gen = D3D12MipmapGen::new(device).unwrap(); let mut lut_heap = D3D12DescriptorHeap::new(device, preset.textures.len())?; - let luts = FilterChainD3D12::load_luts(device, &mut lut_heap, &preset.textures)?; + let luts = FilterChainD3D12::load_luts(device, &mut lut_heap, &preset.textures, &mipmap_gen).unwrap(); Ok(FilterChainD3D12 { common: FilterCommon { diff --git a/librashader-runtime-d3d12/src/heap.rs b/librashader-runtime-d3d12/src/heap.rs index d3b098e..55f8db4 100644 --- a/librashader-runtime-d3d12/src/heap.rs +++ b/librashader-runtime-d3d12/src/heap.rs @@ -88,6 +88,12 @@ impl AsRef } } +impl From<&D3D12DescriptorHeap> for ID3D12DescriptorHeap { + fn from(value: &D3D12DescriptorHeap) -> Self { + value.0.borrow().heap.clone() + } +} + struct D3D12DescriptorHeapInner { device: ID3D12Device, heap: ID3D12DescriptorHeap, @@ -158,7 +164,7 @@ impl D3D12DescriptorHeap { 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), + ptr: (handle.ptr as u64 - inner.cpu_start.ptr as u64) + gpu_start.ptr, }); return Ok(D3D12DescriptorHeapSlot { @@ -175,7 +181,7 @@ impl D3D12DescriptorHeap { } pub fn copy_descriptors(&mut self, - source: &[impl AsRef; NUM_DESC]) + source: &[&D3D12_CPU_DESCRIPTOR_HANDLE; NUM_DESC]) -> error::Result<[D3D12DescriptorHeapSlot; NUM_DESC]> { let dest = array_init::try_array_init(|_| self.alloc_slot())?; let mut inner = self.0.borrow_mut(); @@ -186,7 +192,7 @@ impl D3D12DescriptorHeap { inner.device.CopyDescriptorsSimple( 1, *dest[i].as_ref(), - *source[i].as_ref(), + *source[i], inner.desc.Type ); } diff --git a/librashader-runtime-d3d12/src/hello_triangle.rs b/librashader-runtime-d3d12/src/hello_triangle.rs index 079bd03..eea106b 100644 --- a/librashader-runtime-d3d12/src/hello_triangle.rs +++ b/librashader-runtime-d3d12/src/hello_triangle.rs @@ -310,6 +310,10 @@ pub mod d3d12_hello_triangle { })? }; + unsafe { + command_queue.SetName(w!("MainLoopQueue"))?; + } + let (width, height) = self.window_size(); let swap_chain_desc = DXGI_SWAP_CHAIN_DESC1 { diff --git a/librashader-runtime-d3d12/src/mipmap.rs b/librashader-runtime-d3d12/src/mipmap.rs index 98f604b..af53710 100644 --- a/librashader-runtime-d3d12/src/mipmap.rs +++ b/librashader-runtime-d3d12/src/mipmap.rs @@ -1,7 +1,13 @@ -use windows::Win32::Graphics::Direct3D12::{D3D12_COMPUTE_PIPELINE_STATE_DESC, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_RANGE, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT, D3D12_GPU_DESCRIPTOR_HANDLE, D3D12_ROOT_CONSTANTS, D3D12_ROOT_DESCRIPTOR_TABLE, D3D12_ROOT_PARAMETER, D3D12_ROOT_PARAMETER_0, D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, D3D12_ROOT_SIGNATURE_DESC, D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS, D3D12_SHADER_BYTECODE, D3D12_SHADER_VISIBILITY_ALL, D3D12_STATIC_SAMPLER_DESC, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature}; +use std::borrow::Borrow; +use std::mem::ManuallyDrop; +use windows::Win32::Graphics::Direct3D12::{D3D12_COMPUTE_PIPELINE_STATE_DESC, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_DESCRIPTOR_RANGE, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT, D3D12_GPU_DESCRIPTOR_HANDLE, D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_0, D3D12_RESOURCE_BARRIER_TYPE_UAV, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_UAV_BARRIER, D3D12_ROOT_CONSTANTS, D3D12_ROOT_DESCRIPTOR_TABLE, D3D12_ROOT_PARAMETER, D3D12_ROOT_PARAMETER_0, D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, D3D12_ROOT_SIGNATURE_DESC, D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS, D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS, D3D12_SHADER_BYTECODE, D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SHADER_VISIBILITY_ALL, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_STATIC_SAMPLER_DESC, D3D12_TEX2D_SRV, D3D12_TEX2D_UAV, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_UAV_DIMENSION_TEXTURE2D, D3D12_UNORDERED_ACCESS_VIEW_DESC, D3D12_UNORDERED_ACCESS_VIEW_DESC_0, ID3D12CommandList, ID3D12DescriptorHeap, ID3D12Device, ID3D12GraphicsCommandList, ID3D12PipelineState, ID3D12Resource, ID3D12RootSignature}; +use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT; use librashader_common::Size; -use crate::error; +use crate::{error, util}; +use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, ResourceWorkHeap}; use crate::util::d3d_compile_shader; +use bytemuck::{Zeroable, Pod}; +use librashader_runtime::scaling::MipmapSize; static GENERATE_MIPS_SRC: &[u8] = b" // Copyright (c) Microsoft Corporation. @@ -15,9 +21,9 @@ static GENERATE_MIPS_SRC: &[u8] = b" \" DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\ \" DENY_HULL_SHADER_ROOT_ACCESS |\" \\ \" DENY_PIXEL_SHADER_ROOT_ACCESS ),\" \\ +\"DescriptorTable ( SRV(t0, flags=DATA_VOLATILE) ),\" \\ +\"DescriptorTable ( UAV(u0, flags=DATA_VOLATILE) ),\" \\ \"RootConstants(num32BitConstants=3, b0),\" \\ -\"DescriptorTable ( SRV(t0) ),\" \\ -\"DescriptorTable ( UAV(u0) ),\" \\ \"StaticSampler(s0,\"\\ \" filter = FILTER_MIN_MAG_LINEAR_MIP_POINT,\"\\ \" addressU = TEXTURE_ADDRESS_CLAMP,\"\\ @@ -53,12 +59,51 @@ pub struct D3D12MipmapGen { pipeline: ID3D12PipelineState, } +#[derive(Copy, Clone, Zeroable, Pod)] +#[repr(C)] +struct MipConstants { + inv_out_texel_size: [f32; 2], + src_mip_index: u32, +} + +pub struct MipmapGenContext<'a> { + gen: &'a D3D12MipmapGen, + cmd: &'a ID3D12GraphicsCommandList, + heap: &'a mut D3D12DescriptorHeap, + residuals: Vec> +} + +impl <'a> MipmapGenContext<'a> { + fn new(gen: &'a D3D12MipmapGen, cmd: &'a ID3D12GraphicsCommandList, heap: &'a mut D3D12DescriptorHeap) -> MipmapGenContext<'a> { + Self { + gen, cmd, heap, residuals: Vec::new() + } + } + + /// Generate a set of mipmaps for the resource. + /// This is a "cheap" action and only dispatches a compute shader. + pub fn generate_mipmaps(&mut self, resource: &ID3D12Resource, miplevels: u16, size: Size, format: DXGI_FORMAT) + -> error::Result<()> + { + unsafe { + let residuals = self.gen.generate_mipmaps(self.cmd, resource, miplevels, size, format, self.heap)?; + self.residuals.extend(residuals) + } + + Ok(()) + } + + fn close(self) -> Vec> { + self.residuals + } +} + impl D3D12MipmapGen { pub fn new(device: &ID3D12Device) -> error::Result { unsafe { - let blob = d3d_compile_shader(GENERATE_MIPS_SRC, b"main\0", b"cs_5_1\0")?; + let blob = d3d_compile_shader(GENERATE_MIPS_SRC, b"main\0", b"cs_5_1\0").unwrap(); let blob = std::slice::from_raw_parts(blob.GetBufferPointer().cast(), blob.GetBufferSize()); - let root_signature: ID3D12RootSignature = device.CreateRootSignature(0, blob)?; + let root_signature: ID3D12RootSignature = device.CreateRootSignature(0, blob).unwrap(); let desc = D3D12_COMPUTE_PIPELINE_STATE_DESC { pRootSignature: windows::core::ManuallyDrop::new(&root_signature), @@ -78,13 +123,139 @@ impl D3D12MipmapGen { pipeline, }) } - - } - pub fn generate_mipmaps(miplevels: u16, - size: Size, - handle: D3D12_CPU_DESCRIPTOR_HANDLE) { + /// Enters a mipmapping compute context. + /// This is a relatively expensive operation + /// and should only be done at most a few times per frame. + pub fn mipmapping_context(&self, cmd: &ID3D12GraphicsCommandList, work_heap: &mut D3D12DescriptorHeap, mut f: F) + -> error::Result>> + where + F: FnMut(&mut MipmapGenContext) + { + let heap: ID3D12DescriptorHeap = (&(*work_heap)).into(); + unsafe { + cmd.SetComputeRootSignature(&self.root_signature); + cmd.SetPipelineState(&self.pipeline); + cmd.SetDescriptorHeaps(&[heap]); + } + let mut context = MipmapGenContext::new(&self, cmd, work_heap); + f(&mut context); + Ok(context.close()) + } + + /// SAFETY: + /// - handle must be a CPU handle to an SRV + /// - work_heap must have enough descriptors to fit all miplevels. + unsafe fn generate_mipmaps(&self, + cmd: &ID3D12GraphicsCommandList, + resource: &ID3D12Resource, + + miplevels: u16, + size: Size, + format: DXGI_FORMAT, + work_heap: &mut D3D12DescriptorHeap) -> error::Result>> + { + // create views for mipmap generation + let srv = work_heap.alloc_slot()?; + { + let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC { + Format: 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: miplevels as u32, + ..Default::default() + }, + }, + }; + + self.device.CreateShaderResourceView(resource, + Some(&srv_desc), *srv.as_ref()); + } + + let mut heap_slots = Vec::with_capacity(miplevels as usize); + heap_slots.push(srv); + + for i in 1..miplevels { + let descriptor = work_heap.alloc_slot()?; + let desc = D3D12_UNORDERED_ACCESS_VIEW_DESC { + Format: format, + ViewDimension: D3D12_UAV_DIMENSION_TEXTURE2D, + Anonymous: D3D12_UNORDERED_ACCESS_VIEW_DESC_0 { + Texture2D: D3D12_TEX2D_UAV { + MipSlice: i as u32, + ..Default::default() + } + }, + }; + + self.device.CreateUnorderedAccessView(resource, None, + Some(&desc), *descriptor.as_ref() + ); + heap_slots.push(descriptor); + } + + cmd.SetComputeRootDescriptorTable(0, *heap_slots[0].as_ref()); + + for i in 1..miplevels as u32 { + let scaled = size.scale_mipmap(i); + let mipmap_params =MipConstants { + inv_out_texel_size: [ + 1.0 / scaled.width as f32, + 1.0 / scaled.height as f32 + ], + src_mip_index: (i - 1), + }; + + let mipmap_params = bytemuck::bytes_of(&mipmap_params); + + + util::d3d12_resource_transition_subresource(cmd, resource, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + i - 1 + ); + + util::d3d12_resource_transition_subresource(cmd, resource, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + i + ); + + cmd.SetComputeRootDescriptorTable(1, *heap_slots[i as usize].as_ref()); + cmd.SetComputeRoot32BitConstants(2, + (std::mem::size_of::() / std::mem::size_of::()) as u32, + mipmap_params.as_ptr().cast(), + 0); + + cmd.Dispatch( std::cmp::max(scaled.width / 8, 1), std::cmp::max(scaled.height / 8, 1), 1); + + // todo: handle manuallyDrop properly. + + let uav_barrier = ManuallyDrop::new(D3D12_RESOURCE_UAV_BARRIER { + pResource: windows::core::ManuallyDrop::new(resource), + }); + + let barrier = [D3D12_RESOURCE_BARRIER { + Type: D3D12_RESOURCE_BARRIER_TYPE_UAV, + Anonymous: D3D12_RESOURCE_BARRIER_0 { + UAV: uav_barrier + }, + ..Default::default() + }]; + + cmd.ResourceBarrier(&barrier); + + util::d3d12_resource_transition_subresource(cmd, resource, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + i + ); + } + + Ok(heap_slots) } } \ No newline at end of file diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs index 0f62d8b..a600355 100644 --- a/librashader-runtime-d3d12/src/texture.rs +++ b/librashader-runtime-d3d12/src/texture.rs @@ -1,13 +1,14 @@ use std::mem::ManuallyDrop; use crate::error; use crate::error::assume_d3d12_init; -use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, LutTextureHeap}; +use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, LutTextureHeap, ResourceWorkHeap}; use crate::util::{d3d12_get_closest_format, d3d12_resource_transition, d3d12_update_subresources}; 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, D3D12_SUBRESOURCE_DATA, D3D12_RESOURCE_STATE_COPY_DEST}; +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, D3D12_SUBRESOURCE_DATA, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE}; use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; use librashader_runtime::scaling::MipmapSize; +use crate::mipmap::{D3D12MipmapGen, MipmapGenContext}; pub struct LutTexture { resource: ID3D12Resource, @@ -15,6 +16,7 @@ pub struct LutTexture { size: Size, filter: FilterMode, wrap_mode: WrapMode, + miplevels: Option, } impl LutTexture { @@ -28,13 +30,14 @@ impl LutTexture { mipmap: bool, ) -> error::Result<(LutTexture, ID3D12Resource)> { // todo: d3d12:800 + let miplevels = source.size.calculate_miplevels() as u16; 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: if mipmap { source.size.calculate_miplevels() as u16 } else { 1 }, + MipLevels: if mipmap { miplevels } else { 1 }, Format: ImageFormat::R8G8B8A8Unorm.into(), SampleDesc: DXGI_SAMPLE_DESC { Count: 1, @@ -44,12 +47,18 @@ impl LutTexture { Flags: Default::default(), }; - let format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT { + let mut format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT { Format: desc.Format, Support1: D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, ..Default::default() }; + if mipmap { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + format_support.Support1 |= D3D12_FORMAT_SUPPORT1_MIP; + format_support.Support2 |= D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE; + } + desc.Format = d3d12_get_closest_format(device, desc.Format, format_support); let descriptor = heap.alloc_slot()?; @@ -150,15 +159,23 @@ impl LutTexture { d3d12_resource_transition(cmd, &resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) } - - // todo: upload image data to textur - Ok((LutTexture { resource, descriptor, size: source.size, filter, wrap_mode, + miplevels: if mipmap { Some(miplevels) } else { None } }, upload)) } + + pub fn generate_mipmaps(&self, gen_mips: &mut MipmapGenContext) -> error::Result<()> { + if let Some(miplevels) = self.miplevels { + gen_mips.generate_mipmaps(&self.resource, + miplevels as u16, + self.size, ImageFormat::R8G8B8A8Unorm.into())? + } + + Ok(()) + } } diff --git a/librashader-runtime-d3d12/src/util.rs b/librashader-runtime-d3d12/src/util.rs index 3507b80..68e638d 100644 --- a/librashader-runtime-d3d12/src/util.rs +++ b/librashader-runtime-d3d12/src/util.rs @@ -140,10 +140,22 @@ pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error: } } +#[inline(always)] pub fn d3d12_resource_transition(cmd: &ID3D12GraphicsCommandList, resource: &ID3D12Resource, before: D3D12_RESOURCE_STATES, - after: D3D12_RESOURCE_STATES + after: D3D12_RESOURCE_STATES, +) { + d3d12_resource_transition_subresource(cmd, resource, before, after,D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); +} + + +#[inline(always)] +pub fn d3d12_resource_transition_subresource(cmd: &ID3D12GraphicsCommandList, + resource: &ID3D12Resource, + before: D3D12_RESOURCE_STATES, + after: D3D12_RESOURCE_STATES, + subresource: u32 ) { let barrier = [D3D12_RESOURCE_BARRIER { Type: D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, @@ -151,7 +163,7 @@ pub fn d3d12_resource_transition(cmd: &ID3D12GraphicsCommandList, Anonymous: D3D12_RESOURCE_BARRIER_0 { Transition: ManuallyDrop::new(D3D12_RESOURCE_TRANSITION_BARRIER { pResource: windows::core::ManuallyDrop::new(resource), - Subresource: D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + Subresource: subresource, StateBefore: before, StateAfter: after, })