d3d12: partially implement lut texture

This commit is contained in:
chyyran 2023-01-24 23:15:43 -05:00 committed by Ronny Chan
parent 2f82c5f430
commit 9a3ce029d7
7 changed files with 508 additions and 91 deletions

View file

@ -1,3 +1,16 @@
use std::error::Error;
pub type Result<T> = std::result::Result<T, Box<dyn Error>>;
// todo: make this return error
macro_rules! assume_d3d12_init {
($value:ident, $call:literal) => {
let $value = $value.expect($call);
};
(mut $value:ident, $call:literal) => {
let mut $value = $value.expect($call);
};
}
/// Macro for unwrapping result of a D3D function.
pub(crate) use assume_d3d12_init;

View file

@ -1,14 +1,23 @@
use std::error::Error;
use std::path::Path;
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D12::ID3D12Device;
use crate::error;
use crate::heap::{D3D12DescriptorHeap, LutTextureHeap};
use crate::samplers::SamplerSet;
use crate::texture::LutTexture;
use librashader_presets::{ShaderPreset, TextureConfig};
use librashader_reflect::back::targets::HLSL;
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::presets::CompilePresetTarget;
use crate::error;
use crate::samplers::SamplerSet;
use crate::texture::LutTexture;
use librashader_runtime::image::{Image, UVDirection};
use rustc_hash::FxHashMap;
use std::error::Error;
use std::path::Path;
use windows::core::Interface;
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::WindowsProgramming::INFINITE;
pub struct FilterChainD3D12 {
pub(crate) common: FilterCommon,
@ -28,6 +37,8 @@ pub(crate) struct FilterCommon {
// pub history_textures: Box<[Option<InputTexture>]>,
// pub config: FilterMutable,
// pub disable_mipmaps: bool,
lut_heap: D3D12DescriptorHeap<LutTextureHeap>,
luts: FxHashMap<usize, LutTexture>,
}
impl FilterChainD3D12 {
@ -44,9 +55,59 @@ impl FilterChainD3D12 {
fn load_luts(
device: &ID3D12Device,
heap: &mut D3D12DescriptorHeap<LutTextureHeap>,
textures: &[TextureConfig],
) -> error::Result<FxHashMap<usize, LutTexture>> {
todo!()
unsafe {
// 1 time queue infrastructure for lut uploads
let command_pool: ID3D12CommandAllocator =
device.CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT)?;
let cmd: ID3D12GraphicsCommandList =
device.CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, &command_pool, None)?;
let queue: ID3D12CommandQueue =
device.CreateCommandQueue(&D3D12_COMMAND_QUEUE_DESC {
Type: D3D12_COMMAND_LIST_TYPE_DIRECT,
Priority: 0,
Flags: D3D12_COMMAND_QUEUE_FLAG_NONE,
NodeMask: 0,
})?;
let fence_event = unsafe { CreateEventA(None, false, false, None)? };
let fence: ID3D12Fence = device.CreateFence(0, D3D12_FENCE_FLAG_NONE)?;
let mut luts = FxHashMap::default();
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path, UVDirection::TopLeft)?;
let texture = LutTexture::new(
device,
heap,
&cmd,
&image,
texture.filter_mode,
texture.wrap_mode,
// todo: mipmaps
false,
)?;
luts.insert(index, texture);
}
cmd.Close()?;
queue.ExecuteCommandLists(&[cmd.cast()?]);
queue.Signal(&fence, 1)?;
// Wait until the previous frame is finished.
if unsafe { fence.GetCompletedValue() } < 1 {
unsafe { fence.SetEventOnCompletion(1, fence_event) }
.ok()
.unwrap();
unsafe { WaitForSingleObject(fence_event, INFINITE) };
}
Ok(luts)
}
}
/// Load a filter chain from a pre-parsed `ShaderPreset`.
@ -55,17 +116,23 @@ impl FilterChainD3D12 {
preset: ShaderPreset,
options: Option<&()>,
) -> error::Result<FilterChainD3D12> {
let (passes, semantics) = HLSL::compile_preset_passes::<
GlslangCompilation,
Box<dyn Error>,
>(preset.shaders, &preset.textures)?;
let (passes, semantics) = HLSL::compile_preset_passes::<GlslangCompilation, Box<dyn Error>>(
preset.shaders,
&preset.textures,
)?;
let samplers = SamplerSet::new(device)?;
let mut lut_heap = D3D12DescriptorHeap::new(device, preset.textures.len())?;
let luts = FilterChainD3D12::load_luts(device, &mut lut_heap, &preset.textures)?;
let samplers = SamplerSet::new(&device)?;
Ok(FilterChainD3D12 {
common: FilterCommon {
d3d12: device.clone(),
samplers,
lut_heap,
luts,
},
})
}
}
}

View file

@ -1,17 +1,28 @@
use crate::error;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_GPU_DESCRIPTOR_HANDLE, ID3D12DescriptorHeap, ID3D12Device};
use crate::error;
use windows::Win32::Graphics::Direct3D12::{
ID3D12DescriptorHeap, ID3D12Device, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC,
D3D12_DESCRIPTOR_HEAP_FLAG_NONE, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
D3D12_GPU_DESCRIPTOR_HANDLE,
};
#[const_trait]
pub trait D3D12HeapType {
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC;
}
pub struct SamplerHeap;
impl const D3D12HeapType for SamplerHeap
{
pub trait D3D12ShaderVisibleHeapType: D3D12HeapType {}
pub struct SamplerPaletteHeap;
pub struct LutTextureHeap;
impl D3D12ShaderVisibleHeapType for SamplerPaletteHeap {}
impl const D3D12HeapType for SamplerPaletteHeap {
// sampler palettes just get set directly
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC {
D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
@ -22,12 +33,24 @@ impl const D3D12HeapType for SamplerHeap
}
}
impl const D3D12HeapType for LutTextureHeap {
// Lut texture heaps are CPU only and get bound to the descriptor heap of the shader.
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC {
D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
NumDescriptors: size as u32,
Flags: D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
NodeMask: 0,
}
}
}
pub struct D3D12DescriptorHeapSlot<T> {
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_handle: D3D12_GPU_DESCRIPTOR_HANDLE,
gpu_handle: Option<D3D12_GPU_DESCRIPTOR_HANDLE>,
heap: Arc<RefCell<D3D12DescriptorHeapInner>>,
slot: usize,
_pd: PhantomData<T>
_pd: PhantomData<T>,
}
impl<T> D3D12DescriptorHeapSlot<T> {
@ -43,9 +66,11 @@ impl<T> AsRef<D3D12_CPU_DESCRIPTOR_HANDLE> for D3D12DescriptorHeapSlot<T> {
}
}
impl<T> AsRef<D3D12_GPU_DESCRIPTOR_HANDLE> for D3D12DescriptorHeapSlot<T> {
impl<T: D3D12ShaderVisibleHeapType> AsRef<D3D12_GPU_DESCRIPTOR_HANDLE>
for D3D12DescriptorHeapSlot<T>
{
fn as_ref(&self) -> &D3D12_GPU_DESCRIPTOR_HANDLE {
&self.gpu_handle
self.gpu_handle.as_ref().unwrap()
}
}
@ -53,7 +78,7 @@ struct D3D12DescriptorHeapInner {
heap: ID3D12DescriptorHeap,
desc: D3D12_DESCRIPTOR_HEAP_DESC,
cpu_start: D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_start: D3D12_GPU_DESCRIPTOR_HANDLE,
gpu_start: Option<D3D12_GPU_DESCRIPTOR_HANDLE>,
handle_size: usize,
start: usize,
// Bit flag representation of available handles in the heap.
@ -65,30 +90,40 @@ struct D3D12DescriptorHeapInner {
pub struct D3D12DescriptorHeap<T>(Arc<RefCell<D3D12DescriptorHeapInner>>, PhantomData<T>);
impl<T:D3D12HeapType> D3D12DescriptorHeap<T> {
impl<T: D3D12HeapType> D3D12DescriptorHeap<T> {
pub fn new(device: &ID3D12Device, size: usize) -> error::Result<D3D12DescriptorHeap<T>> {
let desc = T::get_desc(size);
unsafe {
D3D12DescriptorHeap::new_with_desc(device, desc)
}
unsafe { D3D12DescriptorHeap::new_with_desc(device, desc) }
}
}
impl<T> D3D12DescriptorHeap<T> {
pub unsafe fn new_with_desc(device: &ID3D12Device, desc: D3D12_DESCRIPTOR_HEAP_DESC) -> error::Result<D3D12DescriptorHeap<T>> {
pub unsafe fn new_with_desc(
device: &ID3D12Device,
desc: D3D12_DESCRIPTOR_HEAP_DESC,
) -> error::Result<D3D12DescriptorHeap<T>> {
unsafe {
let heap: ID3D12DescriptorHeap = device.CreateDescriptorHeap(&desc)?;
let cpu_start = heap.GetCPUDescriptorHandleForHeapStart();
let gpu_start = heap.GetGPUDescriptorHandleForHeapStart();
Ok(D3D12DescriptorHeap(Arc::new(RefCell::new(D3D12DescriptorHeapInner {
heap,
desc,
cpu_start,
gpu_start,
handle_size: device.GetDescriptorHandleIncrementSize(desc.Type) as usize,
start: 0,
map: vec![false; desc.NumDescriptors as usize].into_boxed_slice(),
})), PhantomData::default()))
let gpu_start = if (desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE).0 != 0 {
Some(heap.GetGPUDescriptorHandleForHeapStart())
} else {
None
};
Ok(D3D12DescriptorHeap(
Arc::new(RefCell::new(D3D12DescriptorHeapInner {
heap,
desc,
cpu_start,
gpu_start,
handle_size: device.GetDescriptorHandleIncrementSize(desc.Type) as usize,
start: 0,
map: vec![false; desc.NumDescriptors as usize].into_boxed_slice(),
})),
PhantomData::default(),
))
}
}
@ -102,9 +137,12 @@ impl<T> D3D12DescriptorHeap<T> {
handle.ptr = inner.cpu_start.ptr + (i * inner.handle_size);
inner.start = i + 1;
let gpu_handle = D3D12_GPU_DESCRIPTOR_HANDLE {
ptr: (handle.ptr as u64 - inner.cpu_start.ptr as u64 + inner.gpu_start.ptr),
};
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),
});
return Ok(D3D12DescriptorHeapSlot {
cpu_handle: handle,
slot: i,

View file

@ -32,8 +32,8 @@ use std::path::Path;
pub trait DXSample {
fn new(filter: impl AsRef<Path>, command_line: &SampleCommandLine) -> Result<Self>
where
Self: Sized;
where
Self: Sized;
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>;
@ -69,8 +69,8 @@ fn build_command_line() -> SampleCommandLine {
}
fn run_sample<S>(mut sample: S) -> Result<()>
where
S: DXSample,
where
S: DXSample,
{
let instance = unsafe { GetModuleHandleA(None)? };
@ -214,7 +214,7 @@ fn get_hardware_adapter(factory: &IDXGIFactory4) -> Result<IDXGIAdapter1> {
std::ptr::null_mut::<Option<ID3D12Device>>(),
)
}
.is_ok()
.is_ok()
{
return Ok(adapter);
}
@ -223,18 +223,23 @@ fn get_hardware_adapter(factory: &IDXGIFactory4) -> Result<IDXGIAdapter1> {
unreachable!()
}
unsafe extern "system" fn debug_log(category: D3D12_MESSAGE_CATEGORY, severity: D3D12_MESSAGE_SEVERITY, id: D3D12_MESSAGE_ID, pdescription: ::windows::core::PCSTR, pcontext: *mut ::core::ffi::c_void) {
unsafe extern "system" fn debug_log(
category: D3D12_MESSAGE_CATEGORY,
severity: D3D12_MESSAGE_SEVERITY,
id: D3D12_MESSAGE_ID,
pdescription: ::windows::core::PCSTR,
pcontext: *mut ::core::ffi::c_void,
) {
unsafe {
let desc = CStr::from_ptr(pdescription.as_ptr().cast());
eprintln!("[{severity:?}-{category:?}] {desc:?}")
}
}
pub mod d3d12_hello_triangle {
use std::path::Path;
use crate::filter_chain::FilterChainD3D12;
use super::*;
use crate::filter_chain::FilterChainD3D12;
use std::path::Path;
const FRAME_COUNT: u32 = 2;
@ -274,10 +279,17 @@ pub mod d3d12_hello_triangle {
fn new(filter: impl AsRef<Path>, command_line: &SampleCommandLine) -> Result<Self> {
let (dxgi_factory, device) = create_device(command_line)?;
//
// let queue = device.cast::<ID3D12InfoQueue1>()?;
// unsafe {
// queue.RegisterMessageCallback(Some(debug_log), D3D12_MESSAGE_CALLBACK_FLAG_NONE, std::ptr::null_mut(), &mut 0).expect("could not register message callback");
// }
let queue = device.cast::<ID3D12InfoQueue1>()?;
unsafe {
queue
.RegisterMessageCallback(
Some(debug_log),
D3D12_MESSAGE_CALLBACK_FLAG_NONE,
std::ptr::null_mut(),
&mut 0,
)
.expect("could not register message callback");
}
let filter = FilterChainD3D12::load_from_path(&device, filter, None).unwrap();
Ok(Sample {
@ -321,7 +333,7 @@ pub mod d3d12_hello_triangle {
None,
)?
}
.cast()?;
.cast()?;
// This sample does not support fullscreen transitions
unsafe {
@ -496,11 +508,7 @@ pub mod d3d12_hello_triangle {
// Record commands.
unsafe {
// TODO: workaround for https://github.com/microsoft/win32metadata/issues/1006
command_list.ClearRenderTargetView(
rtv_handle,
&*[0.3, 0.4, 0.6, 1.0].as_ptr(),
&[],
);
command_list.ClearRenderTargetView(rtv_handle, &*[0.3, 0.4, 0.6, 1.0].as_ptr(), &[]);
command_list.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
command_list.IASetVertexBuffers(0, Some(&[resources.vbv]));
command_list.DrawInstanced(3, 1, 0, 0);
@ -536,14 +544,13 @@ pub mod d3d12_hello_triangle {
}
fn create_device(command_line: &SampleCommandLine) -> Result<(IDXGIFactory4, ID3D12Device)> {
// unsafe {
// let mut debug: Option<ID3D12Debug> = None;
// if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(debug) {
// eprintln!("enabling debug");
// debug.EnableDebugLayer();
// }
// }
unsafe {
let mut debug: Option<ID3D12Debug> = None;
if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(debug) {
eprintln!("enabling debug");
debug.EnableDebugLayer();
}
}
let dxgi_factory_flags = DXGI_CREATE_FACTORY_DEBUG;
@ -571,7 +578,7 @@ pub mod d3d12_hello_triangle {
let signature = unsafe {
D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &mut signature, None)
}
.map(|()| signature.unwrap())?;
.map(|()| signature.unwrap())?;
unsafe {
device.CreateRootSignature(
@ -609,7 +616,7 @@ pub mod d3d12_hello_triangle {
device: &ID3D12Device,
root_signature: &ID3D12RootSignature,
) -> Result<ID3D12PipelineState> {
let compile_flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
let compile_flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
let vertex_shader = compile_shader(SHADER, b"VSMain\0", b"vs_5_0\0")?;
let pixel_shader = compile_shader(SHADER, b"PSMain\0", b"ps_5_0\0")?;
@ -791,8 +798,8 @@ pub mod d3d12_hello_triangle {
.fence
.SetEventOnCompletion(fence, resources.fence_event)
}
.ok()
.unwrap();
.ok()
.unwrap();
unsafe { WaitForSingleObject(resources.fence_event, INFINITE) };
}
@ -801,7 +808,6 @@ pub mod d3d12_hello_triangle {
}
}
pub fn main<S: DXSample>(sample: S) -> Result<()> {
run_sample(sample)?;

View file

@ -1,20 +1,26 @@
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D12::{D3D12_COMPARISON_FUNC_NEVER, D3D12_FLOAT32_MAX, D3D12_SAMPLER_DESC, D3D12_TEXTURE_ADDRESS_MODE, ID3D12Device};
use librashader_common::{FilterMode, WrapMode};
use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, SamplerHeap};
use crate::error;
use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, SamplerPaletteHeap};
use librashader_common::{FilterMode, WrapMode};
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, D3D12_COMPARISON_FUNC_NEVER, D3D12_FLOAT32_MAX, D3D12_SAMPLER_DESC,
D3D12_TEXTURE_ADDRESS_MODE,
};
pub struct SamplerSet {
samplers: FxHashMap<(WrapMode, FilterMode), D3D12DescriptorHeapSlot<SamplerHeap>>,
heap: D3D12DescriptorHeap<SamplerHeap>
samplers: FxHashMap<(WrapMode, FilterMode), D3D12DescriptorHeapSlot<SamplerPaletteHeap>>,
heap: D3D12DescriptorHeap<SamplerPaletteHeap>,
}
impl SamplerSet {
pub fn get(&self, wrap: WrapMode, filter: FilterMode) -> &D3D12DescriptorHeapSlot<SamplerHeap> {
pub fn get(
&self,
wrap: WrapMode,
filter: FilterMode,
) -> &D3D12DescriptorHeapSlot<SamplerPaletteHeap> {
self.samplers.get(&(wrap, filter)).unwrap()
}
pub fn new(device: &ID3D12Device) -> error::Result<SamplerSet> {
let mut samplers = FxHashMap::default();
let wrap_modes = &[
WrapMode::ClampToBorder,
@ -23,7 +29,7 @@ impl SamplerSet {
WrapMode::MirroredRepeat,
];
let mut heap = D3D12DescriptorHeap::new(&device, (2 * wrap_modes.len()))?;
let mut heap = D3D12DescriptorHeap::new(&device, 2 * wrap_modes.len())?;
for wrap_mode in wrap_modes {
unsafe {
@ -58,7 +64,7 @@ impl SamplerSet {
MinLOD: -D3D12_FLOAT32_MAX,
MaxLOD: D3D12_FLOAT32_MAX,
},
*nearest.as_ref()
*nearest.as_ref(),
);
samplers.insert((*wrap_mode, FilterMode::Linear), linear);

View file

@ -1,20 +1,165 @@
use windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_DESC, ID3D12Device, ID3D12Resource};
use librashader_common::{FilterMode, WrapMode};
use crate::error;
use crate::error::assume_d3d12_init;
use crate::heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot, LutTextureHeap};
use crate::util::d3d12_get_closest_format;
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::Dxgi::Common::DXGI_SAMPLE_DESC;
pub struct LutTexture {
handle: ID3D12Resource,
resource: ID3D12Resource,
descriptor: D3D12DescriptorHeapSlot<LutTextureHeap>,
size: Size<u32>,
filter: FilterMode,
wrap_mode: WrapMode,
}
impl LutTexture {
pub fn new(
device: &ID3D12Device,
heap: &mut D3D12DescriptorHeap<LutTextureHeap>,
cmd: &ID3D12GraphicsCommandList,
source: &Image,
desc: D3D12_RESOURCE_DESC,
filter: FilterMode,
wrap_mode: WrapMode,
) {
mipmap: bool,
) -> error::Result<LutTexture> {
// todo: d3d12:800
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: 1, // todo: mipmaps
// MipLevels: if mipmap { u16::MAX } else { 1 },
Format: ImageFormat::R8G8B8A8Unorm.into(),
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
Layout: Default::default(),
Flags: Default::default(),
};
let format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: desc.Format,
Support1: D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE,
..Default::default()
};
desc.Format = d3d12_get_closest_format(device, desc.Format, format_support);
let descriptor = heap.alloc_slot()?;
// create handles on GPU
let mut resource: Option<ID3D12Resource> = None;
unsafe {
device.CreateCommittedResource(
&D3D12_HEAP_PROPERTIES {
Type: D3D12_HEAP_TYPE_DEFAULT,
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
CreationNodeMask: 1,
VisibleNodeMask: 1,
},
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
None,
&mut resource,
)?;
}
assume_d3d12_init!(resource, "CreateCommittedResource");
unsafe {
let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC {
Format: desc.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: desc.MipLevels as u32,
..Default::default()
},
},
};
device.CreateShaderResourceView(&resource, Some(&srv_desc), *descriptor.as_ref());
}
let mut buffer_desc = D3D12_RESOURCE_DESC {
Dimension: D3D12_RESOURCE_DIMENSION_BUFFER,
..Default::default()
};
let mut layout = D3D12_PLACED_SUBRESOURCE_FOOTPRINT::default();
let mut numrows = 0;
let mut rowsize = 0;
let mut total = 0;
// texture upload
unsafe {
device.GetCopyableFootprints(
&desc,
0,
1,
0,
Some(&mut layout),
Some(&mut numrows),
Some(&mut rowsize),
Some(&mut total),
);
buffer_desc.Width = total;
buffer_desc.Height = 1;
buffer_desc.DepthOrArraySize = 1;
buffer_desc.MipLevels = 1;
buffer_desc.SampleDesc.Count = 1;
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
}
let mut upload: Option<ID3D12Resource> = None;
unsafe {
device.CreateCommittedResource(
&D3D12_HEAP_PROPERTIES {
Type: D3D12_HEAP_TYPE_UPLOAD,
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
CreationNodeMask: 1,
VisibleNodeMask: 1,
},
D3D12_HEAP_FLAG_NONE,
&buffer_desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
None,
&mut upload,
)?;
}
assume_d3d12_init!(upload, "CreateCommittedResource");
unsafe {
let mut range = D3D12_RANGE {
Begin: 0,
End: 0
};
let mut buf = std::ptr::null_mut();
upload.Map(0, Some(&range), Some(&mut buf))?;
upload.Unmap(0, None);
}
// todo: upload image data to textur
Ok(LutTexture {
resource,
descriptor,
size: source.size,
filter,
wrap_mode,
})
}
}
}
// todo https://github.com/microsoft/DirectX-Graphics-Samples/blob/master/Libraries/D3D12RaytracingFallback/Include/d3dx12.h#L1893

View file

@ -0,0 +1,142 @@
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::Dxgi::Common::*;
/// wtf retroarch?
const DXGI_FORMAT_EX_A4R4G4B4_UNORM: DXGI_FORMAT = DXGI_FORMAT(1000);
const fn d3d12_format_fallback_list(format: DXGI_FORMAT) -> Option<&'static [DXGI_FORMAT]> {
match format {
DXGI_FORMAT_R32G32B32A32_FLOAT => Some(&[
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R11G11B10_FLOAT,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R16G16B16A16_FLOAT => Some(&[
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R11G11B10_FLOAT,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R8G8B8A8_UNORM => Some(&[
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => Some(&[
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_B8G8R8A8_UNORM => Some(&[
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_B8G8R8X8_UNORM => Some(&[
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_B5G6R5_UNORM => Some(&[
DXGI_FORMAT_B5G6R5_UNORM,
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_EX_A4R4G4B4_UNORM | DXGI_FORMAT_B4G4R4A4_UNORM => Some(&[
DXGI_FORMAT_B4G4R4A4_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_A8_UNORM => Some(&[
DXGI_FORMAT_A8_UNORM,
DXGI_FORMAT_R8_UNORM,
DXGI_FORMAT_R8G8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R8_UNORM => Some(&[
DXGI_FORMAT_R8_UNORM,
DXGI_FORMAT_A8_UNORM,
DXGI_FORMAT_R8G8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
_ => None,
}
}
pub fn d3d12_get_closest_format(
device: &ID3D12Device,
format: DXGI_FORMAT,
format_support: D3D12_FEATURE_DATA_FORMAT_SUPPORT,
) -> DXGI_FORMAT {
let default_list = [format, DXGI_FORMAT_UNKNOWN];
let format_support_list = d3d12_format_fallback_list(format).unwrap_or(&default_list);
for supported in format_support_list {
unsafe {
let mut support = D3D12_FEATURE_DATA_FORMAT_SUPPORT {
Format: format,
..Default::default()
};
if device
.CheckFeatureSupport(
D3D12_FEATURE_FORMAT_SUPPORT,
&mut support as *mut _ as *mut _,
std::mem::size_of::<D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as u32,
)
.is_ok()
&& (support.Support1 & format_support.Support1) == format_support.Support1
&& (support.Support2 & format_support.Support2) == format_support.Support2
{
return *supported;
}
}
}
DXGI_FORMAT_UNKNOWN
}
pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error::Result<ID3DBlob> {
unsafe {
let mut blob = None;
D3DCompile(
source.as_ptr().cast(),
source.len(),
None,
None,
None,
PCSTR(entry.as_ptr()),
PCSTR(version.as_ptr()),
if cfg!(feature = "debug-shader") {
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
} else {
0
},
0,
&mut blob,
None,
)?;
Ok(blob.unwrap())
}
}