d3d12: upload shaders

This commit is contained in:
chyyran 2023-01-30 02:02:10 -05:00 committed by Ronny Chan
parent 53e3732a93
commit c2bef7f985
8 changed files with 423 additions and 38 deletions

View file

@ -220,30 +220,29 @@ impl FilterChainD3D11 {
passes: Vec<ShaderPassMeta>,
semantics: &ShaderSemantics,
) -> error::Result<Vec<FilterPass>> {
// let mut filters = Vec::new();
let mut filters = Vec::new();
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
let reflection = reflect.reflect(index, semantics)?;
let hlsl = reflect.compile(None)?;
let vertex_dxil =
let vertex_dxbc =
util::d3d_compile_shader(hlsl.vertex.as_bytes(), b"main\0", b"vs_5_0\0")?;
let vs = d3d11_compile_bound_shader(
device,
&vertex_dxil,
&vertex_dxbc,
None,
ID3D11Device::CreateVertexShader,
)?;
let ia_desc = DrawQuad::get_spirv_cross_vbo_desc();
let vao = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxil)?;
let vao = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxbc)?;
let fragment_dxil =
let fragment_dxbc =
util::d3d_compile_shader(hlsl.fragment.as_bytes(), b"main\0", b"ps_5_0\0")?;
let ps = d3d11_compile_bound_shader(
device,
&fragment_dxil,
&fragment_dxbc,
None,
ID3D11Device::CreatePixelShader,
)?;

View file

@ -126,6 +126,7 @@ pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error:
None,
)?;
// SAFETY: if D3DCompile succeeds then blob is Some
Ok(blob.unwrap())
}
}

View file

@ -1,12 +1,12 @@
use std::borrow::Borrow;
use crate::error;
use crate::{error, util};
use crate::heap::{D3D12DescriptorHeap, LutTextureHeap, ResourceWorkHeap};
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 librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_runtime::image::{Image, UVDirection};
use rustc_hash::FxHashMap;
use std::error::Error;
@ -21,7 +21,16 @@ use windows::Win32::Graphics::Direct3D12::{
};
use windows::Win32::System::Threading::{CreateEventA, ResetEvent, WaitForSingleObject};
use windows::Win32::System::WindowsProgramming::INFINITE;
use librashader_common::ImageFormat;
use librashader_reflect::back::{CompileReflectShader, CompileShader};
use librashader_reflect::reflect::ReflectShader;
use librashader_reflect::reflect::semantics::ShaderSemantics;
use crate::filter_pass::FilterPass;
use crate::graphics_pipeline::{D3D12GraphicsPipeline, D3D12RootSignature};
use crate::mipmap::D3D12MipmapGen;
use crate::quad_render::DrawQuad;
type ShaderPassMeta = ShaderPassArtifact<impl CompileReflectShader<HLSL, GlslangCompilation>>;
pub struct FilterChainD3D12 {
pub(crate) common: FilterCommon,
@ -30,6 +39,7 @@ pub struct FilterChainD3D12 {
// pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>,
// pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
// pub(crate) draw_quad: DrawQuad,
pub(crate) filters: Vec<FilterPass>,
}
pub(crate) struct FilterCommon {
@ -44,6 +54,7 @@ pub(crate) struct FilterCommon {
lut_heap: D3D12DescriptorHeap<LutTextureHeap>,
luts: FxHashMap<usize, LutTexture>,
mipmap_gen: D3D12MipmapGen,
root_signature: D3D12RootSignature,
}
impl FilterChainD3D12 {
@ -58,6 +69,41 @@ impl FilterChainD3D12 {
Self::load_from_preset(device, preset, options)
}
/// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(
device: &ID3D12Device,
preset: ShaderPreset,
options: Option<&()>,
) -> error::Result<FilterChainD3D12> {
let (passes, semantics) = HLSL::compile_preset_passes::<GlslangCompilation, Box<dyn Error>>(
preset.shaders,
&preset.textures,
)?;
let samplers = SamplerSet::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, &mipmap_gen).unwrap();
let root_signature = D3D12RootSignature::new(device)?;
let filters = FilterChainD3D12::init_passes(device, &root_signature, passes, &semantics)?;
Ok(FilterChainD3D12 {
common: FilterCommon {
d3d12: device.clone(),
samplers,
lut_heap,
luts,
mipmap_gen,
root_signature,
},
filters
})
}
fn load_luts(
device: &ID3D12Device,
heap: &mut D3D12DescriptorHeap<LutTextureHeap>,
@ -142,36 +188,41 @@ impl FilterChainD3D12 {
unsafe { CloseHandle(fence_event) };
}
std::mem::forget(residuals);
drop(residuals);
Ok(luts)
}
}
/// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(
device: &ID3D12Device,
preset: ShaderPreset,
options: Option<&()>,
) -> error::Result<FilterChainD3D12> {
let (passes, semantics) = HLSL::compile_preset_passes::<GlslangCompilation, Box<dyn Error>>(
preset.shaders,
&preset.textures,
)?;
fn init_passes(device: &ID3D12Device,
root_signature: &D3D12RootSignature,
passes: Vec<ShaderPassMeta>,
semantics: &ShaderSemantics,)
-> error::Result<Vec<FilterPass>> {
let samplers = SamplerSet::new(device)?;
let mipmap_gen = D3D12MipmapGen::new(device).unwrap();
let mut filters = Vec::new();
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
let reflection = reflect.reflect(index, semantics)?;
let hlsl = reflect.compile(None)?;
let mut lut_heap = D3D12DescriptorHeap::new(device, preset.textures.len())?;
let luts = FilterChainD3D12::load_luts(device, &mut lut_heap, &preset.textures, &mipmap_gen).unwrap();
let graphics_pipeline = D3D12GraphicsPipeline::new(device,
&hlsl,
root_signature,
if let Some(format) = config.get_format_override() {
format
} else if source.format != ImageFormat::Unknown {
source.format
} else {
ImageFormat::R8G8B8A8Unorm
}.into()
)?;
Ok(FilterChainD3D12 {
common: FilterCommon {
d3d12: device.clone(),
samplers,
lut_heap,
luts,
mipmap_gen,
},
})
filters.push(FilterPass {
pipeline: graphics_pipeline,
})
}
Ok(filters)
}
}

View file

@ -0,0 +1,5 @@
use crate::graphics_pipeline::D3D12GraphicsPipeline;
pub(crate) struct FilterPass {
pub(crate) pipeline: D3D12GraphicsPipeline
}

View file

@ -0,0 +1,204 @@
use windows::core::Vtable;
use windows::Win32::Foundation::BOOL;
use windows::Win32::Graphics::Direct3D12::{D3D12_BLEND_DESC, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP, D3D12_BLEND_OP_ADD, D3D12_BLEND_SRC_ALPHA, D3D12_COLOR_WRITE_ENABLE_ALL, D3D12_CULL_MODE_NONE, D3D12_DESCRIPTOR_RANGE, D3D12_DESCRIPTOR_RANGE_TYPE, 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, D3D_ROOT_SIGNATURE_VERSION_1_0, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature};
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_UNKNOWN, DXGI_SAMPLE_DESC};
use librashader_reflect::back::cross::CrossHlslContext;
use librashader_reflect::back::ShaderCompilerOutput;
use crate::{error, util};
use crate::quad_render::DrawQuad;
pub struct D3D12GraphicsPipeline {
pipeline_state: ID3D12PipelineState,
}
const D3D12_SLANG_ROOT_PARAMETERS: &'static [D3D12_ROOT_PARAMETER; 4] = &[
// srvs
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 16,
BaseShaderRegister: 0,
RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: 0,
},
}
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
// samplers
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
NumDescriptors: 16,
BaseShaderRegister: 0,
RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: 0,
},
}
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
// UBO
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 0,
RegisterSpace: 0,
}
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 1,
RegisterSpace: 0,
}
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
}
];
const D3D12_SLANG_ROOT_SIGNATURE: &'static D3D12_ROOT_SIGNATURE_DESC = &D3D12_ROOT_SIGNATURE_DESC {
NumParameters: D3D12_SLANG_ROOT_PARAMETERS.len() as u32,
pParameters: D3D12_SLANG_ROOT_PARAMETERS.as_ptr(),
NumStaticSamplers: 0,
pStaticSamplers: std::ptr::null(),
Flags: D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT,
};
pub struct D3D12RootSignature {
signature: ID3D12RootSignature
}
impl D3D12RootSignature {
pub fn new(device: &ID3D12Device)
-> error::Result<D3D12RootSignature>
{
let signature = unsafe {
let mut rs_blob = None;
// todo: D3D12SerializeVersionedRootSignature
// todo: hlsl rootsig tbh
D3D12SerializeRootSignature(D3D12_SLANG_ROOT_SIGNATURE,
D3D_ROOT_SIGNATURE_VERSION_1,
&mut rs_blob,
None
)?;
// SAFETY: if D3D12SerializeRootSignature succeeds then blob is Some
let rs_blob = rs_blob.unwrap();
let blob = std::slice::from_raw_parts(rs_blob.GetBufferPointer().cast(),
rs_blob.GetBufferSize());
let root_signature: ID3D12RootSignature = device.CreateRootSignature(
0, blob
)?;
root_signature
};
Ok(D3D12RootSignature {
signature,
})
}
}
impl D3D12GraphicsPipeline {
pub fn new(device: &ID3D12Device,
shader_assembly: &ShaderCompilerOutput<String, CrossHlslContext>,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT
) -> error::Result<D3D12GraphicsPipeline> {
let vertex_dxbc =
util::d3d_compile_shader(shader_assembly.vertex.as_bytes(),
b"main\0", b"vs_5_0\0")?;
let fragment_dxbc =
util::d3d_compile_shader(shader_assembly.fragment.as_bytes(), b"main\0",
b"ps_5_0\0")?;
let input_element = DrawQuad::get_spirv_cross_vbo_desc();
let pipeline_state: ID3D12PipelineState = unsafe {
let pipeline_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC {
pRootSignature: windows::core::ManuallyDrop::new(&root_signature.signature),
VS: D3D12_SHADER_BYTECODE {
pShaderBytecode: vertex_dxbc.GetBufferPointer(),
BytecodeLength: vertex_dxbc.GetBufferSize(),
},
PS: D3D12_SHADER_BYTECODE {
pShaderBytecode: fragment_dxbc.GetBufferPointer(),
BytecodeLength: fragment_dxbc.GetBufferSize(),
},
StreamOutput: Default::default(),
BlendState: D3D12_BLEND_DESC {
RenderTarget: [
D3D12_RENDER_TARGET_BLEND_DESC {
BlendEnable: BOOL::from(false),
LogicOpEnable: BOOL::from(false),
SrcBlend: D3D12_BLEND_SRC_ALPHA,
DestBlend: D3D12_BLEND_INV_SRC_ALPHA,
BlendOp: D3D12_BLEND_OP_ADD,
SrcBlendAlpha: D3D12_BLEND_SRC_ALPHA,
DestBlendAlpha: D3D12_BLEND_INV_SRC_ALPHA,
BlendOpAlpha: D3D12_BLEND_OP_ADD,
LogicOp: D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: D3D12_COLOR_WRITE_ENABLE_ALL.0 as u8,
},
Default::default(),
Default::default(),
Default::default(),
Default::default(),
Default::default(),
Default::default(),
Default::default()
],
..Default::default()
},
SampleMask: u32::MAX,
RasterizerState: D3D12_RASTERIZER_DESC {
FillMode: D3D12_FILL_MODE_SOLID,
CullMode: D3D12_CULL_MODE_NONE,
..Default::default()
},
DepthStencilState: Default::default(),
InputLayout: D3D12_INPUT_LAYOUT_DESC {
pInputElementDescs: input_element.as_ptr(),
NumElements: input_element.len() as u32,
},
PrimitiveTopologyType: D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets: 1,
RTVFormats: [
render_format,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
],
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
NodeMask: 0,
..Default::default()
};
device.CreateGraphicsPipelineState(&pipeline_desc)?
};
Ok(D3D12GraphicsPipeline {
pipeline_state,
})
}
}

View file

@ -1,6 +1,6 @@
#![feature(const_trait_impl)]
#![feature(let_chains)]
#![feature(type_alias_impl_trait)]
mod error;
mod filter_chain;
mod heap;
@ -9,6 +9,9 @@ mod samplers;
mod texture;
mod util;
mod mipmap;
mod filter_pass;
mod quad_render;
mod graphics_pipeline;
#[cfg(test)]
mod tests {

View file

@ -0,0 +1,120 @@
use crate::error;
use bytemuck::offset_of;
use windows::core::PCSTR;
use windows::Win32::Graphics::Direct3D::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
use windows::Win32::Graphics::Direct3D11::{
ID3D11Buffer, ID3D11Device, ID3D11DeviceContext, D3D11_BIND_VERTEX_BUFFER, D3D11_BUFFER_DESC,
D3D11_INPUT_ELEMENT_DESC, D3D11_INPUT_PER_VERTEX_DATA, D3D11_SUBRESOURCE_DATA,
D3D11_USAGE_IMMUTABLE,
};
use windows::Win32::Graphics::Direct3D12::{D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, D3D12_INPUT_ELEMENT_DESC};
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R32G32_FLOAT;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
struct D3D12Vertex {
position: [f32; 2],
texcoord: [f32; 2],
color: [f32; 4],
}
const CLEAR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
static QUAD_VBO_DATA: &[D3D12Vertex; 4] = &[
D3D12Vertex {
position: [0.0, 0.0],
texcoord: [0.0, 1.0],
color: CLEAR,
},
D3D12Vertex {
position: [0.0, 1.0],
texcoord: [0.0, 0.0],
color: CLEAR,
},
D3D12Vertex {
position: [1.0, 0.0],
texcoord: [1.0, 1.0],
color: CLEAR,
},
D3D12Vertex {
position: [1.0, 1.0],
texcoord: [1.0, 0.0],
color: CLEAR,
},
];
pub(crate) struct DrawQuad {
buffer: ID3D11Buffer,
context: ID3D11DeviceContext,
offset: u32,
stride: u32,
}
impl DrawQuad {
// pub fn new(device: &ID3D11Device, context: &ID3D11DeviceContext) -> error::Result<DrawQuad> {
// unsafe {
// let mut buffer = None;
// device.CreateBuffer(
// &D3D11_BUFFER_DESC {
// ByteWidth: std::mem::size_of::<[D3D11Vertex; 4]>() as u32,
// Usage: D3D11_USAGE_IMMUTABLE,
// BindFlags: D3D11_BIND_VERTEX_BUFFER,
// CPUAccessFlags: Default::default(),
// MiscFlags: Default::default(),
// StructureByteStride: 0,
// },
// Some(&D3D11_SUBRESOURCE_DATA {
// pSysMem: QUAD_VBO_DATA.as_ptr().cast(),
// SysMemPitch: 0,
// SysMemSlicePitch: 0,
// }),
// Some(&mut buffer),
// )?;
// assume_d3d11_init!(buffer, "CreateBuffer");
//
// Ok(DrawQuad {
// buffer,
// context: context.clone(),
// offset: 0,
// stride: std::mem::size_of::<D3D11Vertex>() as u32,
// })
// }
// }
//
// pub fn bind_vertices(&self) {
// unsafe {
// self.context
// .IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// self.context.IASetVertexBuffers(
// 0,
// 1,
// Some(&Some(self.buffer.clone())),
// Some(&self.stride),
// Some(&self.offset),
// );
// }
// }
pub fn get_spirv_cross_vbo_desc() -> [D3D12_INPUT_ELEMENT_DESC; 2] {
[
D3D12_INPUT_ELEMENT_DESC {
SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()),
SemanticIndex: 0,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: offset_of!(D3D12Vertex, position) as u32,
InputSlotClass: D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
D3D12_INPUT_ELEMENT_DESC {
SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()),
SemanticIndex: 1,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: offset_of!(D3D12Vertex, texcoord) as u32,
InputSlotClass: D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
]
}
}

View file

@ -116,6 +116,7 @@ pub fn d3d12_get_closest_format(
}
pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error::Result<ID3DBlob> {
// todo: compile with dxc
unsafe {
let mut blob = None;
D3DCompile(
@ -126,11 +127,12 @@ pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error:
None,
PCSTR(entry.as_ptr()),
PCSTR(version.as_ptr()),
if cfg!(feature = "debug-shader") {
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
} else {
D3DCOMPILE_OPTIMIZATION_LEVEL3
},
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
// if cfg!(feature = "debug-shader") {
// D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
// } else {
// D3DCOMPILE_OPTIMIZATION_LEVEL3
// },
0,
&mut blob,
None,