use concinnity_core::gfx::render_types;
use concinnity_core::render::backend_init::WorldShader;
use concinnity_core::render::error::{RenderError, RenderResult};
use windows::Win32::Graphics::Direct3D12::*;
use super::CullPlan;
use crate::directx::allocator::PooledBuffer;
use crate::directx::context::{FRAMES, align256, dump_on_err};
use crate::directx::error::map_hresult;
use crate::directx::init::InitGpu;
use crate::directx::init::pipelines::{
BindlessMainShaders, BucketPipelineTargets, build_bucket_pipeline, build_world_pipeline_table,
compile_main_bindless_shaders, create_main_bindless_root_signature,
};
pub(super) struct BindlessPass {
pub(super) root_sig: ID3D12RootSignature,
pub(super) pso: ID3D12PipelineState,
pub(super) world_pipelines: Vec<Option<ID3D12PipelineState>>,
pub(super) shaders: BindlessMainShaders,
pub(super) object_buffers: Vec<PooledBuffer>,
pub(super) object_ptrs: Vec<*mut u8>,
}
pub(super) fn build_bindless_pass(
gpu: &InitGpu<'_>,
world_shaders: &[WorldShader<'_>],
plan: &CullPlan,
msaa_samples: u32,
) -> RenderResult<BindlessPass> {
let device = gpu.hw.alloc.device();
let info_queue = gpu.hw.info_queue.as_ref();
let hot_reload = gpu.hot_reload;
let n_cull = plan.n_cull;
let world_default = world_shaders
.first()
.copied()
.ok_or_else(|| RenderError::Other("BackendInit carried no shaders".to_string()))?;
let bucket_shaders = world_shaders.get(1..).unwrap_or(&[]);
let (bvs, bps) = compile_main_bindless_shaders(hot_reload)?;
let bindless_main_shaders = BindlessMainShaders { vs: bvs, ps: bps };
let brs = dump_on_err(info_queue, create_main_bindless_root_signature(device))?;
let targets = BucketPipelineTargets {
root_sig: &brs,
msaa_samples,
engine_default: &bindless_main_shaders,
hot_reload,
};
let main_pso = build_bucket_pipeline(device, info_queue, targets, 0, world_default)?;
let world_pipelines = if bucket_shaders.is_empty() {
Vec::new()
} else {
let max = render_types::MAX_SHADER_BUCKETS;
if bucket_shaders.len() + 1 > max {
return Err(RenderError::Other(format!(
"world declares {} Shaders but at most {max} can be routed",
bucket_shaders.len() + 1
)));
}
build_world_pipeline_table(device, info_queue, targets, bucket_shaders)?
};
let mut object_buffers: Vec<PooledBuffer> = Vec::new();
let mut object_ptrs: Vec<*mut u8> = Vec::new();
if n_cull > 0 {
let object_buffer_size =
align256((n_cull * std::mem::size_of::<render_types::GpuObjectData>()) as u64);
for _ in 0..FRAMES + 1 {
let buf = gpu.hw.alloc.alloc_buffer(
object_buffer_size,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
let mut ptr = std::ptr::null_mut::<std::ffi::c_void>();
unsafe { buf.Map(0, None, Some(&mut ptr)) }
.map_err(|e| map_hresult(e.code(), "map object buffer"))?;
object_ptrs.push(ptr as *mut u8);
object_buffers.push(buf);
}
}
Ok(BindlessPass {
root_sig: brs,
pso: main_pso,
world_pipelines,
shaders: bindless_main_shaders,
object_buffers,
object_ptrs,
})
}