use ash::vk;
use crate::vulkan::owned::{OwnedSetLayout, VkDevice};
use super::allocator::{DeviceAllocator, PooledBuffer};
use super::texture;
mod geometry;
mod geometry_rebuild;
mod skinning;
mod streaming;
mod textures;
pub(in crate::vulkan) fn create_descriptor_set_layout(
device: &VkDevice,
bindings: &[(u32, vk::DescriptorType, vk::ShaderStageFlags)],
) -> Result<OwnedSetLayout, String> {
let vk_bindings: Vec<_> = bindings
.iter()
.map(|&(b, ty, stage)| {
vk::DescriptorSetLayoutBinding::default()
.binding(b)
.descriptor_type(ty)
.descriptor_count(1)
.stage_flags(stage)
})
.collect();
let info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&vk_bindings);
device
.create_descriptor_set_layout(&info)
.map_err(|e| format!("descriptor set layout: {e}"))
}
pub(in crate::vulkan) fn alloc_descriptor_sets(
device: &VkDevice,
pool: vk::DescriptorPool,
layouts: &[vk::DescriptorSetLayout],
) -> Result<Vec<vk::DescriptorSet>, String> {
if layouts.is_empty() {
return Ok(vec![]);
}
let alloc = vk::DescriptorSetAllocateInfo::default()
.descriptor_pool(pool)
.set_layouts(layouts);
unsafe { device.allocate_descriptor_sets(&alloc) }
.map_err(|e| format!("allocate descriptor sets: {e}"))
}
pub(in crate::vulkan) fn shared_geometry_usage(rt_capable: bool) -> vk::BufferUsageFlags {
let base = vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::TRANSFER_DST;
if rt_capable {
base | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS
| vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR
| vk::BufferUsageFlags::STORAGE_BUFFER
} else {
base
}
}
pub(in crate::vulkan) fn upload_geometry_buffer<T: bytemuck::NoUninit>(
alloc: &DeviceAllocator,
device: &VkDevice,
command_pool: vk::CommandPool,
queue: vk::Queue,
data: &[T],
usage: vk::BufferUsageFlags,
) -> Result<PooledBuffer, String> {
upload_geometry_buffer_raw(
alloc,
device,
command_pool,
queue,
bytemuck::cast_slice(data),
usage,
)
}
pub(in crate::vulkan) fn upload_geometry_buffer_raw(
alloc: &DeviceAllocator,
device: &VkDevice,
command_pool: vk::CommandPool,
queue: vk::Queue,
data: &[u8],
usage: vk::BufferUsageFlags,
) -> Result<PooledBuffer, String> {
let usage = usage | vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::TRANSFER_DST;
let size = data.len() as u64;
if size == 0 {
return Ok(alloc.create_buffer(4, usage, vk::MemoryPropertyFlags::DEVICE_LOCAL)?);
}
let staging = alloc.create_buffer(
size,
vk::BufferUsageFlags::TRANSFER_SRC,
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
)?;
staging.write_bytes(0, data);
let buf = alloc.create_buffer(size, usage, vk::MemoryPropertyFlags::DEVICE_LOCAL)?;
texture::one_shot_submit(device, command_pool, queue, |cmd| {
let copy = vk::BufferCopy::default().size(size);
unsafe {
device.cmd_copy_buffer(
cmd,
staging.buffer(),
buf.buffer(),
std::slice::from_ref(©),
)
};
})?;
Ok(buf)
}