use concinnity_core::render::backend_init;
use concinnity_core::render::error::{RenderError, RenderResult};
use concinnity_core::render::shadow_bias;
use windows::Win32::Graphics::Direct3D12::*;
use windows::Win32::Graphics::Dxgi::Common::*;
use crate::directx::builtin_shaders;
use crate::directx::builtin_shaders::CompileProgram;
use crate::directx::com;
use crate::directx::context::dump_on_err;
use crate::directx::draw::shadow::ShadowPush;
use crate::directx::error::map_pso_hresult;
use crate::directx::pipeline::{main_input_layout, serialize_and_create_root_sig};
use crate::directx::root_constants::root_dwords;
use crate::directx::texture::HDR_FORMAT;
pub(in crate::directx) fn world_entry(
world: &concinnity_core::components::ShaderPrograms,
entry: &str,
hot_reload: bool,
) -> RenderResult<Vec<u8>> {
let req = crate::shader::surface_source::Request {
platform: concinnity_core::platform::Platform::DirectX,
hot_reload,
};
crate::shader::surface_source::artifact(world, entry, &req, crate::shader::compile::cooked)
.map(|c| c.into_owned())
}
pub(in crate::directx) fn compile_main_bindless_shaders(
hot_reload: bool,
) -> RenderResult<(Vec<u8>, Vec<u8>)> {
let vs = builtin_shaders::MAIN_BINDLESS_VERT.compile(hot_reload)?;
let ps = builtin_shaders::MAIN_BINDLESS_FRAG.compile(hot_reload)?;
Ok((vs, ps))
}
pub(in crate::directx) fn compile_shadow_bindless_vs(hot_reload: bool) -> RenderResult<Vec<u8>> {
builtin_shaders::SHADOW_VERT_BINDLESS.compile(hot_reload)
}
pub(super) fn create_main_bindless_root_signature(
device: &ID3D12Device,
) -> RenderResult<ID3D12RootSignature> {
let shadow_srv_ranges = [
D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 0, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
},
D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 2,
BaseShaderRegister: 5, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
},
];
let pool_srv_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: u32::MAX, BaseShaderRegister: 0, RegisterSpace: 1, OffsetInDescriptorsFromTableStart: 0,
};
let shadow_sampler_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
NumDescriptors: 1,
BaseShaderRegister: 0, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let linear_cube_sampler_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
NumDescriptors: 2,
BaseShaderRegister: 1, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let ssao_srv_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 4, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let probe_cube_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 7, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let spot_shadow_srv_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 16, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let ltc_srv_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 2,
BaseShaderRegister: 18, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let params = [
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Constants: D3D12_ROOT_CONSTANTS {
ShaderRegister: 0,
RegisterSpace: 0,
Num32BitValues: 1,
},
},
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,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 2,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 3,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: shadow_srv_ranges.len() as u32,
pDescriptorRanges: shadow_srv_ranges.as_ptr(),
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &pool_srv_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &shadow_sampler_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &linear_cube_sampler_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 3,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &ssao_srv_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &probe_cube_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 4, RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 1,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 5,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 2,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 15, RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &spot_shadow_srv_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 17, RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: <c_srv_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 8, RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
];
serialize_and_create_root_sig(device, ¶ms, "main bindless root sig")
}
pub(in crate::directx) fn create_shadow_root_signature(
device: &ID3D12Device,
) -> RenderResult<ID3D12RootSignature> {
let params = [
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Constants: D3D12_ROOT_CONSTANTS {
ShaderRegister: 0,
RegisterSpace: 0,
Num32BitValues: root_dwords::<ShadowPush>(),
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_VERTEX,
},
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_VERTEX,
},
];
serialize_and_create_root_sig(device, ¶ms, "shadow root sig")
}
pub(in crate::directx) fn create_shadow_bindless_root_signature(
device: &ID3D12Device,
) -> RenderResult<ID3D12RootSignature> {
let params = [
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Constants: D3D12_ROOT_CONSTANTS {
ShaderRegister: 0,
RegisterSpace: 0,
Num32BitValues: 1,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_VERTEX,
},
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_VERTEX,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Constants: D3D12_ROOT_CONSTANTS {
ShaderRegister: 2,
RegisterSpace: 0,
Num32BitValues: 1,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_VERTEX,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_SRV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 0,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_VERTEX,
},
];
serialize_and_create_root_sig(device, ¶ms, "shadow bindless root sig")
}
pub(in crate::directx) fn create_main_pso(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
vs: &[u8],
ps: &[u8],
rtv_format: DXGI_FORMAT,
sample_count: u32,
) -> RenderResult<ID3D12PipelineState> {
create_main_pso_filled(
device,
root_sig,
vs,
ps,
rtv_format,
sample_count,
D3D12_FILL_MODE_SOLID,
)
}
pub(in crate::directx) fn create_main_pso_wireframe(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
vs: &[u8],
ps: &[u8],
rtv_format: DXGI_FORMAT,
sample_count: u32,
) -> RenderResult<ID3D12PipelineState> {
create_main_pso_filled(
device,
root_sig,
vs,
ps,
rtv_format,
sample_count,
D3D12_FILL_MODE_WIREFRAME,
)
}
fn create_main_pso_filled(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
vs: &[u8],
ps: &[u8],
rtv_format: DXGI_FORMAT,
sample_count: u32,
fill_mode: D3D12_FILL_MODE,
) -> RenderResult<ID3D12PipelineState> {
let layout = main_input_layout();
let pso_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC {
pRootSignature: com::borrowed(root_sig),
VS: D3D12_SHADER_BYTECODE {
pShaderBytecode: vs.as_ptr() as _,
BytecodeLength: vs.len(),
},
PS: D3D12_SHADER_BYTECODE {
pShaderBytecode: ps.as_ptr() as _,
BytecodeLength: ps.len(),
},
InputLayout: D3D12_INPUT_LAYOUT_DESC {
pInputElementDescs: layout.as_ptr(),
NumElements: layout.len() as u32,
},
PrimitiveTopologyType: D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets: 1,
RTVFormats: {
let mut a = [DXGI_FORMAT_UNKNOWN; 8];
a[0] = rtv_format;
a
},
DSVFormat: DXGI_FORMAT_D32_FLOAT,
SampleDesc: DXGI_SAMPLE_DESC {
Count: sample_count,
Quality: 0,
},
SampleMask: u32::MAX,
RasterizerState: D3D12_RASTERIZER_DESC {
FillMode: fill_mode,
CullMode: D3D12_CULL_MODE_NONE,
FrontCounterClockwise: true.into(),
DepthBias: 0,
DepthBiasClamp: 0.0,
SlopeScaledDepthBias: 0.0,
DepthClipEnable: true.into(),
..Default::default()
},
DepthStencilState: D3D12_DEPTH_STENCIL_DESC {
DepthEnable: true.into(),
DepthWriteMask: D3D12_DEPTH_WRITE_MASK_ALL,
DepthFunc: D3D12_COMPARISON_FUNC_LESS,
StencilEnable: false.into(),
..Default::default()
},
BlendState: D3D12_BLEND_DESC {
RenderTarget: {
let mut arr = [D3D12_RENDER_TARGET_BLEND_DESC::default(); 8];
arr[0] = D3D12_RENDER_TARGET_BLEND_DESC {
BlendEnable: false.into(),
RenderTargetWriteMask: D3D12_COLOR_WRITE_ENABLE_ALL.0 as u8,
..Default::default()
};
arr
},
..Default::default()
},
..Default::default()
};
unsafe { crate::directx::pso_library::create_graphics(device, &pso_desc) }
.map_err(|e| map_pso_hresult(e.code(), "create main PSO"))
}
pub(in crate::directx) fn create_shadow_pso(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
vs: &[u8],
) -> RenderResult<ID3D12PipelineState> {
let layout = main_input_layout();
let pso_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC {
pRootSignature: com::borrowed(root_sig),
VS: D3D12_SHADER_BYTECODE {
pShaderBytecode: vs.as_ptr() as _,
BytecodeLength: vs.len(),
},
InputLayout: D3D12_INPUT_LAYOUT_DESC {
pInputElementDescs: layout.as_ptr(),
NumElements: layout.len() as u32,
},
PrimitiveTopologyType: D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets: 0,
DSVFormat: DXGI_FORMAT_D32_FLOAT,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
SampleMask: u32::MAX,
RasterizerState: D3D12_RASTERIZER_DESC {
FillMode: D3D12_FILL_MODE_SOLID,
CullMode: D3D12_CULL_MODE_NONE,
FrontCounterClockwise: true.into(),
DepthBias: shadow_bias::RASTER_CONSTANT as i32,
DepthBiasClamp: shadow_bias::RASTER_CLAMP,
SlopeScaledDepthBias: shadow_bias::RASTER_SLOPE,
DepthClipEnable: true.into(),
..Default::default()
},
DepthStencilState: D3D12_DEPTH_STENCIL_DESC {
DepthEnable: true.into(),
DepthWriteMask: D3D12_DEPTH_WRITE_MASK_ALL,
DepthFunc: D3D12_COMPARISON_FUNC_LESS,
StencilEnable: false.into(),
..Default::default()
},
BlendState: D3D12_BLEND_DESC {
..Default::default()
},
..Default::default()
};
unsafe { crate::directx::pso_library::create_graphics(device, &pso_desc) }
.map_err(|e| map_pso_hresult(e.code(), "create shadow PSO"))
}
pub(in crate::directx) struct BindlessMainShaders {
pub vs: Vec<u8>,
pub ps: Vec<u8>,
}
pub(in crate::directx) fn build_bucket_pipeline(
device: &ID3D12Device,
info_queue: Option<&ID3D12InfoQueue>,
targets: BucketPipelineTargets<'_>,
bucket: usize,
shader: backend_init::WorldShader<'_>,
) -> RenderResult<ID3D12PipelineState> {
let (vs, ps) = match shader.programs {
Some(programs) => (
world_entry(programs, "vertex_main_bindless", targets.hot_reload)?,
world_entry(programs, "fragment_main_bindless", targets.hot_reload)?,
),
None => (
targets.engine_default.vs.clone(),
targets.engine_default.ps.clone(),
),
};
if vs.is_empty() || ps.is_empty() {
return Err(RenderError::ShaderCompile(format!(
"shader bucket {bucket} carries no vertex/fragment bytecode"
)));
}
dump_on_err(
info_queue,
create_main_pso(
device,
targets.root_sig,
&vs,
&ps,
HDR_FORMAT,
targets.msaa_samples,
),
)
.map_err(|e| e.context(format!("shader bucket {bucket}")))
}
#[derive(Clone, Copy)]
pub(in crate::directx) struct BucketPipelineTargets<'a> {
pub root_sig: &'a ID3D12RootSignature,
pub msaa_samples: u32,
pub engine_default: &'a BindlessMainShaders,
pub hot_reload: bool,
}
pub(super) fn build_world_pipeline_table(
device: &ID3D12Device,
info_queue: Option<&ID3D12InfoQueue>,
targets: BucketPipelineTargets<'_>,
bucket_shaders: &[backend_init::WorldShader<'_>],
) -> RenderResult<Vec<Option<ID3D12PipelineState>>> {
let mut table = Vec::with_capacity(bucket_shaders.len());
for (i, shader) in bucket_shaders.iter().enumerate() {
let bucket = i + 1;
if shader.deferred {
table.push(None);
continue;
}
table.push(Some(build_bucket_pipeline(
device, info_queue, targets, bucket, *shader,
)?));
}
Ok(table)
}
#[cfg(test)]
mod tests {
#[test]
fn bindless_main_shaders_compile() {
if !concinnity_shader::dxc_available() {
return;
}
super::compile_main_bindless_shaders(false).expect("bindless main shaders must compile");
}
}