d3d12: complete mipmapper

This commit is contained in:
chyyran 2023-01-28 01:38:55 -05:00 committed by Ronny Chan
parent 48e5a8a149
commit 53e3732a93
8 changed files with 286 additions and 29 deletions

14
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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 {

View file

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

View file

@ -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 {

View file

@ -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,
size: Size<u32>,
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<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>,
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)
}
}

View file

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

View file

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