d3d12: use hlsl as a fallback pipeline

This commit is contained in:
chyyran 2023-02-05 01:54:56 -05:00
parent d6ac2c665d
commit 72c9548c7a
4 changed files with 167 additions and 53 deletions

View file

@ -1,21 +1,22 @@
use std::collections::VecDeque;
use crate::{error, util};
use crate::{error, graphics_pipeline, util};
use crate::descriptor_heap::{D3D12DescriptorHeap, CpuStagingHeap, ResourceWorkHeap, SamplerWorkHeap, RenderTargetHeap};
use crate::samplers::SamplerSet;
use crate::luts::LutTexture;
use librashader_presets::{ShaderPreset, TextureConfig};
use librashader_reflect::back::targets::DXIL;
use librashader_reflect::back::targets::{DXIL, HLSL};
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_runtime::image::{Image, UVDirection};
use rustc_hash::FxHashMap;
use std::error::Error;
use std::path::Path;
use spirv_cross::hlsl::ShaderModel;
use windows::core::Interface;
use windows::w;
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::Graphics::Direct3D12::{ID3D12CommandAllocator, ID3D12CommandQueue, ID3D12Device, ID3D12Fence, ID3D12GraphicsCommandList, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE, ID3D12DescriptorHeap, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET};
use windows::Win32::Graphics::Direct3D::Dxc::{CLSID_DxcLibrary, CLSID_DxcValidator, DxcCreateInstance, IDxcLibrary, IDxcValidator};
use windows::Win32::Graphics::Direct3D::Dxc::{CLSID_DxcCompiler, CLSID_DxcLibrary, CLSID_DxcValidator, DxcCreateInstance, IDxcCompiler, IDxcLibrary, IDxcUtils, IDxcValidator};
use windows::Win32::System::Threading::{CreateEventA, ResetEvent, WaitForSingleObject};
use windows::Win32::System::WindowsProgramming::INFINITE;
use librashader_common::{ImageFormat, Size, Viewport};
@ -34,7 +35,8 @@ use crate::quad_render::DrawQuad;
use crate::render_target::RenderTarget;
use crate::texture::{InputTexture, OutputDescriptor, OutputTexture};
type ShaderPassMeta = ShaderPassArtifact<impl CompileReflectShader<DXIL, GlslangCompilation>>;
type DxilShaderPassMeta = ShaderPassArtifact<impl CompileReflectShader<DXIL, GlslangCompilation>>;
type HlslShaderPassMeta = ShaderPassArtifact<impl CompileReflectShader<HLSL, GlslangCompilation>>;
pub struct FilterMutable {
pub(crate) passes_enabled: usize,
@ -90,11 +92,19 @@ impl FilterChainD3D12 {
) -> error::Result<FilterChainD3D12> {
let shader_count = preset.shaders.len();
let lut_count = preset.textures.len();
let shader_copy = preset.shaders.clone();
let (passes, semantics) = DXIL::compile_preset_passes::<GlslangCompilation, Box<dyn Error>>(
preset.shaders,
&preset.textures,
).unwrap();
let (hlsl_passes, _) = HLSL::compile_preset_passes::<GlslangCompilation, Box<dyn Error>>(
shader_copy,
&preset.textures,
).unwrap();
let samplers = SamplerSet::new(device)?;
let mipmap_gen = D3D12MipmapGen::new(device).unwrap();
@ -115,7 +125,7 @@ impl FilterChainD3D12 {
let root_signature = D3D12RootSignature::new(device)?;
let (texture_heap, sampler_heap, filters)
= FilterChainD3D12::init_passes(device, &root_signature, passes, &semantics).unwrap();
= FilterChainD3D12::init_passes(device, &root_signature, passes, hlsl_passes, &semantics).unwrap();
@ -342,17 +352,22 @@ impl FilterChainD3D12 {
fn init_passes(device: &ID3D12Device,
root_signature: &D3D12RootSignature,
passes: Vec<ShaderPassMeta>,
passes: Vec<DxilShaderPassMeta>,
hlsl_passes: Vec<HlslShaderPassMeta>,
semantics: &ShaderSemantics,)
-> error::Result<(ID3D12DescriptorHeap, ID3D12DescriptorHeap, Vec<FilterPass>)> {
-> error::Result<(ID3D12DescriptorHeap, ID3D12DescriptorHeap, Vec<FilterPass>)> {
let validator: IDxcValidator = unsafe {
DxcCreateInstance(&CLSID_DxcValidator)?
};
let dxc: IDxcLibrary = unsafe {
let library: IDxcUtils = unsafe {
DxcCreateInstance(&CLSID_DxcLibrary)?
};
let compiler: IDxcCompiler = unsafe {
DxcCreateInstance(&CLSID_DxcCompiler)?
};
let mut filters = Vec::new();
let shader_count = passes.len();
let work_heap =
@ -372,32 +387,51 @@ impl FilterChainD3D12 {
sampler_work_heap.suballocate(MAX_BINDINGS_COUNT as usize)
};
for (index, (((config, source, mut reflect),
for (index, ((((config, source, mut dxil), (_, _, mut hlsl)),
mut texture_heap), mut sampler_heap))
in passes.into_iter()
.zip(hlsl_passes)
.zip(work_heaps)
.zip(sampler_work_heaps)
.enumerate() {
let reflection = reflect.reflect(index, semantics)?;
let dxil = reflect.compile(None)?;
let dxil_reflection = dxil.reflect(index, semantics)?;
let dxil = dxil.compile(Some(librashader_reflect::back::dxil::ShaderModel::ShaderModel6_0))?;
let hlsl_reflection = hlsl.reflect(index, semantics)?;
let hlsl = hlsl.compile(Some(ShaderModel::V6_0))?;
let render_format = if let Some(format) = config.get_format_override() {
format
} else if source.format != ImageFormat::Unknown {
source.format
} else {
ImageFormat::R8G8B8A8Unorm
}.into();
eprintln!("building pipeline for pass {:?}", index);
let graphics_pipeline = D3D12GraphicsPipeline::new(device,
&dxc,
&validator,
&dxil,
root_signature,
if let Some(format) = config.get_format_override() {
format
} else if source.format != ImageFormat::Unknown {
source.format
} else {
ImageFormat::R8G8B8A8Unorm
}.into(),
&source
)?;
/// incredibly cursed.
let (reflection, graphics_pipeline) = if let Ok(graphics_pipeline) =
D3D12GraphicsPipeline::new_from_dxil(device,
&library,
&validator,
&dxil,
root_signature,
render_format
) {
(dxil_reflection, graphics_pipeline)
} else {
let graphics_pipeline = D3D12GraphicsPipeline::new_from_hlsl(device,
&library,
&compiler,
&hlsl,
root_signature,
render_format
)?;
(hlsl_reflection, graphics_pipeline)
};
let uniform_storage = UniformStorage::new(
reflection

View file

@ -1,9 +1,12 @@
use windows::Win32::Foundation::BOOL;
use windows::Win32::Graphics::Direct3D12::{D3D12_BLEND_DESC, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_SRC_ALPHA, D3D12_COLOR_WRITE_ENABLE_ALL, D3D12_CULL_MODE_NONE, D3D12_DESCRIPTOR_RANGE, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, D3D12_FILL_MODE_SOLID, D3D12_GRAPHICS_PIPELINE_STATE_DESC, D3D12_INPUT_LAYOUT_DESC, D3D12_LOGIC_OP_NOOP, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, D3D12_RASTERIZER_DESC, D3D12_RENDER_TARGET_BLEND_DESC, D3D12_ROOT_DESCRIPTOR, D3D12_ROOT_DESCRIPTOR_TABLE, D3D12_ROOT_PARAMETER, D3D12_ROOT_PARAMETER_0, D3D12_ROOT_PARAMETER_TYPE_CBV, D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, D3D12_ROOT_SIGNATURE_DESC, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, D3D12_SHADER_BYTECODE, D3D12_SHADER_VISIBILITY_ALL, D3D12_SHADER_VISIBILITY_PIXEL, D3D12SerializeRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature};
use windows::Win32::Graphics::Direct3D::Dxc::{IDxcBlob, IDxcCompiler, IDxcLibrary, IDxcUtils, IDxcValidator};
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_UNKNOWN, DXGI_SAMPLE_DESC};
use librashader_reflect::back::cross::CrossHlslContext;
use librashader_reflect::back::dxil::DxilObject;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::BindingStage;
use crate::{error, util};
use crate::quad_render::DrawQuad;
@ -112,25 +115,13 @@ impl D3D12RootSignature {
}
}
impl D3D12GraphicsPipeline {
pub fn new(device: &ID3D12Device,
library: &IDxcLibrary,
validator: &IDxcValidator,
shader_assembly: &ShaderCompilerOutput<DxilObject, (Vec<u32>, Vec<u32>)>,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
source: &ShaderSource,
fn new_from_blobs(
device: &ID3D12Device,
vertex_dxil: IDxcBlob,
fragment_dxil: IDxcBlob,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
) -> error::Result<D3D12GraphicsPipeline> {
if shader_assembly.vertex.requires_runtime_data() {
panic!("vertex needs rt data??")
}
if shader_assembly.fragment.requires_runtime_data() {
panic!("fragment needs rt data??")
}
let vertex_dxil =
util::dxc_validate_shader(library, validator, &shader_assembly.vertex)?;
let fragment_dxil =
util::dxc_validate_shader(library, validator, &shader_assembly.fragment)?;
let input_element = DrawQuad::get_spirv_cross_vbo_desc();
let pipeline_state: ID3D12PipelineState = unsafe {
@ -207,4 +198,43 @@ impl D3D12GraphicsPipeline {
handle: pipeline_state,
})
}
pub fn new_from_dxil(device: &ID3D12Device,
library: &IDxcUtils,
validator: &IDxcValidator,
shader_assembly: &ShaderCompilerOutput<DxilObject, ()>,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
) -> error::Result<D3D12GraphicsPipeline> {
if shader_assembly.vertex.requires_runtime_data() {
panic!("vertex needs rt data??")
}
if shader_assembly.fragment.requires_runtime_data() {
panic!("fragment needs rt data??")
}
let vertex_dxil =
util::dxc_validate_shader(library, validator, &shader_assembly.vertex)?;
let fragment_dxil =
util::dxc_validate_shader(library, validator, &shader_assembly.fragment)?;
Self::new_from_blobs(device, vertex_dxil, fragment_dxil, root_signature, render_format)
}
pub fn new_from_hlsl(device: &ID3D12Device,
library: &IDxcUtils,
dxc: &IDxcCompiler,
shader_assembly: &ShaderCompilerOutput<String, CrossHlslContext>,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
) -> error::Result<D3D12GraphicsPipeline> {
unsafe {
let vertex_dxil = util::dxc_compile_shader(library, dxc, &shader_assembly.vertex, BindingStage::VERTEX)?;
let fragment_dxil =
util::dxc_compile_shader(library, dxc,&shader_assembly.fragment, BindingStage::FRAGMENT)?;
Self::new_from_blobs(device, vertex_dxil, fragment_dxil, root_signature, render_format)
}
}
}

View file

@ -25,8 +25,8 @@ mod tests {
#[test]
fn triangle_d3d12() {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
"../test/slang-shaders/crt/crt-royale.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// "../test/slang-shaders/crt/crt-royale.slangp",
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
&SampleCommandLine {
use_warp_device: false,
},

View file

@ -2,12 +2,13 @@ use std::ffi::CStr;
use std::mem::ManuallyDrop;
use std::u64;
use crate::error;
use windows::core::{Interface, PCSTR};
use windows::core::{Interface, PCSTR, PCWSTR};
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, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE, 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::Direct3D::Dxc::{DXC_CP, DxcValidatorFlags_Default, DxcValidatorFlags_InPlaceEdit, DxcValidatorFlags_ModuleOnly, DxcValidatorFlags_ValidMask, IDxcBlob, IDxcBlobUtf8, IDxcLibrary, IDxcValidator};
use windows::Win32::Graphics::Direct3D::Dxc::{DXC_CP, DXC_CP_UTF8, DxcValidatorFlags_Default, DxcValidatorFlags_InPlaceEdit, DxcValidatorFlags_ModuleOnly, DxcValidatorFlags_ValidMask, IDxcBlob, IDxcBlobUtf8, IDxcCompiler, IDxcLibrary, IDxcUtils, IDxcValidator};
use windows::Win32::Graphics::Dxgi::Common::*;
use librashader_reflect::reflect::semantics::BindingStage;
use crate::error::assume_d3d12_init;
/// wtf retroarch?
@ -145,16 +146,65 @@ pub fn fxc_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error:
}
}
pub fn dxc_validate_shader(library: &IDxcLibrary, validator: &IDxcValidator, source: &[u8]) -> error::Result<IDxcBlob> {
pub fn dxc_compile_shader(library: &IDxcUtils, compiler: &IDxcCompiler, source: &String, profile: BindingStage) -> error::Result<IDxcBlob> {
// todo: compile with dxc
// let mut source = source.to_vec();
let include = unsafe {
library.CreateDefaultIncludeHandler()?
};
let blob = unsafe {
library.CreateBlobFromPinned(
source.as_ptr().cast(),
source.as_bytes().len() as u32,
DXC_CP_UTF8
)?
};
let profile = if profile == BindingStage::FRAGMENT {
windows::w!("ps_6_0")
} else {
windows::w!("vs_6_0")
};
unsafe {
let result = compiler.Compile(&blob,
PCWSTR::null(),
windows::w!("main"),
profile,
None,
&[],
&include
)?;
if let Ok(buf) = result.GetErrorBuffer() {
unsafe {
let buf: IDxcBlobUtf8 = buf.cast().unwrap();
let buf = std::slice::from_raw_parts(buf.GetBufferPointer()
.cast(), buf.GetBufferSize());
let str = std::str::from_utf8_unchecked(buf);
if str.len() != 0 {
eprintln!("{}", str);
}
}
}
let result = result.GetResult()?;
Ok(result)
}
}
pub fn dxc_validate_shader(library: &IDxcUtils, validator: &IDxcValidator, source: &[u8]) -> error::Result<IDxcBlob> {
// todo: compile with dxc
// let mut source = source.to_vec();
let blob = unsafe {
library.CreateBlobWithEncodingOnHeapCopy(
source.as_ptr().cast(),
source.len() as u32,
DXC_CP(0)
)?
library.CreateBlob(source.as_ptr().cast(),
source.len() as u32,
DXC_CP(0))?
};
unsafe {