diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 79f030a..ed43c1f 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -74,13 +74,14 @@ impl FilterChainD3D12 { 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)?; - let texture = LutTexture::new( + let (texture, staging) = LutTexture::new( device, heap, &cmd, @@ -91,6 +92,7 @@ impl FilterChainD3D12 { false, )?; luts.insert(index, texture); + residuals.push(staging); } cmd.Close()?; @@ -106,6 +108,7 @@ impl FilterChainD3D12 { unsafe { WaitForSingleObject(fence_event, INFINITE) }; } + Ok(luts) } } diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs index d718710..8442a37 100644 --- a/librashader-runtime-d3d12/src/texture.rs +++ b/librashader-runtime-d3d12/src/texture.rs @@ -1,10 +1,11 @@ +use std::mem::ManuallyDrop; use crate::error; use crate::error::assume_d3d12_init; use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, LutTextureHeap}; -use crate::util::d3d12_get_closest_format; +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}; +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::Dxgi::Common::DXGI_SAMPLE_DESC; pub struct LutTexture { @@ -24,7 +25,7 @@ impl LutTexture { filter: FilterMode, wrap_mode: WrapMode, mipmap: bool, - ) -> error::Result { + ) -> error::Result<(LutTexture, ID3D12Resource)> { // todo: d3d12:800 let mut desc = D3D12_RESOURCE_DESC { Dimension: D3D12_RESOURCE_DIMENSION_TEXTURE2D, @@ -93,8 +94,8 @@ impl LutTexture { }; let mut layout = D3D12_PLACED_SUBRESOURCE_FOOTPRINT::default(); - let mut numrows = 0; - let mut rowsize = 0; + // let mut numrows = 0; + // let mut rowsize = 0; let mut total = 0; // texture upload unsafe { @@ -104,8 +105,7 @@ impl LutTexture { 1, 0, Some(&mut layout), - Some(&mut numrows), - Some(&mut rowsize), + None, None, Some(&mut total), ); @@ -137,27 +137,28 @@ impl LutTexture { assume_d3d12_init!(upload, "CreateCommittedResource"); unsafe { - let mut range = D3D12_RANGE { - Begin: 0, - End: 0 - }; + let subresource = [D3D12_SUBRESOURCE_DATA { + pData: source.bytes.as_ptr().cast(), + RowPitch: 4 * source.size.width as isize, + SlicePitch: (4 * source.size.width * source.size.height) as isize, + }]; - let mut buf = std::ptr::null_mut(); + d3d12_resource_transition(cmd, &resource, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST); - upload.Map(0, Some(&range), Some(&mut buf))?; - - upload.Unmap(0, None); + d3d12_update_subresources(cmd, &resource, + &upload, 0, 0, 1, &subresource)?; + d3d12_resource_transition(cmd, &resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) } // todo: upload image data to textur - Ok(LutTexture { + Ok((LutTexture { resource, descriptor, size: source.size, filter, wrap_mode, - }) + }, upload)) } } diff --git a/librashader-runtime-d3d12/src/util.rs b/librashader-runtime-d3d12/src/util.rs index 87ce95f..2c58fb0 100644 --- a/librashader-runtime-d3d12/src/util.rs +++ b/librashader-runtime-d3d12/src/util.rs @@ -1,13 +1,14 @@ +use std::mem::ManuallyDrop; +use std::u64; 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::Direct3D12::{ID3D12Device, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FEATURE_FORMAT_SUPPORT, ID3D12CommandList, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_RESOURCE_DESC, D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE, D3D12_RESOURCE_DESC1, D3D12_RESOURCE_BARRIER_0, D3D12_RESOURCE_TRANSITION_BARRIER, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATES, D3D12_PLACED_SUBRESOURCE_FOOTPRINT, D3D12_MEMCPY_DEST, D3D12_SUBRESOURCE_DATA, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, D3D12_TEXTURE_COPY_LOCATION_0, D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT}; use windows::Win32::Graphics::Dxgi::Common::*; +use crate::error::assume_d3d12_init; /// wtf retroarch? const DXGI_FORMAT_EX_A4R4G4B4_UNORM: DXGI_FORMAT = DXGI_FORMAT(1000); @@ -140,3 +141,187 @@ pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error: Ok(blob.unwrap()) } } + +pub fn d3d12_resource_transition(cmd: &ID3D12GraphicsCommandList, + resource: &ID3D12Resource, + before: D3D12_RESOURCE_STATES, + after: D3D12_RESOURCE_STATES +) { + let barrier = [D3D12_RESOURCE_BARRIER { + Type: D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + Flags: D3D12_RESOURCE_BARRIER_FLAG_NONE, + Anonymous: D3D12_RESOURCE_BARRIER_0 { + Transition: ManuallyDrop::new(D3D12_RESOURCE_TRANSITION_BARRIER { + pResource: windows::core::ManuallyDrop::new(resource), + Subresource: D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, + StateBefore: before, + StateAfter: after, + }) + }, + }]; + + unsafe { + cmd.ResourceBarrier(&barrier) + } +} + +pub fn d3d12_update_subresources(cmd: &ID3D12GraphicsCommandList, + destination_resource: &ID3D12Resource, + intermediate_resource: &ID3D12Resource, + intermediate_offset: u64, + first_subresouce: u32, + num_subresources: u32, + source: &[D3D12_SUBRESOURCE_DATA] +) -> error::Result { + + // let allocation_size = std::mem::size_of::() + // + std::mem::size_of::() + // + std::mem::size_of::() * num_subresources; + + unsafe { + let destination_desc = destination_resource.GetDesc(); + let mut device: Option = None; + destination_resource.GetDevice(&mut device)?; + assume_d3d12_init!(device, "GetDevice"); + + + let mut layouts = vec![D3D12_PLACED_SUBRESOURCE_FOOTPRINT::default(); num_subresources as usize]; + let mut num_rows = vec![0; num_subresources as usize]; + let mut row_sizes_in_bytes = vec![0; num_subresources as usize]; + let mut required_size = 0; + // texture upload + unsafe { + device.GetCopyableFootprints( + &destination_desc, + first_subresouce, + num_subresources, + intermediate_offset, + Some(layouts.as_mut_ptr()), + Some(num_rows.as_mut_ptr()), + Some(row_sizes_in_bytes.as_mut_ptr()), + Some(&mut required_size), + ); + } + + update_subresources( + cmd, + destination_resource, + intermediate_resource, + first_subresouce, + num_subresources, + required_size, + &layouts, + &num_rows, + &row_sizes_in_bytes, + source, + ) + } +} + +#[allow(clippy::too_many_arguments)] +fn update_subresources( + cmd: &ID3D12GraphicsCommandList, + destination_resource: &ID3D12Resource, + intermediate_resource: &ID3D12Resource, + first_subresouce: u32, + num_subresources: u32, + required_size: u64, + layouts: &[D3D12_PLACED_SUBRESOURCE_FOOTPRINT], + num_rows: &[u32], + row_sizes_in_bytes: &[u64], + source_data: &[D3D12_SUBRESOURCE_DATA], +) -> error::Result { + // ToDo: implement validation as in the original function + + + unsafe { + let mut data = std::ptr::null_mut(); + intermediate_resource.Map(0, None, Some(&mut data))?; + + for i in 0..num_subresources as usize { + let dest_data = D3D12_MEMCPY_DEST { + pData: data.offset(layouts[i].Offset as isize) + as *mut std::ffi::c_void, + RowPitch: layouts[i].Footprint.RowPitch as usize, + SlicePitch: ((layouts[i].Footprint.RowPitch) + * num_rows[i]) as usize, + }; + + memcpy_subresource( + &dest_data, + &source_data[i], + row_sizes_in_bytes[i], + num_rows[i], + layouts[i].Footprint.Depth, + ); + } + intermediate_resource.Unmap(0, None); + } + + unsafe { + let destination_desc = destination_resource.GetDesc(); + if destination_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER { + cmd.CopyBufferRegion( + destination_resource, + 0, + intermediate_resource, + layouts[0].Offset, + layouts[0].Footprint.Width as u64, + ); + } else { + for i in 0..num_subresources as usize { + + let dest_location = D3D12_TEXTURE_COPY_LOCATION { + pResource: windows::core::ManuallyDrop::new(destination_resource), + Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 { + SubresourceIndex: i as u32 + first_subresouce + }, + }; + + let source_location = D3D12_TEXTURE_COPY_LOCATION { + pResource: windows::core::ManuallyDrop::new(intermediate_resource), + Type: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 { + PlacedFootprint: layouts[i] + }, + }; + + cmd.CopyTextureRegion( + &dest_location, + 0, + 0, + 0, + &source_location, + None, + ); + } + } + Ok(required_size) + } + +} + +// this function should not leak to the public API, so +// there is no point in using struct wrappers +unsafe fn memcpy_subresource( + dest: &D3D12_MEMCPY_DEST, + src: &D3D12_SUBRESOURCE_DATA, + row_sizes_in_bytes: u64, + num_rows: u32, + num_slices: u32, +) { + for z in 0..num_slices as usize { + let dest_slice = + dest.pData.offset((dest.SlicePitch * z) as isize); + let src_slice = src.pData.offset((src.SlicePitch * z as isize) as isize); + + for y in 0..num_rows as usize { + std::ptr::copy_nonoverlapping( + src_slice.offset((src.RowPitch * y as isize) as isize), + dest_slice.offset((dest.RowPitch * y) as isize), + row_sizes_in_bytes as usize, + ); + } + } +}