d3d12: implement sampler palette

This commit is contained in:
chyyran 2023-01-24 02:02:27 -05:00 committed by Ronny Chan
parent 4dc34fceb2
commit 2f82c5f430
10 changed files with 299 additions and 105 deletions

1
Cargo.lock generated
View file

@ -746,6 +746,7 @@ name = "librashader-runtime-d3d12"
version = "0.1.0-beta.8"
dependencies = [
"array-init",
"bit-set",
"bytemuck",
"gfx-maths",
"librashader-common",

View file

@ -15,6 +15,7 @@ description = "RetroArch shaders for all."
default = []
opengl = ["gl"]
d3d11 = ["windows", "dxgi"]
d3d12 = ["windows", "dxgi"]
dxgi = ["windows"]
vulkan = ["ash"]
@ -32,4 +33,5 @@ features = [
"Win32_Graphics_Dxgi_Common",
"Win32_Graphics_Direct3D",
"Win32_Graphics_Direct3D11",
"Win32_Graphics_Direct3D12",
]

View file

@ -0,0 +1,22 @@
use crate::{FilterMode, WrapMode};
use windows::Win32::Graphics::Direct3D12;
impl From<WrapMode> for Direct3D12::D3D12_TEXTURE_ADDRESS_MODE {
fn from(value: WrapMode) -> Self {
match value {
WrapMode::ClampToBorder => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_BORDER,
WrapMode::ClampToEdge => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
WrapMode::Repeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_WRAP,
WrapMode::MirroredRepeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
}
}
}
impl From<FilterMode> for Direct3D12::D3D12_FILTER {
fn from(value: FilterMode) -> Self {
match value {
FilterMode::Linear => Direct3D12::D3D12_FILTER_MIN_MAG_MIP_LINEAR,
_ => Direct3D12::D3D12_FILTER_MIN_MAG_MIP_POINT,
}
}
}

View file

@ -16,6 +16,10 @@ pub mod dxgi;
#[cfg(all(target_os = "windows", feature = "d3d11"))]
pub mod d3d11;
/// Direct3D 12 common conversions.
#[cfg(all(target_os = "windows", feature = "d3d12"))]
pub mod d3d12;
mod viewport;
pub use viewport::Viewport;

View file

@ -1,77 +0,0 @@
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC, D3D12_GPU_DESCRIPTOR_HANDLE, ID3D12DescriptorHeap, ID3D12Device};
use crate::error;
pub struct D3D12DescriptorHeapSlot {
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
heap: Arc<D3D12DescriptorHeap>
}
pub struct D3D12DescriptorHeap {
heap: ID3D12DescriptorHeap,
desc: D3D12_DESCRIPTOR_HEAP_DESC,
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_handle: D3D12_GPU_DESCRIPTOR_HANDLE,
alignment: u32,
map: Box<[bool]>,
start: usize
}
impl D3D12DescriptorHeap {
pub fn new(device: &ID3D12Device, desc: D3D12_DESCRIPTOR_HEAP_DESC) -> error::Result<Arc<D3D12DescriptorHeap>> {
unsafe {
let heap: ID3D12DescriptorHeap = device.CreateDescriptorHeap(&desc)?;
let cpu_handle = heap.GetCPUDescriptorHandleForHeapStart();
let gpu_handle = heap.GetGPUDescriptorHandleForHeapStart();
let alignment = device.GetDescriptorHandleIncrementSize(desc.Type);
let mut map = Vec::new();
map.resize(desc.NumDescriptors as usize, false);
Ok(Arc::new(D3D12DescriptorHeap {
heap,
desc,
cpu_handle,
gpu_handle,
alignment,
map: Box::new([]),
start: 0,
}))
}
}
pub fn allocate_slot(self: &Arc<D3D12DescriptorHeap>) -> error::Result<D3D12DescriptorHeapSlot> {
let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 };
for i in self.start..self.desc.NumDescriptors as usize {
if !self.map[i] {
self.map[i] = true;
handle.ptr = self.cpu_handle.ptr + (i * self.alignment) as u64;
self.start = i + 1;
return Ok(D3D12DescriptorHeapSlot {
cpu_handle: handle,
heap: Arc::clone(self),
});
}
}
todo!("error need to fail");
}
pub fn free_slot(&mut self) -> error::Result<D3D12_CPU_DESCRIPTOR_HANDLE> {
let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 };
for i in self.start..self.desc.NumDescriptors as usize {
if !self.map[i] {
self.map[i] = true;
handle.ptr = self.cpu_handle.ptr + (i * self.alignment) as u64;
self.start = i + 1;
return Ok(handle);
}
}
todo!("error need to fail");
}
}
impl Drop

View file

@ -2,11 +2,13 @@ use std::error::Error;
use std::path::Path;
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D12::ID3D12Device;
use librashader_presets::ShaderPreset;
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;
pub struct FilterChainD3D12 {
pub(crate) common: FilterCommon,
@ -20,7 +22,7 @@ pub struct FilterChainD3D12 {
pub(crate) struct FilterCommon {
pub(crate) d3d12: ID3D12Device,
// pub(crate) luts: FxHashMap<usize, LutTexture>,
// pub samplers: SamplerSet,
pub samplers: SamplerSet,
// pub output_textures: Box<[Option<InputTexture>]>,
// pub feedback_textures: Box<[Option<InputTexture>]>,
// pub history_textures: Box<[Option<InputTexture>]>,
@ -31,16 +33,25 @@ pub(crate) struct FilterCommon {
impl FilterChainD3D12 {
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(
device: &ID3D12Device,
path: impl AsRef<Path>,
options: Option<&()>,
) -> error::Result<FilterChainD3D12> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset, options)
Self::load_from_preset(device, preset, options)
}
fn load_luts(
device: &ID3D12Device,
textures: &[TextureConfig],
) -> error::Result<FxHashMap<usize, LutTexture>> {
todo!()
}
/// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(
device: &ID3D12Device,
preset: ShaderPreset,
options: Option<&()>,
) -> error::Result<FilterChainD3D12> {
@ -49,7 +60,12 @@ impl FilterChainD3D12 {
Box<dyn Error>,
>(preset.shaders, &preset.textures)?;
todo!()
let samplers = SamplerSet::new(&device)?;
Ok(FilterChainD3D12 {
common: FilterCommon {
d3d12: device.clone(),
samplers,
},
})
}
}

View file

@ -0,0 +1,130 @@
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;
#[const_trait]
pub trait D3D12HeapType {
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC;
}
pub struct SamplerHeap;
impl const D3D12HeapType for SamplerHeap
{
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC {
D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
NumDescriptors: size as u32,
Flags: D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
NodeMask: 0,
}
}
}
pub struct D3D12DescriptorHeapSlot<T> {
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_handle: D3D12_GPU_DESCRIPTOR_HANDLE,
heap: Arc<RefCell<D3D12DescriptorHeapInner>>,
slot: usize,
_pd: PhantomData<T>
}
impl<T> D3D12DescriptorHeapSlot<T> {
/// Get the index of the resource within the heap.
pub fn index(&self) -> usize {
self.slot
}
}
impl<T> AsRef<D3D12_CPU_DESCRIPTOR_HANDLE> for D3D12DescriptorHeapSlot<T> {
fn as_ref(&self) -> &D3D12_CPU_DESCRIPTOR_HANDLE {
&self.cpu_handle
}
}
impl<T> AsRef<D3D12_GPU_DESCRIPTOR_HANDLE> for D3D12DescriptorHeapSlot<T> {
fn as_ref(&self) -> &D3D12_GPU_DESCRIPTOR_HANDLE {
&self.gpu_handle
}
}
struct D3D12DescriptorHeapInner {
heap: ID3D12DescriptorHeap,
desc: D3D12_DESCRIPTOR_HEAP_DESC,
cpu_start: D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_start: D3D12_GPU_DESCRIPTOR_HANDLE,
handle_size: usize,
start: usize,
// Bit flag representation of available handles in the heap.
//
// 0 - Occupied
// 1 - free
map: Box<[bool]>,
}
pub struct D3D12DescriptorHeap<T>(Arc<RefCell<D3D12DescriptorHeapInner>>, PhantomData<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)
}
}
}
impl<T> 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()))
}
}
pub fn alloc_slot(&mut self) -> error::Result<D3D12DescriptorHeapSlot<T>> {
let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 };
let mut inner = self.0.borrow_mut();
for i in inner.start..inner.desc.NumDescriptors as usize {
if !inner.map[i] {
inner.map[i] = true;
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),
};
return Ok(D3D12DescriptorHeapSlot {
cpu_handle: handle,
slot: i,
heap: Arc::clone(&self.0),
gpu_handle,
_pd: Default::default(),
});
}
}
todo!("error need to fail");
}
}
impl<T> Drop for D3D12DescriptorHeapSlot<T> {
fn drop(&mut self) {
let mut inner = self.heap.borrow_mut();
inner.map[self.slot] = false;
if inner.start > self.slot {
inner.start = self.slot
}
}
}

View file

@ -1,3 +1,4 @@
use std::ffi::CStr;
use windows::{
core::*, Win32::Foundation::*, Win32::Graphics::Direct3D::Fxc::*, Win32::Graphics::Direct3D::*,
Win32::Graphics::Direct3D12::*, Win32::Graphics::Dxgi::Common::*, Win32::Graphics::Dxgi::*,
@ -27,9 +28,10 @@ float4 PSMain(PSInput input) : SV_TARGET
}\0";
use std::mem::transmute;
use std::path::Path;
pub trait DXSample {
fn new(command_line: &SampleCommandLine) -> Result<Self>
fn new(filter: impl AsRef<Path>, command_line: &SampleCommandLine) -> Result<Self>
where
Self: Sized;
@ -221,7 +223,17 @@ 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 {
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::*;
const FRAME_COUNT: u32 = 2;
@ -230,6 +242,7 @@ pub mod d3d12_hello_triangle {
dxgi_factory: IDXGIFactory4,
device: ID3D12Device,
resources: Option<Resources>,
pub filter: FilterChainD3D12,
}
struct Resources {
@ -258,13 +271,20 @@ pub mod d3d12_hello_triangle {
}
impl DXSample for Sample {
fn new(command_line: &SampleCommandLine) -> Result<Self> {
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 filter = FilterChainD3D12::load_from_path(&device, filter, None).unwrap();
Ok(Sample {
dxgi_factory,
device,
resources: None,
filter,
})
}
@ -516,20 +536,16 @@ pub mod d3d12_hello_triangle {
}
fn create_device(command_line: &SampleCommandLine) -> Result<(IDXGIFactory4, ID3D12Device)> {
if cfg!(debug_assertions) {
unsafe {
let mut debug: Option<ID3D12Debug> = None;
if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(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 = if cfg!(debug_assertions) {
DXGI_CREATE_FACTORY_DEBUG
} else {
0
};
let dxgi_factory_flags = DXGI_CREATE_FACTORY_DEBUG;
let dxgi_factory: IDXGIFactory4 = unsafe { CreateDXGIFactory2(dxgi_factory_flags) }?;
@ -540,7 +556,7 @@ pub mod d3d12_hello_triangle {
}?;
let mut device: Option<ID3D12Device> = None;
unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_11_0, &mut device) }?;
unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_12_2, &mut device) }?;
Ok((dxgi_factory, device.unwrap()))
}
@ -593,11 +609,7 @@ pub mod d3d12_hello_triangle {
device: &ID3D12Device,
root_signature: &ID3D12RootSignature,
) -> Result<ID3D12PipelineState> {
let compile_flags = if cfg!(debug_assertions) {
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
} else {
0
};
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")?;

View file

@ -1,7 +1,71 @@
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE;
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;
pub struct SamplerSet {
samplers: FxHashMap<(WrapMode, FilterMode), D3D12_GPU_DESCRIPTOR_HANDLE>,
samplers: FxHashMap<(WrapMode, FilterMode), D3D12DescriptorHeapSlot<SamplerHeap>>,
heap: D3D12DescriptorHeap<SamplerHeap>
}
impl SamplerSet {
pub fn get(&self, wrap: WrapMode, filter: FilterMode) -> &D3D12DescriptorHeapSlot<SamplerHeap> {
self.samplers.get(&(wrap, filter)).unwrap()
}
pub fn new(device: &ID3D12Device) -> error::Result<SamplerSet> {
let mut samplers = FxHashMap::default();
let wrap_modes = &[
WrapMode::ClampToBorder,
WrapMode::ClampToEdge,
WrapMode::Repeat,
WrapMode::MirroredRepeat,
];
let mut heap = D3D12DescriptorHeap::new(&device, (2 * wrap_modes.len()))?;
for wrap_mode in wrap_modes {
unsafe {
let mut linear = heap.alloc_slot()?;
device.CreateSampler(
&D3D12_SAMPLER_DESC {
Filter: FilterMode::Linear.into(),
AddressU: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode),
AddressV: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode),
AddressW: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode),
MipLODBias: 0.0,
MaxAnisotropy: 1,
ComparisonFunc: D3D12_COMPARISON_FUNC_NEVER,
BorderColor: [0.0, 0.0, 0.0, 0.0],
MinLOD: -D3D12_FLOAT32_MAX,
MaxLOD: D3D12_FLOAT32_MAX,
},
*linear.as_ref(),
);
let mut nearest = heap.alloc_slot()?;
device.CreateSampler(
&D3D12_SAMPLER_DESC {
Filter: FilterMode::Nearest.into(),
AddressU: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode),
AddressV: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode),
AddressW: D3D12_TEXTURE_ADDRESS_MODE::from(*wrap_mode),
MipLODBias: 0.0,
MaxAnisotropy: 1,
ComparisonFunc: D3D12_COMPARISON_FUNC_NEVER,
BorderColor: [0.0, 0.0, 0.0, 0.0],
MinLOD: -D3D12_FLOAT32_MAX,
MaxLOD: D3D12_FLOAT32_MAX,
},
*nearest.as_ref()
);
samplers.insert((*wrap_mode, FilterMode::Linear), linear);
samplers.insert((*wrap_mode, FilterMode::Nearest), nearest);
}
}
Ok(SamplerSet { samplers, heap })
}
}

View file

@ -0,0 +1,20 @@
use windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_DESC, ID3D12Device, ID3D12Resource};
use librashader_common::{FilterMode, WrapMode};
use librashader_runtime::image::Image;
pub struct LutTexture {
handle: ID3D12Resource,
}
impl LutTexture {
pub fn new(
device: &ID3D12Device,
source: &Image,
desc: D3D12_RESOURCE_DESC,
filter: FilterMode,
wrap_mode: WrapMode,
) {
// todo: d3d12:800
}
}