use concinnity_core::gfx::render_types::{GpuMaterialParams, MATERIAL_PARAM_COUNT};
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::material_params::MaterialParamTable;
use windows::Win32::Graphics::Direct3D12::*;
use super::allocator::{DeviceAllocator, PooledBuffer};
use super::com;
use super::context::DxContext;
use super::error::map_hresult;
pub(in crate::directx) const MATERIAL_PARAMS_ROOT_PARAM: u32 = 20;
struct MappedCopy {
buffer: PooledBuffer,
ptr: *mut u8,
}
pub(in crate::directx) struct DxMaterialParams {
table: MaterialParamTable,
copies: Vec<MappedCopy>,
}
impl DxMaterialParams {
pub(in crate::directx) fn new(
alloc: &DeviceAllocator,
rows: Vec<GpuMaterialParams>,
slots: usize,
) -> RenderResult<Self> {
let table = MaterialParamTable::new(rows, slots);
let copies = (0..slots)
.map(|_| {
let buffer = alloc.alloc_buffer(
table.byte_len() as u64,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
let mut ptr = std::ptr::null_mut::<std::ffi::c_void>();
unsafe { buffer.Map(0, None, Some(&mut ptr)) }
.map_err(|e| map_hresult(e.code(), "map material parameter table"))?;
Ok(MappedCopy {
buffer,
ptr: ptr.cast(),
})
})
.collect::<RenderResult<Vec<_>>>()?;
Ok(Self { table, copies })
}
pub(in crate::directx) fn set(&mut self, row: u32, params: [f32; MATERIAL_PARAM_COUNT]) {
self.table.set(row, params);
}
pub(in crate::directx) fn upload(&mut self, slot: usize) {
let Some(copy) = self.copies.get(slot) else {
return;
};
if let Some(rows) = self.table.take_upload(slot) {
let bytes = std::mem::size_of_val(rows);
unsafe {
std::ptr::copy_nonoverlapping(rows.as_ptr().cast::<u8>(), copy.ptr, bytes);
}
}
}
pub(in crate::directx) fn gpu_va(&self, slot: usize) -> u64 {
com::gpu_va(&self.copies[slot].buffer)
}
}
impl DxContext {
pub(super) fn set_material_params(&mut self, row: u32, params: [f32; MATERIAL_PARAM_COUNT]) {
if let Some(table) = self.cull.material_params.as_mut() {
table.set(row, params);
}
}
pub(super) fn material_params_gva(&self, slot: usize) -> u64 {
self.cull
.material_params
.as_ref()
.map_or(0, |table| table.gpu_va(slot))
}
}