d3d12: complete mipmapper
This commit is contained in:
parent
48e5a8a149
commit
53e3732a93
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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<LutTextureHeap>,
|
||||
textures: &[TextureConfig],
|
||||
mipmap_gen: &D3D12MipmapGen
|
||||
) -> error::Result<FxHashMap<usize, LutTexture>> {
|
||||
let mut work_heap: D3D12DescriptorHeap<ResourceWorkHeap> = 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 {
|
||||
|
|
|
@ -88,6 +88,12 @@ impl<T: D3D12ShaderVisibleHeapType> AsRef<D3D12_GPU_DESCRIPTOR_HANDLE>
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: D3D12ShaderVisibleHeapType> From<&D3D12DescriptorHeap<T>> for ID3D12DescriptorHeap {
|
||||
fn from(value: &D3D12DescriptorHeap<T>) -> Self {
|
||||
value.0.borrow().heap.clone()
|
||||
}
|
||||
}
|
||||
|
||||
struct D3D12DescriptorHeapInner {
|
||||
device: ID3D12Device,
|
||||
heap: ID3D12DescriptorHeap,
|
||||
|
@ -158,7 +164,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
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<T> D3D12DescriptorHeap<T> {
|
|||
}
|
||||
|
||||
pub fn copy_descriptors<const NUM_DESC: usize>(&mut self,
|
||||
source: &[impl AsRef<D3D12_CPU_DESCRIPTOR_HANDLE>; NUM_DESC])
|
||||
source: &[&D3D12_CPU_DESCRIPTOR_HANDLE; NUM_DESC])
|
||||
-> error::Result<[D3D12DescriptorHeapSlot<T>; NUM_DESC]> {
|
||||
let dest = array_init::try_array_init(|_| self.alloc_slot())?;
|
||||
let mut inner = self.0.borrow_mut();
|
||||
|
@ -186,7 +192,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
inner.device.CopyDescriptorsSimple(
|
||||
1,
|
||||
*dest[i].as_ref(),
|
||||
*source[i].as_ref(),
|
||||
*source[i],
|
||||
inner.desc.Type
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<ResourceWorkHeap>,
|
||||
residuals: Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>
|
||||
}
|
||||
|
||||
impl <'a> MipmapGenContext<'a> {
|
||||
fn new(gen: &'a D3D12MipmapGen, cmd: &'a ID3D12GraphicsCommandList, heap: &'a mut D3D12DescriptorHeap<ResourceWorkHeap>) -> 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<u32>, 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<D3D12DescriptorHeapSlot<ResourceWorkHeap>> {
|
||||
self.residuals
|
||||
}
|
||||
}
|
||||
|
||||
impl D3D12MipmapGen {
|
||||
pub fn new(device: &ID3D12Device) -> error::Result<D3D12MipmapGen> {
|
||||
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,
|
||||
/// 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<F>(&self, cmd: &ID3D12GraphicsCommandList, work_heap: &mut D3D12DescriptorHeap<ResourceWorkHeap>, mut f: F)
|
||||
-> error::Result<Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>>
|
||||
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<u32>,
|
||||
handle: D3D12_CPU_DESCRIPTOR_HANDLE) {
|
||||
format: DXGI_FORMAT,
|
||||
work_heap: &mut D3D12DescriptorHeap<ResourceWorkHeap>) -> error::Result<Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>>
|
||||
{
|
||||
// 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::<MipConstants>() / std::mem::size_of::<u32>()) 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)
|
||||
}
|
||||
}
|
|
@ -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<u32>,
|
||||
filter: FilterMode,
|
||||
wrap_mode: WrapMode,
|
||||
miplevels: Option<u16>,
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue