librashader/librashader-runtime-d3d12/src/graphics_pipeline.rs

375 lines
14 KiB
Rust
Raw Normal View History

2023-02-06 12:05:22 +11:00
use crate::error::assume_d3d12_init;
use crate::error::FilterChainError::Direct3DOperationError;
2023-02-06 08:17:23 +11:00
use crate::quad_render::DrawQuad;
use crate::{error, util};
use librashader_cache::cache::{cache_object, cache_pipeline};
2023-01-30 18:02:10 +11:00
use librashader_reflect::back::cross::CrossHlslContext;
2023-02-05 17:54:56 +11:00
use librashader_reflect::back::dxil::DxilObject;
2023-01-30 18:02:10 +11:00
use librashader_reflect::back::ShaderCompilerOutput;
use std::ops::Deref;
use widestring::u16cstr;
2023-02-06 08:17:23 +11:00
use windows::Win32::Foundation::BOOL;
use windows::Win32::Graphics::Direct3D::Dxc::{
CLSID_DxcLibrary, DxcCreateInstance, IDxcBlob, IDxcCompiler, IDxcUtils, IDxcValidator, DXC_CP,
};
2023-02-06 17:05:19 +11:00
use windows::Win32::Graphics::Direct3D12::{
D3D12SerializeVersionedRootSignature, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature,
D3D12_BLEND_DESC, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_SRC_ALPHA,
D3D12_CACHED_PIPELINE_STATE, D3D12_COLOR_WRITE_ENABLE_ALL, D3D12_CULL_MODE_NONE,
D3D12_DESCRIPTOR_RANGE1, D3D12_DESCRIPTOR_RANGE_FLAGS,
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE, D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE,
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_DESCRIPTOR1, D3D12_ROOT_DESCRIPTOR_FLAG_NONE, D3D12_ROOT_DESCRIPTOR_TABLE1,
D3D12_ROOT_PARAMETER1, D3D12_ROOT_PARAMETER1_0, D3D12_ROOT_PARAMETER_TYPE_CBV,
2023-02-06 17:05:19 +11:00
D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, D3D12_ROOT_SIGNATURE_DESC1,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, D3D12_SHADER_BYTECODE,
D3D12_SHADER_VISIBILITY_ALL, D3D12_SHADER_VISIBILITY_PIXEL,
D3D12_VERSIONED_ROOT_SIGNATURE_DESC, D3D12_VERSIONED_ROOT_SIGNATURE_DESC_0,
D3D_ROOT_SIGNATURE_VERSION_1_1,
};
2023-02-06 08:17:23 +11:00
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_UNKNOWN, DXGI_SAMPLE_DESC};
2023-01-30 18:02:10 +11:00
pub struct D3D12GraphicsPipeline {
2023-02-01 16:16:06 +11:00
pub(crate) handle: ID3D12PipelineState,
pub(crate) format: DXGI_FORMAT,
vertex: Vec<u8>,
fragment: Vec<u8>,
2023-01-30 18:02:10 +11:00
}
2023-02-06 15:18:13 +11:00
const D3D12_SLANG_ROOT_PARAMETERS: &[D3D12_ROOT_PARAMETER1; 4] = &[
2023-01-30 18:02:10 +11:00
// srvs
2023-02-06 15:18:13 +11:00
D3D12_ROOT_PARAMETER1 {
2023-01-30 18:02:10 +11:00
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
2023-02-06 15:18:13 +11:00
Anonymous: D3D12_ROOT_PARAMETER1_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE1 {
2023-01-30 18:02:10 +11:00
NumDescriptorRanges: 1,
2023-02-06 15:18:13 +11:00
pDescriptorRanges: &D3D12_DESCRIPTOR_RANGE1 {
2023-01-30 18:02:10 +11:00
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 16,
BaseShaderRegister: 0,
RegisterSpace: 0,
2023-02-06 17:05:19 +11:00
Flags: D3D12_DESCRIPTOR_RANGE_FLAGS(
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE.0
| D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE.0,
),
2023-01-30 18:02:10 +11:00
OffsetInDescriptorsFromTableStart: 0,
},
2023-02-06 08:17:23 +11:00
},
2023-01-30 18:02:10 +11:00
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
// samplers
2023-02-06 15:18:13 +11:00
D3D12_ROOT_PARAMETER1 {
2023-01-30 18:02:10 +11:00
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
2023-02-06 15:18:13 +11:00
Anonymous: D3D12_ROOT_PARAMETER1_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE1 {
2023-01-30 18:02:10 +11:00
NumDescriptorRanges: 1,
2023-02-06 15:18:13 +11:00
pDescriptorRanges: &D3D12_DESCRIPTOR_RANGE1 {
2023-01-30 18:02:10 +11:00
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
NumDescriptors: 16,
BaseShaderRegister: 0,
RegisterSpace: 0,
2023-02-06 15:18:13 +11:00
Flags: D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE,
2023-01-30 18:02:10 +11:00
OffsetInDescriptorsFromTableStart: 0,
},
2023-02-06 08:17:23 +11:00
},
2023-01-30 18:02:10 +11:00
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
// UBO
2023-02-06 15:18:13 +11:00
D3D12_ROOT_PARAMETER1 {
2023-01-30 18:02:10 +11:00
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
2023-02-06 15:18:13 +11:00
Anonymous: D3D12_ROOT_PARAMETER1_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR1 {
2023-01-30 18:02:10 +11:00
ShaderRegister: 0,
RegisterSpace: 0,
2023-02-06 15:18:13 +11:00
Flags: D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
2023-02-06 08:17:23 +11:00
},
2023-01-30 18:02:10 +11:00
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
2023-02-06 15:18:13 +11:00
// push
D3D12_ROOT_PARAMETER1 {
2023-01-30 18:02:10 +11:00
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
2023-02-06 15:18:13 +11:00
Anonymous: D3D12_ROOT_PARAMETER1_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR1 {
2023-01-30 18:02:10 +11:00
ShaderRegister: 1,
RegisterSpace: 0,
2023-02-06 15:18:13 +11:00
Flags: D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
2023-02-06 08:17:23 +11:00
},
2023-01-30 18:02:10 +11:00
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
2023-02-06 08:17:23 +11:00
},
2023-01-30 18:02:10 +11:00
];
2023-02-06 17:05:19 +11:00
const D3D12_SLANG_VERSIONED_ROOT_SIGNATURE: &D3D12_VERSIONED_ROOT_SIGNATURE_DESC =
&D3D12_VERSIONED_ROOT_SIGNATURE_DESC {
Version: D3D_ROOT_SIGNATURE_VERSION_1_1,
Anonymous: D3D12_VERSIONED_ROOT_SIGNATURE_DESC_0 {
Desc_1_1: D3D12_ROOT_SIGNATURE_DESC1 {
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,
},
},
};
2023-01-30 18:02:10 +11:00
pub struct D3D12RootSignature {
2023-02-06 08:17:23 +11:00
pub(crate) handle: ID3D12RootSignature,
2023-01-30 18:02:10 +11:00
}
impl D3D12RootSignature {
2023-02-06 08:17:23 +11:00
pub fn new(device: &ID3D12Device) -> error::Result<D3D12RootSignature> {
2023-01-30 18:02:10 +11:00
let signature = unsafe {
let mut rs_blob = None;
2023-02-06 14:31:34 +11:00
D3D12SerializeVersionedRootSignature(
D3D12_SLANG_VERSIONED_ROOT_SIGNATURE,
2023-02-06 08:17:23 +11:00
&mut rs_blob,
None,
2023-01-30 18:02:10 +11:00
)?;
2023-02-06 14:31:34 +11:00
assume_d3d12_init!(rs_blob, "D3D12SerializeVersionedRootSignature");
2023-02-06 08:17:23 +11:00
let blob = std::slice::from_raw_parts(
rs_blob.GetBufferPointer().cast(),
rs_blob.GetBufferSize(),
);
let root_signature: ID3D12RootSignature = device.CreateRootSignature(0, blob)?;
2023-01-30 18:02:10 +11:00
root_signature
};
2023-02-06 08:17:23 +11:00
Ok(D3D12RootSignature { handle: signature })
2023-01-30 18:02:10 +11:00
}
}
impl D3D12GraphicsPipeline {
pub fn new_from_blobs(
2023-02-05 17:54:56 +11:00
device: &ID3D12Device,
vertex_dxil: IDxcBlob,
fragment_dxil: IDxcBlob,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
2023-01-30 18:02:10 +11:00
) -> error::Result<D3D12GraphicsPipeline> {
let input_element = DrawQuad::get_spirv_cross_vbo_desc();
let pipeline_state: ID3D12PipelineState = unsafe {
let pipeline_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC {
2023-02-01 17:57:31 +11:00
pRootSignature: windows::core::ManuallyDrop::new(&root_signature.handle),
2023-01-30 18:02:10 +11:00
VS: D3D12_SHADER_BYTECODE {
pShaderBytecode: vertex_dxil.GetBufferPointer(),
BytecodeLength: vertex_dxil.GetBufferSize(),
2023-01-30 18:02:10 +11:00
},
PS: D3D12_SHADER_BYTECODE {
pShaderBytecode: fragment_dxil.GetBufferPointer(),
BytecodeLength: fragment_dxil.GetBufferSize(),
2023-01-30 18:02:10 +11:00
},
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(),
2023-02-06 08:17:23 +11:00
Default::default(),
2023-01-30 18:02:10 +11:00
],
..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()
};
cache_pipeline(
"d3d12",
&[&vertex_dxil, &fragment_dxil, &render_format.0],
|cached: Option<Vec<u8>>| {
if let Some(cached) = cached {
let pipeline_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC {
CachedPSO: D3D12_CACHED_PIPELINE_STATE {
pCachedBlob: cached.as_ptr().cast(),
CachedBlobSizeInBytes: cached.len(),
},
pRootSignature: windows::core::ManuallyDrop::new(
&root_signature.handle,
),
..pipeline_desc
};
device.CreateGraphicsPipelineState(&pipeline_desc)
} else {
device.CreateGraphicsPipelineState(&pipeline_desc)
}
},
|pso: &ID3D12PipelineState| {
let cached_pso = pso.GetCachedBlob()?;
Ok(cached_pso)
},
true,
)?
2023-01-30 18:02:10 +11:00
};
unsafe {
let vertex = Vec::from(std::slice::from_raw_parts(
vertex_dxil.GetBufferPointer().cast(),
vertex_dxil.GetBufferSize(),
));
let fragment = Vec::from(std::slice::from_raw_parts(
fragment_dxil.GetBufferPointer().cast(),
fragment_dxil.GetBufferSize(),
));
Ok(D3D12GraphicsPipeline {
handle: pipeline_state,
format: render_format,
vertex,
fragment,
})
}
}
pub fn recompile(
&mut self,
format: DXGI_FORMAT,
root_sig: &D3D12RootSignature,
device: &ID3D12Device,
) -> error::Result<()> {
let (vertex, fragment) = unsafe {
let library: IDxcUtils = DxcCreateInstance(&CLSID_DxcLibrary)?;
let vertex = library.CreateBlobFromPinned(
self.vertex.as_ptr().cast(),
self.vertex.len() as u32,
DXC_CP(0),
)?;
let fragment = library.CreateBlobFromPinned(
self.fragment.as_ptr().cast(),
self.fragment.len() as u32,
DXC_CP(0),
)?;
(vertex, fragment)
};
let mut new_pipeline =
Self::new_from_blobs(device, vertex.into(), fragment.into(), root_sig, format)?;
std::mem::swap(self, &mut new_pipeline);
Ok(())
2023-01-30 18:02:10 +11:00
}
2023-02-05 17:54:56 +11:00
2023-02-06 08:17:23 +11:00
pub fn new_from_dxil(
device: &ID3D12Device,
library: &IDxcUtils,
validator: &IDxcValidator,
shader_assembly: &ShaderCompilerOutput<DxilObject, ()>,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
2023-02-05 17:54:56 +11:00
) -> error::Result<D3D12GraphicsPipeline> {
if shader_assembly.vertex.requires_runtime_data() {
2023-02-06 12:05:22 +11:00
return Err(Direct3DOperationError(
"Compiled DXIL Vertex shader needs unexpected runtime data",
));
2023-02-05 17:54:56 +11:00
}
if shader_assembly.fragment.requires_runtime_data() {
2023-02-06 12:05:22 +11:00
return Err(Direct3DOperationError(
"Compiled DXIL fragment shader needs unexpected runtime data",
));
2023-02-05 17:54:56 +11:00
}
let vertex_dxil = cache_object(
"dxil",
&[shader_assembly.vertex.deref()],
|&[source]| util::dxc_validate_shader(library, validator, source),
|f| Ok(f),
true,
)?;
let fragment_dxil = cache_object(
"dxil",
&[shader_assembly.fragment.deref()],
|&[source]| util::dxc_validate_shader(library, validator, source),
|f| Ok(f),
true,
)?;
2023-02-05 17:54:56 +11:00
2023-02-06 08:17:23 +11:00
Self::new_from_blobs(
device,
vertex_dxil,
fragment_dxil,
root_signature,
render_format,
)
2023-02-05 17:54:56 +11:00
}
2023-02-06 08:17:23 +11:00
pub fn new_from_hlsl(
device: &ID3D12Device,
library: &IDxcUtils,
dxc: &IDxcCompiler,
shader_assembly: &ShaderCompilerOutput<String, CrossHlslContext>,
root_signature: &D3D12RootSignature,
render_format: DXGI_FORMAT,
2023-02-05 17:54:56 +11:00
) -> error::Result<D3D12GraphicsPipeline> {
let vertex_dxil = cache_object(
"dxil",
&[shader_assembly.vertex.as_bytes()],
|&[source]| util::dxc_compile_shader(library, dxc, source, u16cstr!("vs_6_0")),
|f| Ok(f),
true,
)?;
let fragment_dxil = cache_object(
"dxil",
&[shader_assembly.fragment.as_bytes()],
|&[source]| util::dxc_compile_shader(library, dxc, source, u16cstr!("ps_6_0")),
|f| Ok(f),
true,
)?;
2023-02-05 17:54:56 +11:00
2023-02-10 13:03:55 +11:00
Self::new_from_blobs(
device,
vertex_dxil,
fragment_dxil,
root_signature,
render_format,
)
2023-02-05 17:54:56 +11:00
}
2023-02-06 08:17:23 +11:00
}