diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 70df262..1baedb7 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -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>; +type DxilShaderPassMeta = ShaderPassArtifact>; +type HlslShaderPassMeta = ShaderPassArtifact>; pub struct FilterMutable { pub(crate) passes_enabled: usize, @@ -90,11 +92,19 @@ impl FilterChainD3D12 { ) -> error::Result { 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::>( preset.shaders, &preset.textures, ).unwrap(); + let (hlsl_passes, _) = HLSL::compile_preset_passes::>( + 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, + passes: Vec, + hlsl_passes: Vec, semantics: &ShaderSemantics,) - -> error::Result<(ID3D12DescriptorHeap, ID3D12DescriptorHeap, Vec)> { + -> error::Result<(ID3D12DescriptorHeap, ID3D12DescriptorHeap, Vec)> { 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 diff --git a/librashader-runtime-d3d12/src/graphics_pipeline.rs b/librashader-runtime-d3d12/src/graphics_pipeline.rs index ce0f9a8..4681b99 100644 --- a/librashader-runtime-d3d12/src/graphics_pipeline.rs +++ b/librashader-runtime-d3d12/src/graphics_pipeline.rs @@ -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, Vec)>, - 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 { - 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, + root_signature: &D3D12RootSignature, + render_format: DXGI_FORMAT, + ) -> error::Result { + 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, + root_signature: &D3D12RootSignature, + render_format: DXGI_FORMAT, + ) -> error::Result { + 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) + } + + } } \ No newline at end of file diff --git a/librashader-runtime-d3d12/src/lib.rs b/librashader-runtime-d3d12/src/lib.rs index 473a50d..b1da449 100644 --- a/librashader-runtime-d3d12/src/lib.rs +++ b/librashader-runtime-d3d12/src/lib.rs @@ -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, }, diff --git a/librashader-runtime-d3d12/src/util.rs b/librashader-runtime-d3d12/src/util.rs index 9bf4d27..3635fc6 100644 --- a/librashader-runtime-d3d12/src/util.rs +++ b/librashader-runtime-d3d12/src/util.rs @@ -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 { + +pub fn dxc_compile_shader(library: &IDxcUtils, compiler: &IDxcCompiler, source: &String, profile: BindingStage) -> error::Result { + // 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 { // 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 {