summary refs log tree commit diff
path: root/src/graphics/render.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/render.rs')
-rw-r--r--src/graphics/render.rs105
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)
+}
+