diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-08-17 01:41:16 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-08-17 02:07:34 -0700 |
| commit | b52d1be4302e452a45a03595f8c70411a061f920 (patch) | |
| tree | 27af0086f681df583389cfadafd65d7067d26fb2 /src/graphics/render.rs | |
| parent | db64249ce8108439ada78a2d23d67d2c573a1688 (diff) | |
move the texture binding to a push descriptor
with a descriptor update template, even yay this also moves us to a minimum Vulkan version of 1.4, which we understand to be widely deployed. in theory, push descriptors and update templates were available via extensions in earlier versions, but it doesn't seem worth doing the work to switch out whether we use the extensions based on the version, so we don't. Force-Push: yes Change-Id: I26db8771abf5626d9614630c66e019ea99babcac
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) +} + |