d3d12: load lut texture data

This commit is contained in:
chyyran 2023-01-25 01:32:10 -05:00 committed by Ronny Chan
parent 9a3ce029d7
commit 56538dbfbf
3 changed files with 210 additions and 21 deletions

View file

@ -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)
}
}

View file

@ -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<LutTexture> {
) -> 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))
}
}

View file

@ -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<u64> {
// let allocation_size = std::mem::size_of::<D3D12_PLACED_SUBRESOURCE_FOOTPRINT>()
// + std::mem::size_of::<u32>()
// + std::mem::size_of::<u64>() * num_subresources;
unsafe {
let destination_desc = destination_resource.GetDesc();
let mut device: Option<ID3D12Device> = 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<u64> {
// 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,
);
}
}
}