use ash::vk;
use concinnity_core::gfx::render_types::{self, InstancedCluster, ShadowUniforms};
use concinnity_core::render::error::RenderResult;
use super::InitGpu;
use super::cull::CullPlan;
use crate::vulkan::context::{VkDescriptors, VkHardware, VkShadow};
use crate::vulkan::descriptor_layout::{
PoolSizes, StageDescriptors, global_set, shadow_global_set,
};
use crate::vulkan::global_set::GlobalBindings;
use crate::vulkan::owned::{OwnedDescriptorPool, OwnedSetLayout};
use crate::vulkan::resources::{alloc_descriptor_sets, create_descriptor_set_layout};
use crate::vulkan::set_writes::SetWrites;
pub(super) fn stage_limits(hw: &VkHardware) -> StageDescriptors {
let properties = unsafe {
hw.instance
.get_physical_device_properties(hw.physical_device)
};
crate::vulkan::descriptor_layout::stage_limits(&properties.limits)
}
pub(super) struct SetPoolInputs<'a> {
pub(super) instanced_clusters: &'a [InstancedCluster],
pub(super) text_atlas_count: usize,
pub(super) plan: &'a CullPlan,
}
pub(super) fn build_descriptors(
gpu: &InitGpu<'_>,
pool: SetPoolInputs<'_>,
bindings: &GlobalBindings<'_>,
) -> RenderResult<VkDescriptors> {
let global_set_layout = create_descriptor_set_layout(&gpu.hw.device, &global_set())?;
let shadow_views = render_types::NUM_SHADOW_CASCADES as u32 + bindings.spot_shadow.count();
let descriptor_pool = create_descriptor_pool(gpu, pool, bindings.shadow, shadow_views)?;
let global_sets = write_global_sets(gpu, &global_set_layout, &descriptor_pool, bindings)?;
let shadow_global_sets = write_shadow_global_sets(gpu, &descriptor_pool, bindings.shadow)?;
Ok(VkDescriptors {
global_set_layout,
descriptor_pool,
global_sets,
shadow_global_sets,
})
}
fn create_descriptor_pool(
gpu: &InitGpu<'_>,
pool: SetPoolInputs<'_>,
shadow: &VkShadow,
shadow_views: u32,
) -> RenderResult<OwnedDescriptorPool> {
let InitGpu { hw, frames, .. } = *gpu;
let SetPoolInputs {
instanced_clusters,
text_atlas_count,
plan,
} = pool;
let CullPlan {
bindless_active,
bindless_pool_size,
bindless_uab,
..
} = *plan;
let n_cluster = instanced_clusters.len() as u32;
let n_atlas = text_atlas_count.max(1) as u32;
let n_frames = frames as u32;
let bindless_sets_count = if bindless_active { n_frames } else { 0 };
let gbuffer_sets_count = if bindless_active { n_frames } else { 0 };
let history_sets_count = gbuffer_sets_count * n_frames;
let shadow_cull_set_count = if bindless_active && shadow.enabled() {
n_frames * shadow_views
} else {
0
};
let pool_sizes = PoolSizes::default()
.sets(&global_set(), n_frames)
.sets(&shadow_global_set(), n_frames)
.add(
vk::DescriptorType::UNIFORM_BUFFER,
gbuffer_sets_count + history_sets_count,
)
.add(
vk::DescriptorType::SAMPLED_IMAGE,
n_atlas
+ n_frames * super::composite::COMPOSITE_SOURCES
+ bindless_pool_size as u32 * bindless_sets_count,
)
.add(
vk::DescriptorType::SAMPLER,
n_atlas + n_frames * super::composite::COMPOSITE_SOURCES,
)
.add(
vk::DescriptorType::STORAGE_BUFFER,
n_cluster * n_frames
+ 2 * bindless_sets_count
+ 4 * bindless_sets_count
+ 3 * shadow_cull_set_count
+ 2 * gbuffer_sets_count
+ 2 * history_sets_count,
)
.build();
let total_sets = n_frames
+ n_frames
+ n_atlas
+ n_frames * n_cluster
+ n_frames
+ bindless_sets_count
+ bindless_sets_count
+ shadow_cull_set_count
+ gbuffer_sets_count
+ history_sets_count;
let mut pool_info = vk::DescriptorPoolCreateInfo::default()
.pool_sizes(&pool_sizes)
.max_sets(total_sets);
if bindless_uab {
pool_info = pool_info.flags(vk::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND);
}
hw.device
.create_descriptor_pool(&pool_info)
.map_err(|e| crate::vulkan::error::map_vk_result(e, "descriptor pool"))
}
fn write_global_sets(
gpu: &InitGpu<'_>,
layout: &OwnedSetLayout,
pool: &OwnedDescriptorPool,
bindings: &GlobalBindings<'_>,
) -> RenderResult<Vec<vk::DescriptorSet>> {
let InitGpu { hw, frames, .. } = *gpu;
let layouts = vec![layout.handle(); frames];
let global_sets = alloc_descriptor_sets(&hw.device, pool.handle(), &layouts)?;
for (i, &set) in global_sets.iter().enumerate() {
bindings.frame(i).write(&hw.device, set);
}
Ok(global_sets)
}
fn write_shadow_global_sets(
gpu: &InitGpu<'_>,
pool: &OwnedDescriptorPool,
shadow: &VkShadow,
) -> RenderResult<Vec<vk::DescriptorSet>> {
let InitGpu { hw, frames, .. } = *gpu;
let device = &hw.device;
let layout = shadow.global_set_layout.handle();
let shadow_global_layouts: Vec<_> = (0..frames).map(|_| layout).collect();
let shadow_global_sets = alloc_descriptor_sets(device, pool.handle(), &shadow_global_layouts)?;
let shadow_ubo_size = std::mem::size_of::<ShadowUniforms>() as u64;
for (&set, ubo) in shadow_global_sets.iter().zip(&shadow.ubos) {
SetWrites::new(set)
.uniform_buffer(0, ubo.buffer(), shadow_ubo_size)
.apply(device);
}
Ok(shadow_global_sets)
}