diff options
Diffstat (limited to 'src/graphics/render.rs')
| -rw-r--r-- | src/graphics/render.rs | 105 |
1 files changed, 93 insertions, 12 deletions
diff --git a/src/graphics/render.rs b/src/graphics/render.rs index 30f4b62..368bb96 100644 --- a/src/graphics/render.rs +++ b/src/graphics/render.rs @@ -4,12 +4,12 @@ use crate::assets::asset; use crate::graphics::{ Permanent, ForReinit, WindowDressing, Frame, Model, Texture }; -use crate::shader_data::{ Vertex, VertexPushBlock }; +use crate::shader_data::{ Vertex, VertexPushBlock, TexturePushBlock }; use std::mem::size_of; use vulkanalia::Device; -use vulkanalia::vk::{ self, Handle, HasBuilder, DeviceV1_0 }; +use vulkanalia::vk::{ self, Handle, HasBuilder, DeviceV1_0, DeviceV1_1 }; // Render is a state object that collects the Vulkan graphics objects which @@ -23,6 +23,12 @@ pub struct Render { pub pipeline_layout: vk::PipelineLayout, pub model: Option<Model>, + pub texture: Option<Texture>, + + // Notice that our descriptor logic is split between the descriptor update + // template for the push descriptors, which is defined here, and the + // descriptor sets, which are per-frame and are kept in Frame. + pub texture_descriptor_update_template: vk::DescriptorUpdateTemplate, pub per_frame: Vec<Frame>, } @@ -30,12 +36,14 @@ pub struct Render { impl Render { pub fn new(permanent: &Permanent, for_reinit: &ForReinit, - window_dressing: &WindowDressing, texture: &Texture) + window_dressing: &WindowDressing) -> Result<Self> { let device = &permanent.device; let sample_count = for_reinit.sample_count; - let descriptor_set_layout = &for_reinit.descriptor_set_layout; + let primary_descriptor_set_layout + = &for_reinit.primary_descriptor_set_layout; + let push_descriptor_set_layout = &for_reinit.push_descriptor_set_layout; let swapchain = &window_dressing.swapchain; let depth_format = &window_dressing.depth_format; @@ -43,19 +51,26 @@ impl Render { &swapchain.format, &depth_format)?; let (pipeline_layout, pipeline) - = init_pipeline(device, descriptor_set_layout, &swapchain.extent, + = init_pipeline(device, primary_descriptor_set_layout, + push_descriptor_set_layout, &swapchain.extent, sample_count, &render_pass)?; + let texture_descriptor_update_template + = init_descriptor_update_template(device, &pipeline_layout)?; + let per_frame = Frame::new(permanent, for_reinit, window_dressing, - texture, &render_pass)?; + &render_pass)?; let model = None; + let texture = None; Ok(Render { render_pass, pipeline, pipeline_layout, model, + texture, + texture_descriptor_update_template, per_frame, }) } @@ -64,14 +79,16 @@ impl Render { // idle. pub fn reinit(&mut self, permanent: &Permanent, for_reinit: &ForReinit, - window_dressing: &WindowDressing, texture: &Texture) + window_dressing: &WindowDressing) -> Result<()> { self.destroy_replaceable(permanent); let device = &permanent.device; let sample_count = for_reinit.sample_count; - let descriptor_set_layout = &for_reinit.descriptor_set_layout; + let primary_descriptor_set_layout + = &for_reinit.primary_descriptor_set_layout; + let push_descriptor_set_layout = &for_reinit.push_descriptor_set_layout; let swapchain = &window_dressing.swapchain; let depth_format = &window_dressing.depth_format; @@ -79,15 +96,21 @@ impl Render { &swapchain.format, &depth_format)?; let (pipeline_layout, pipeline) - = init_pipeline(device, descriptor_set_layout, &swapchain.extent, + = init_pipeline(device, primary_descriptor_set_layout, + push_descriptor_set_layout, &swapchain.extent, sample_count, &render_pass)?; + let texture_descriptor_update_template + = init_descriptor_update_template(device, &pipeline_layout)?; + Frame::reinit(&mut self.per_frame, permanent, for_reinit, window_dressing, - texture, &render_pass)?; + &render_pass)?; self.render_pass = render_pass; self.pipeline = pipeline; self.pipeline_layout = pipeline_layout; + self.texture_descriptor_update_template + = texture_descriptor_update_template; Ok(()) } @@ -103,6 +126,10 @@ impl Render { if let Some(model) = self.model { model.destroy(&permanent.device); } + + if let Some(texture) = self.texture { + texture.destroy(&permanent.device); + } } #[allow(unsafe_code)] @@ -112,6 +139,11 @@ impl Render { let device = &permanent.device; + unsafe { + device.destroy_descriptor_update_template( + self.texture_descriptor_update_template, None) + }; + unsafe { device.destroy_pipeline(self.pipeline, None) }; unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) }; unsafe { device.destroy_render_pass(self.render_pass, None) }; @@ -120,6 +152,10 @@ impl Render { pub fn set_model(&mut self, model: Model) { self.model = Some(model); } + + pub fn set_texture(&mut self, texture: Texture) { + self.texture = Some(texture); + } } @@ -209,7 +245,8 @@ fn init_render_pass(device: &Device, sample_count: vk::SampleCountFlags, #[allow(unsafe_code)] fn init_pipeline(device: &Device, - descriptor_set_layout: &vk::DescriptorSetLayout, + primary_descriptor_set_layout: &vk::DescriptorSetLayout, + push_descriptor_set_layout: &vk::DescriptorSetLayout, extent: &vk::Extent2D, sample_count: vk::SampleCountFlags, render_pass: &vk::RenderPass) -> Result<(vk::PipelineLayout, vk::Pipeline)> @@ -308,7 +345,16 @@ fn init_pipeline(device: &Device, .offset(0) .size(size_of::<VertexPushBlock<f32>>() as u32); - let layouts = [*descriptor_set_layout]; + // Indices into this layout array will appear as magic constants in + // several places: the call to cmd_bind_descriptor_sets() in + // scene.rs's generate_scene_commands(); the update template's definition + // in init_descriptor_update_template(), below; and the call to + // cmd_push_descriptor_set_with_template() in texture.rs's make_active(). + // + // When the list of layouts is changed, all those places need to be + // updated. Keep the breadcrumb comments on the other end in sync with this + // one, as well. + let layouts = [*primary_descriptor_set_layout, *push_descriptor_set_layout]; let push_constant_ranges = [vertex_push_constant_range]; let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder() .set_layouts(&layouts) @@ -345,3 +391,38 @@ fn init_pipeline(device: &Device, Ok((pipeline_layout, pipeline)) } + +#[allow(unsafe_code)] +fn init_descriptor_update_template( + device: &Device, + pipeline_layout: &vk::PipelineLayout) + -> Result<vk::DescriptorUpdateTemplate> +{ + let entry_info = vk::DescriptorUpdateTemplateEntry::builder() + .dst_binding(0) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .descriptor_count(1) + .offset(0) + .stride(size_of::<TexturePushBlock>()); + + let entries = &[entry_info]; + + // Please notice the magic constant set(1). This is a zero-based index + // into the array of descriptor set layouts passed to + // create_pipeline_layout() in init_pipeline(), above. + let template_info = vk::DescriptorUpdateTemplateCreateInfo::builder() + .template_type(vk::DescriptorUpdateTemplateType::PUSH_DESCRIPTORS) + .descriptor_update_entries(entries) + .set(1) + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .pipeline_layout(*pipeline_layout) + .flags(vk::DescriptorUpdateTemplateCreateFlags::empty()); + + let texture_descriptor_update_template = unsafe { + device.create_descriptor_update_template(&template_info, None) + }?; + + Ok(texture_descriptor_update_template) +} + |