Use RenderTarget instead of RenderPass directly

This commit is contained in:
hodasemi 2023-01-21 14:14:43 +01:00
parent bc2f1cd7c9
commit 6336ec3e64
2 changed files with 181 additions and 196 deletions

View file

@ -54,6 +54,16 @@ impl<T> TargetMode<T> {
TargetMode::Stereo(l, r) => (l, r), TargetMode::Stereo(l, r) => (l, r),
} }
} }
pub fn execute<F, R>(&self, mut f: F) -> anyhow::Result<TargetMode<R>>
where
F: FnMut(&T) -> anyhow::Result<R>,
{
Ok(match self {
TargetMode::Mono(s) => TargetMode::Mono(f(s)?),
TargetMode::Stereo(l, r) => TargetMode::Stereo(f(l)?, f(r)?),
})
}
} }
impl<T: Clone> Clone for TargetMode<T> { impl<T: Clone> Clone for TargetMode<T> {
@ -64,3 +74,15 @@ impl<T: Clone> Clone for TargetMode<T> {
} }
} }
} }
impl<T> From<T> for TargetMode<T> {
fn from(value: T) -> Self {
TargetMode::Mono(value)
}
}
impl<T> From<(T, T)> for TargetMode<T> {
fn from((lhs, rhs): (T, T)) -> Self {
TargetMode::Stereo(lhs, rhs)
}
}

View file

@ -72,7 +72,6 @@ impl<'a> GuiHandlerCreateInfo<'a> {
struct GuiSeparator { struct GuiSeparator {
_descriptor_layout: Arc<DescriptorSetLayout>, _descriptor_layout: Arc<DescriptorSetLayout>,
_pipeline_layout: Arc<PipelineLayout>,
_pipeline: Arc<Pipeline>, _pipeline: Arc<Pipeline>,
} }
@ -111,13 +110,12 @@ pub struct GuiHandler {
top_ui: RwLock<Option<Arc<dyn TopGui>>>, top_ui: RwLock<Option<Arc<dyn TopGui>>>,
tooltip_ui: RwLock<Option<Arc<dyn TopGui>>>, tooltip_ui: RwLock<Option<Arc<dyn TopGui>>>,
render_pass: Arc<RenderPass>, render_targets: TargetMode<RwLock<RenderTarget>>,
framebuffers: Mutex<TargetMode<Vec<Arc<Framebuffer>>>>,
command_buffers: TargetMode<Vec<CommandBufferState>>, command_buffers: TargetMode<Vec<CommandBufferState>>,
text_objects: GuiSeparator, text_objects: TargetMode<GuiSeparator>,
rectangle_objects: GuiSeparator, rectangle_objects: TargetMode<GuiSeparator>,
single_color_objects: GuiSeparator, single_color_objects: TargetMode<GuiSeparator>,
_bitmap_font: Arc<Image>, _bitmap_font: Arc<Image>,
_bitmap_desc_pool: Arc<DescriptorPool>, _bitmap_desc_pool: Arc<DescriptorPool>,
@ -183,18 +181,25 @@ impl GuiHandler {
} }
}; };
let render_pass = // let render_pass =
Self::create_render_pass(device, context.format(), context.image_layout())?; // Self::create_render_pass(device, context.format(), context.image_layout())?;
let framebuffers = Self::create_framebuffers(device, &context.images(), &render_pass)?; // let framebuffers = Self::create_framebuffers(device, &context.images(), &render_pass)?;
let (text_objs, color_layout) = Self::init_text_objects(device, &render_pass)?; let render_targets = Self::create_render_targets(device, &context.images())?;
let rect_objs = Self::init_rectangle_objects(device, &render_pass)?;
let single_color_objects = Self::init_single_color_objects(device, &render_pass)?; let (text_objs, color_layout) = Self::init_text_objects(device, &render_targets)?;
let rect_objs = Self::init_rectangle_objects(device, &render_targets)?;
let single_color_objects = Self::init_single_color_objects(device, &render_targets)?;
let (bitmap_texture, bitmap_desc_pool, bitmap_desc_set) = Self::init_bitmap_font( let (bitmap_texture, bitmap_desc_pool, bitmap_desc_set) = Self::init_bitmap_font(
device, device,
queue, queue,
text_objs._descriptor_layout.clone(), match &text_objs {
TargetMode::Mono(l) => l,
TargetMode::Stereo(l, _) => l,
}
._descriptor_layout
.clone(),
gui_handler_create_info.font.clone(), gui_handler_create_info.font.clone(),
)?; )?;
@ -252,8 +257,7 @@ impl GuiHandler {
top_ui: RwLock::new(None), top_ui: RwLock::new(None),
tooltip_ui: RwLock::new(None), tooltip_ui: RwLock::new(None),
render_pass, render_targets,
framebuffers: Mutex::new(framebuffers),
command_buffers, command_buffers,
text_objects: text_objs, text_objects: text_objs,
@ -382,6 +386,14 @@ impl GuiHandler {
} }
} }
fn text_desc_layout(&self) -> &Arc<DescriptorSetLayout> {
&match &self.text_objects {
TargetMode::Mono(l) => l,
TargetMode::Stereo(l, _) => l,
}
._descriptor_layout
}
pub(crate) fn image_descriptor(&self, mut path: AssetPath) -> Result<Arc<DescriptorSet>> { pub(crate) fn image_descriptor(&self, mut path: AssetPath) -> Result<Arc<DescriptorSet>> {
if !path.has_prefix() { if !path.has_prefix() {
path.set_prefix(&self.resource_base_path.full_path()); path.set_prefix(&self.resource_base_path.full_path());
@ -398,7 +410,7 @@ impl GuiHandler {
.build(&self.device, &self.queue)?; .build(&self.device, &self.queue)?;
let desc_pool = DescriptorPool::builder() let desc_pool = DescriptorPool::builder()
.set_layout(self.text_objects._descriptor_layout.clone()) .set_layout(self.text_desc_layout().clone())
.build(self.device.clone())?; .build(self.device.clone())?;
let descriptor_set = DescriptorPool::prepare_set(&desc_pool).allocate()?; let descriptor_set = DescriptorPool::prepare_set(&desc_pool).allocate()?;
@ -761,17 +773,15 @@ impl GuiHandler {
fn render( fn render(
&self, &self,
command_buffer_state: &CommandBufferState, command_buffer_state: &CommandBufferState,
framebuffer: &Arc<Framebuffer>, render_target: &RenderTarget,
single_color_objects: &GuiSeparator,
rectangle_objects: &GuiSeparator,
text_objects: &GuiSeparator,
) -> Result<()> { ) -> Result<()> {
if !command_buffer_state.valid.load(SeqCst) { if !command_buffer_state.valid.load(SeqCst) {
let gui_command_buffer = &command_buffer_state.command_buffer; let gui_command_buffer = &command_buffer_state.command_buffer;
let inheritance_info = CommandBuffer::inheritance_info( let inheritance_info = render_target.inheritance_info();
Some(&self.render_pass),
Some(0),
Some(framebuffer),
None,
);
let mut command_buffer_begin_info = VkCommandBufferBeginInfo::new( let mut command_buffer_begin_info = VkCommandBufferBeginInfo::new(
VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
@ -802,7 +812,7 @@ impl GuiHandler {
for (_, elements) in layers.iter() { for (_, elements) in layers.iter() {
if !elements.is_colorables_empty() { if !elements.is_colorables_empty() {
buffer_recorder.bind_pipeline(&self.single_color_objects._pipeline)?; buffer_recorder.bind_pipeline(&single_color_objects._pipeline)?;
buffer_recorder.set_scissor(&scissor); buffer_recorder.set_scissor(&scissor);
buffer_recorder.set_viewport(&viewport); buffer_recorder.set_viewport(&viewport);
@ -819,7 +829,7 @@ impl GuiHandler {
} }
if !elements.is_displayables_empty() || !elements.is_iconizables_empty() { if !elements.is_displayables_empty() || !elements.is_iconizables_empty() {
buffer_recorder.bind_pipeline(&self.rectangle_objects._pipeline)?; buffer_recorder.bind_pipeline(&rectangle_objects._pipeline)?;
buffer_recorder.set_scissor(&scissor); buffer_recorder.set_scissor(&scissor);
buffer_recorder.set_viewport(&viewport); buffer_recorder.set_viewport(&viewport);
@ -846,7 +856,7 @@ impl GuiHandler {
} }
if !elements.is_textables_empty() { if !elements.is_textables_empty() {
buffer_recorder.bind_pipeline(&self.text_objects._pipeline)?; buffer_recorder.bind_pipeline(&text_objects._pipeline)?;
buffer_recorder.set_scissor(&scissor); buffer_recorder.set_scissor(&scissor);
buffer_recorder.set_viewport(&viewport); buffer_recorder.set_viewport(&viewport);
@ -1139,113 +1149,27 @@ impl GuiHandler {
// private // private
impl GuiHandler { impl GuiHandler {
/// Creates a simple render pass for gui rendering fn create_render_targets(
/// Only color framebuffer is attached
fn create_render_pass(
device: &Arc<Device>,
final_format: VkFormat,
target_layout: VkImageLayout,
) -> Result<Arc<RenderPass>> {
let target_reference = VkAttachmentReference {
attachment: 0,
layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
};
let subpass_descriptions = [VkSubpassDescription::new(
0,
&[],
slice::from_ref(&target_reference),
&[],
None,
&[],
)];
let attachments = [VkAttachmentDescription::new(
0,
final_format,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
target_layout,
target_layout,
)];
let src_access = Image::src_layout_to_access(target_layout);
let dst_access = Image::dst_layout_to_access(target_layout);
let render_pass_image_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
let dependencies = [
VkSubpassDependency::new(
VK_SUBPASS_EXTERNAL,
0,
CommandBuffer::access_to_stage(src_access),
CommandBuffer::access_to_stage(render_pass_image_access),
src_access,
render_pass_image_access,
VK_DEPENDENCY_BY_REGION_BIT,
),
VkSubpassDependency::new(
0,
VK_SUBPASS_EXTERNAL,
CommandBuffer::access_to_stage(render_pass_image_access),
CommandBuffer::access_to_stage(dst_access),
render_pass_image_access,
dst_access,
VK_DEPENDENCY_BY_REGION_BIT,
),
];
let renderpass = RenderPass::new(
device.clone(),
&subpass_descriptions,
&attachments,
&dependencies,
)?;
Ok(renderpass)
}
fn create_framebuffers(
device: &Arc<Device>, device: &Arc<Device>,
target_images: &TargetMode<Vec<Arc<Image>>>, target_images: &TargetMode<Vec<Arc<Image>>>,
render_pass: &Arc<RenderPass>, ) -> Result<TargetMode<RwLock<RenderTarget>>> {
) -> Result<TargetMode<Vec<Arc<Framebuffer>>>> { let create = |target_images: &Vec<Arc<Image>>| -> Result<RenderTarget> {
// closure to create array of framebuffer from array of images RenderTarget::builder()
let create_framebuffer = |device: &Arc<Device>, .add_sub_pass(
images: &Vec<Arc<Image>>, SubPass::builder(target_images[0].width(), target_images[0].height())
render_pass: &Arc<RenderPass>| .set_prepared_targets(target_images, 0, [0.0, 0.0, 0.0, 0.0], false)
-> Result<Vec<Arc<Framebuffer>>> { .build(device)?,
let mut framebuffers = Vec::with_capacity(images.len());
for image in images.iter() {
Image::convert_layout(image, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)?;
framebuffers.push(
Framebuffer::builder()
.set_render_pass(render_pass)
.add_attachment(image)
.build(device.clone())?,
) )
} .build(device)
Ok(framebuffers)
}; };
match target_images { Ok(match target_images {
TargetMode::Mono(images) => { TargetMode::Mono(images) => TargetMode::Mono(RwLock::new(create(images)?)),
let framebuffers = create_framebuffer(device, images, render_pass)?; TargetMode::Stereo(left_images, right_images) => TargetMode::Stereo(
RwLock::new(create(left_images)?),
Ok(TargetMode::Mono(framebuffers)) RwLock::new(create(right_images)?),
} ),
TargetMode::Stereo(left_images, right_images) => { })
let left_framebuffers = create_framebuffer(device, left_images, render_pass)?;
let right_framebuffers = create_framebuffer(device, right_images, render_pass)?;
Ok(TargetMode::Stereo(left_framebuffers, right_framebuffers))
}
}
} }
fn create_command_buffers( fn create_command_buffers(
@ -1295,8 +1219,8 @@ impl GuiHandler {
fn init_text_objects( fn init_text_objects(
device: &Arc<Device>, device: &Arc<Device>,
render_pass: &Arc<RenderPass>, render_targets: &TargetMode<RwLock<RenderTarget>>,
) -> Result<(GuiSeparator, Arc<DescriptorSetLayout>)> { ) -> Result<(TargetMode<GuiSeparator>, Arc<DescriptorSetLayout>)> {
// --- layout creation --- // --- layout creation ---
let descriptor_layout = DescriptorSetLayout::builder() let descriptor_layout = DescriptorSetLayout::builder()
.add_layout_binding( .add_layout_binding(
@ -1332,31 +1256,30 @@ impl GuiHandler {
let (input_bindings, input_attributes) = TexturedVertex::vertex_input_state(); let (input_bindings, input_attributes) = TexturedVertex::vertex_input_state();
let pipeline = GuiHandler::init_gui_pipeline(
device,
input_bindings,
input_attributes,
render_pass,
&pipeline_layout,
vertex_shader,
fragment_shader,
)?;
Ok(( Ok((
GuiSeparator { render_targets.execute(|render_target| {
_descriptor_layout: descriptor_layout, Ok(GuiSeparator {
_pipeline_layout: pipeline_layout, _descriptor_layout: descriptor_layout.clone(),
_pipeline: pipeline, _pipeline: GuiHandler::init_gui_pipeline(
}, device,
input_bindings.clone(),
input_attributes.clone(),
render_target.read().unwrap().render_pass(),
&pipeline_layout,
vertex_shader.clone(),
fragment_shader.clone(),
)?,
})
})?,
color_layout, color_layout,
)) ))
} }
fn init_rectangle_objects( fn init_rectangle_objects(
device: &Arc<Device>, device: &Arc<Device>,
render_pass: &Arc<RenderPass>, render_targets: &TargetMode<RwLock<RenderTarget>>,
) -> Result<GuiSeparator> { ) -> Result<TargetMode<GuiSeparator>> {
let descriptor_layout = DescriptorSetLayout::builder() let descriptor_layout = DescriptorSetLayout::builder()
.add_layout_binding( .add_layout_binding(
0, 0,
@ -1384,28 +1307,27 @@ impl GuiHandler {
let (input_bindings, input_attributes) = TexturedVertex::vertex_input_state(); let (input_bindings, input_attributes) = TexturedVertex::vertex_input_state();
let pipeline = GuiHandler::init_gui_pipeline( render_targets.execute(|render_target| {
device,
input_bindings,
input_attributes,
render_pass,
&pipeline_layout,
vertex_shader,
fragment_shader,
)?;
Ok(GuiSeparator { Ok(GuiSeparator {
_descriptor_layout: descriptor_layout, _descriptor_layout: descriptor_layout.clone(),
_pipeline_layout: pipeline_layout,
_pipeline: pipeline, _pipeline: GuiHandler::init_gui_pipeline(
device,
input_bindings.clone(),
input_attributes.clone(),
render_target.read().unwrap().render_pass(),
&pipeline_layout,
vertex_shader.clone(),
fragment_shader.clone(),
)?,
})
}) })
} }
fn init_single_color_objects( fn init_single_color_objects(
device: &Arc<Device>, device: &Arc<Device>,
render_pass: &Arc<RenderPass>, render_targets: &TargetMode<RwLock<RenderTarget>>,
) -> Result<GuiSeparator> { ) -> Result<TargetMode<GuiSeparator>> {
let color_layout = DescriptorSetLayout::builder() let color_layout = DescriptorSetLayout::builder()
.add_layout_binding( .add_layout_binding(
0, 0,
@ -1433,21 +1355,20 @@ impl GuiHandler {
let (input_bindings, input_attributes) = Colorable::vertex_input_state(); let (input_bindings, input_attributes) = Colorable::vertex_input_state();
let pipeline = GuiHandler::init_gui_pipeline( render_targets.execute(|render_target| {
device,
input_bindings,
input_attributes,
render_pass,
&pipeline_layout,
vertex_shader,
fragment_shader,
)?;
Ok(GuiSeparator { Ok(GuiSeparator {
_descriptor_layout: color_layout, _descriptor_layout: color_layout.clone(),
_pipeline_layout: pipeline_layout,
_pipeline: pipeline, _pipeline: GuiHandler::init_gui_pipeline(
device,
input_bindings.clone(),
input_attributes.clone(),
render_target.read().unwrap().render_pass(),
&pipeline_layout,
vertex_shader.clone(),
fragment_shader.clone(),
)?,
})
}) })
} }
@ -1475,24 +1396,31 @@ impl GuiHandler {
&self, &self,
buffer_recorder: &mut CommandBufferRecorder<'_>, buffer_recorder: &mut CommandBufferRecorder<'_>,
command_buffer_states: &[CommandBufferState], command_buffer_states: &[CommandBufferState],
framebuffers: &[Arc<Framebuffer>], render_target: &RenderTarget,
single_color_objects: &GuiSeparator,
rectangle_objects: &GuiSeparator,
text_objects: &GuiSeparator,
index: usize, index: usize,
) -> Result<()> { ) -> Result<()> {
let command_buffer_state = &command_buffer_states[index]; let command_buffer_state = &command_buffer_states[index];
let framebuffer = &framebuffers[index];
self.render(command_buffer_state, framebuffer)?; self.render(
command_buffer_state,
render_target,
single_color_objects,
rectangle_objects,
text_objects,
)?;
buffer_recorder.begin_render_pass_full( render_target.begin(
&self.render_pass, buffer_recorder,
framebuffer,
&[],
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS,
index,
); );
buffer_recorder.execute_commands(&[&command_buffer_state.command_buffer]); buffer_recorder.execute_commands(&[&command_buffer_state.command_buffer]);
buffer_recorder.end_render_pass(); render_target.end(buffer_recorder);
Ok(()) Ok(())
} }
@ -1537,23 +1465,56 @@ impl GuiHandler {
match ( match (
&self.command_buffers, &self.command_buffers,
self.framebuffers.lock().unwrap().deref(), &self.render_targets,
&self.text_objects,
&self.rectangle_objects,
&self.single_color_objects,
indices, indices,
) { ) {
( (
TargetMode::Mono(command_buffers), TargetMode::Mono(command_buffers),
TargetMode::Mono(framebuffers), TargetMode::Mono(render_target),
TargetMode::Mono(text_objects),
TargetMode::Mono(rectangle_objects),
TargetMode::Mono(single_color_object),
TargetMode::Mono(index), TargetMode::Mono(index),
) => { ) => {
self.select_rendering(buffer_recorder, command_buffers, framebuffers, *index)?; self.select_rendering(
buffer_recorder,
command_buffers,
&*render_target.read().unwrap(),
single_color_object,
rectangle_objects,
text_objects,
*index,
)?;
} }
( (
TargetMode::Stereo(left_cbs, right_cbs), TargetMode::Stereo(left_cbs, right_cbs),
TargetMode::Stereo(left_frb, right_frb), TargetMode::Stereo(left_rt, right_rt),
TargetMode::Stereo(left_text_objects, right_text_objects),
TargetMode::Stereo(left_rectangle_objects, right_rectangle_objects),
TargetMode::Stereo(left_single_color_object, right_single_color_object),
TargetMode::Stereo(left_index, right_index), TargetMode::Stereo(left_index, right_index),
) => { ) => {
self.select_rendering(buffer_recorder, left_cbs, left_frb, *left_index)?; self.select_rendering(
self.select_rendering(buffer_recorder, right_cbs, right_frb, *right_index)?; buffer_recorder,
left_cbs,
&*left_rt.read().unwrap(),
left_single_color_object,
left_rectangle_objects,
left_text_objects,
*left_index,
)?;
self.select_rendering(
buffer_recorder,
right_cbs,
&*right_rt.read().unwrap(),
right_single_color_object,
right_rectangle_objects,
right_text_objects,
*right_index,
)?;
} }
_ => panic!("Invalid TargetMode combination"), _ => panic!("Invalid TargetMode combination"),
}; };
@ -1562,11 +1523,13 @@ impl GuiHandler {
} }
pub fn resize(&self, width: u32, height: u32) -> Result<()> { pub fn resize(&self, width: u32, height: u32) -> Result<()> {
*self.framebuffers.lock().unwrap() = Self::create_framebuffers( todo!();
self.context.device(),
&self.context.images(), // *self.framebuffers.lock().unwrap() = Self::create_framebuffers(
&self.render_pass, // self.context.device(),
)?; // &self.context.images(),
// &self.render_pass,
// )?;
self.needs_update.store(true, SeqCst); self.needs_update.store(true, SeqCst);
*self.ortho.write().unwrap() = ortho(0.0, width as f32, 0.0, height as f32, -1.0, 1.0); *self.ortho.write().unwrap() = ortho(0.0, width as f32, 0.0, height as f32, -1.0, 1.0);