use ash::vk;
use concinnity_core::render::error::RenderResult;
use super::gbuffer::{GBUFFER_VIEW_UBO_SIZE, PREPASS_TARGETS};
use crate::vulkan::allocator::PooledBuffer;
use crate::vulkan::builtin_shaders::{self, CompileProgram};
use crate::vulkan::descriptor_layout::{Binding, PoolSizes};
use crate::vulkan::owned::{
OwnedDescriptorPool, OwnedPipeline, OwnedPipelineLayout, OwnedSetLayout, VkDevice,
};
use crate::vulkan::pipeline_desc::{Depth, GraphicsPipelineDesc};
use crate::vulkan::resources::{alloc_descriptor_sets, create_descriptor_set_layout};
use crate::vulkan::set_writes::SetWrites;
const VIEW_SET: [Binding; 1] = [(
0,
vk::DescriptorType::UNIFORM_BUFFER,
vk::ShaderStageFlags::VERTEX,
)];
pub(in crate::vulkan) struct GbufferSky {
_pool: OwnedDescriptorPool,
_set_layout: OwnedSetLayout,
layout: OwnedPipelineLayout,
pipeline: OwnedPipeline,
sets: Vec<vk::DescriptorSet>,
}
impl GbufferSky {
pub(in crate::vulkan) fn build(
device: &VkDevice,
render_pass: vk::RenderPass,
view_ubos: &[PooledBuffer],
hot_reload: bool,
) -> RenderResult<Self> {
let frames = view_ubos.len() as u32;
let sizes = PoolSizes::default().sets(&VIEW_SET, frames).build();
let pool = device
.create_descriptor_pool(
&vk::DescriptorPoolCreateInfo::default()
.max_sets(frames)
.pool_sizes(&sizes),
)
.map_err(|e| crate::vulkan::error::map_vk_result(e, "gbuffer sky descriptor pool"))?;
let set_layout = create_descriptor_set_layout(device, &VIEW_SET)?;
let layouts = [set_layout.handle()];
let layout = device
.create_pipeline_layout(&vk::PipelineLayoutCreateInfo::default().set_layouts(&layouts))
.map_err(|e| crate::vulkan::error::map_vk_result(e, "gbuffer sky pipeline layout"))?;
let set_layouts = vec![set_layout.handle(); view_ubos.len()];
let sets = alloc_descriptor_sets(device, pool.handle(), &set_layouts)?;
for (&set, ubo) in sets.iter().zip(view_ubos) {
SetWrites::new(set)
.uniform_buffer(0, ubo.buffer(), GBUFFER_VIEW_UBO_SIZE)
.apply(device);
}
let pipeline = Self::build_pipeline(device, layout.handle(), render_pass, hot_reload)?;
Ok(Self {
_pool: pool,
_set_layout: set_layout,
layout,
pipeline,
sets,
})
}
fn build_pipeline(
device: &VkDevice,
layout: vk::PipelineLayout,
render_pass: vk::RenderPass,
hot_reload: bool,
) -> RenderResult<OwnedPipeline> {
let vs = builtin_shaders::GBUFFER_SKY_VERT.compile(hot_reload)?;
let fs = builtin_shaders::GBUFFER_SKY_FRAG.compile(hot_reload)?;
GraphicsPipelineDesc {
depth: Depth::read_only(),
..GraphicsPipelineDesc::fullscreen(&vs, &fs, layout, render_pass, &PREPASS_TARGETS)
}
.build(device, "gbuffer sky")
}
pub(in crate::vulkan) fn rebuild_pipeline(
&self,
device: &VkDevice,
render_pass: vk::RenderPass,
) -> RenderResult<OwnedPipeline> {
Self::build_pipeline(device, self.layout.handle(), render_pass, true)
}
pub(in crate::vulkan) fn swap_pipeline(&mut self, pipeline: OwnedPipeline) {
self.pipeline = pipeline;
}
pub(in crate::vulkan) fn encode(
&self,
device: &VkDevice,
cmd: vk::CommandBuffer,
frame_idx: usize,
) {
let Some(&set) = self.sets.get(frame_idx) else {
return;
};
unsafe {
device.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, self.pipeline.handle());
device.cmd_bind_descriptor_sets(
cmd,
vk::PipelineBindPoint::GRAPHICS,
self.layout.handle(),
0,
&[set],
&[],
);
device.cmd_draw(cmd, 3, 1, 0, 0);
}
}
}