use ash::vk;
use concinnity_core::gfx::render_types::{GpuMaterialParams, MATERIAL_PARAM_COUNT};
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::material_params::MaterialParamTable;
use super::allocator::{DeviceAllocator, PooledBuffer};
use super::context::VkContext;
pub(in crate::vulkan) const MATERIAL_PARAMS_BINDING: u32 = 2;
pub(in crate::vulkan) struct VkMaterialParams {
table: MaterialParamTable,
buffers: Vec<PooledBuffer>,
}
impl VkMaterialParams {
pub(in crate::vulkan) fn new(
alloc: &DeviceAllocator,
rows: Vec<GpuMaterialParams>,
frames: usize,
) -> RenderResult<Self> {
let table = MaterialParamTable::new(rows, frames);
let buffers = (0..frames)
.map(|_| host_buffer(alloc, table.byte_len()))
.collect::<RenderResult<Vec<_>>>()?;
Ok(Self { table, buffers })
}
pub(in crate::vulkan) fn set(&mut self, row: u32, params: [f32; MATERIAL_PARAM_COUNT]) {
self.table.set(row, params);
}
pub(in crate::vulkan) fn upload(&mut self, frame: usize) {
let Some(buf) = self.buffers.get(frame) else {
return;
};
if let Some(rows) = self.table.take_upload(frame) {
buf.write_slice(0, rows);
}
}
pub(in crate::vulkan) fn descriptor(&self, frame: usize) -> vk::DescriptorBufferInfo {
vk::DescriptorBufferInfo::default()
.buffer(self.buffers[frame].buffer())
.offset(0)
.range(self.table.byte_len() as u64)
}
pub(in crate::vulkan) fn snapshot(
&self,
alloc: &DeviceAllocator,
) -> RenderResult<PooledBuffer> {
let buf = host_buffer(alloc, self.table.byte_len())?;
buf.write_slice(0, self.table.rows());
Ok(buf)
}
}
fn host_buffer(alloc: &DeviceAllocator, size: usize) -> RenderResult<PooledBuffer> {
alloc.create_buffer(
size as u64,
vk::BufferUsageFlags::STORAGE_BUFFER,
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
)
}
impl VkContext {
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);
}
}
}