diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-07-05 14:53:37 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-07-05 14:53:37 -0700 |
| commit | 82cba53f60013699631be3f1fdc0bd1e47d5f6d6 (patch) | |
| tree | 5527f14ff2389b332f7bd5bcc88a4eaf4561b27a /src | |
| parent | aea6d8b310dede44211fcf994f8ddb42df076d91 (diff) | |
successfully instantiate the render pipeline
in the words of the tutorial, "We are already getting quite close to seeing something pop up on the screen"..... it took THREE DAYS. encouragement is great and all, but perhaps don't trivialize that effort Force-Push: yes Change-Id: Icf7fd651dbf12cae0320f98d1622fad5fcd3fd0d
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 225 |
1 files changed, 212 insertions, 13 deletions
diff --git a/src/main.rs b/src/main.rs index 62c6025..1528b1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -131,6 +131,13 @@ struct Surreality { swapchain: OnceCell<vk::SwapchainKHR>, swapchain_images: OnceCell<Vec<vk::Image>>, swapchain_image_views: OnceCell<Vec<vk::ImageView>>, + format: OnceCell<vk::Format>, + extent: OnceCell<vk::Extent2D>, + + render_pass: OnceCell<vk::RenderPass>, + + pipeline: OnceCell<vk::Pipeline>, + pipeline_layout: OnceCell<vk::PipelineLayout>, } impl Surreality { @@ -151,6 +158,11 @@ impl Surreality { swapchain: OnceCell::new(), swapchain_images: OnceCell::new(), swapchain_image_views: OnceCell::new(), + format: OnceCell::new(), + extent: OnceCell::new(), + render_pass: OnceCell::new(), + pipeline: OnceCell::new(), + pipeline_layout: OnceCell::new(), } } @@ -181,7 +193,13 @@ impl Surreality { self.init_vulkan_swapchain()?; } - self.init_pipeline()?; + if self.render_pass.get().is_none() { + self.init_render_pass()?; + } + + if self.pipeline.get().is_none() { + self.init_pipeline()?; + } Ok(()) } @@ -544,8 +562,6 @@ impl Surreality { let device = self.device.get().unwrap().clone(); let surface = self.surface.get().unwrap().clone(); - println!("features {:?}", features); - let format = self.pick_surface_format(&features.formats)?; let presentation_mode @@ -636,28 +652,174 @@ impl Surreality { self.swapchain.set(swapchain).unwrap(); self.swapchain_images.set(images).unwrap(); self.swapchain_image_views.set(image_views).unwrap(); + self.format.set(format.format).unwrap(); + self.extent.set(extent).unwrap(); } Ok(()) } #[allow(unsafe_code)] - fn init_pipeline(&mut self) -> Result<()> { - // TODO integrate with Cargo - let vertex_binary = include_bytes!("../vert.spv"); - let fragment_binary = include_bytes!("../frag.spv"); + fn init_render_pass(&mut self) -> Result<()> { + if self.render_pass.get().is_none() { + let device = self.device.get().unwrap(); + let format = self.format.get().unwrap(); + + let color_attachment + = vk::AttachmentDescription::builder() + .format(*format) + .samples(vk::SampleCountFlags::_1) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::STORE) + .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) + .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); + + let color_attachment_reference + = vk::AttachmentReference::builder() + .attachment(0) + .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + + let subpass_attachments = [color_attachment_reference]; + let subpass = vk::SubpassDescription::builder() + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .color_attachments(&subpass_attachments); + + let render_attachments = [color_attachment]; + let subpasses = [subpass]; + let render_pass_info = vk::RenderPassCreateInfo::builder() + .attachments(&render_attachments) + .subpasses(&subpasses); + + let render_pass = unsafe { + device.create_render_pass(&render_pass_info, None) + }?; - let _ = self.load_spirv_shader_module(vertex_binary)?; + self.render_pass.set(render_pass).unwrap(); + } Ok(()) } - fn load_spirv_shader_module(&mut self, binary: &[u8]) - -> Result<vk::ShaderModule> - { - let bytecode = Bytecode::new(binary)?; + #[allow(unsafe_code)] + fn init_pipeline(&mut self) -> Result<()> { + if self.pipeline.get().is_none() { + let device = self.device.get().unwrap().clone(); + let extent = self.extent.get().unwrap().clone(); + let render_pass = self.render_pass.get().unwrap().clone(); + + // TODO integrate with Cargo + let vertex_binary = include_bytes!("../vert.spv"); + let fragment_binary = include_bytes!("../frag.spv"); + + let vertex_module = self.load_spirv_shader_module(vertex_binary)?; + let fragment_module = self.load_spirv_shader_module(fragment_binary)?; + + let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::VERTEX) + .module(vertex_module) + .name(b"main\0"); + + let fragment_stage_info = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::FRAGMENT) + .module(fragment_module) + .name(b"main\0"); + + let vertex_input_state_info + = vk::PipelineVertexInputStateCreateInfo::builder(); + + let input_assembly_state_info + = vk::PipelineInputAssemblyStateCreateInfo::builder() + .topology(vk::PrimitiveTopology::TRIANGLE_LIST) + .primitive_restart_enable(false); + + let viewport = vk::Viewport::builder() + .x(0.0) + .y(0.0) + .width(extent.width as f32) + .height(extent.height as f32) + .min_depth(0.0) + .max_depth(1.0); + let viewports = [viewport]; + + let scissor = vk::Rect2D::builder() + .offset(vk::Offset2D { x: 0, y: 0 }) + .extent(extent); + let scissor_list = [scissor]; + + let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder() + .viewports(&viewports) + .scissors(&scissor_list); + + let rasterizer_state_info + = vk::PipelineRasterizationStateCreateInfo::builder() + .depth_clamp_enable(false) + .rasterizer_discard_enable(false) + .polygon_mode(vk::PolygonMode::FILL) + .line_width(1.0) + .cull_mode(vk::CullModeFlags::BACK) + .front_face(vk::FrontFace::CLOCKWISE) + .depth_bias_enable(false); + + let multisample_state_info + = vk::PipelineMultisampleStateCreateInfo::builder() + .sample_shading_enable(false) + .rasterization_samples(vk::SampleCountFlags::_1); + + let blend_attachment_info + = vk::PipelineColorBlendAttachmentState::builder() + .color_write_mask(vk::ColorComponentFlags::all()) + .blend_enable(false) + .src_color_blend_factor(vk::BlendFactor::ONE) + .dst_color_blend_factor(vk::BlendFactor::ZERO) + .color_blend_op(vk::BlendOp::ADD) + .src_alpha_blend_factor(vk::BlendFactor::ONE) + .dst_alpha_blend_factor(vk::BlendFactor::ZERO) + .alpha_blend_op(vk::BlendOp::ADD); + let blend_attachments = [blend_attachment_info]; + + let blend_info = vk::PipelineColorBlendStateCreateInfo::builder() + .logic_op_enable(false) + .logic_op(vk::LogicOp::COPY) + .attachments(&blend_attachments) + .blend_constants([0.0, 0.0, 0.0, 0.0]); + + let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder(); + + let pipeline_layout = unsafe { + device.create_pipeline_layout(&pipeline_layout_info, None) + }?; + + let stages = [vertex_stage_info, fragment_stage_info]; + let pipeline_info + = vk::GraphicsPipelineCreateInfo::builder() + .stages(&stages) + .vertex_input_state(&vertex_input_state_info) + .input_assembly_state(&input_assembly_state_info) + .viewport_state(&viewport_state_info) + .rasterization_state(&rasterizer_state_info) + .multisample_state(&multisample_state_info) + .color_blend_state(&blend_info) + .layout(pipeline_layout) + .render_pass(render_pass) + .subpass(0); + + let pipeline = unsafe { + device.create_graphics_pipelines(vk::PipelineCache::null(), + &[pipeline_info], None) + }?.0[0]; + + self.pipeline_layout.set(pipeline_layout).unwrap(); + self.pipeline.set(pipeline).unwrap(); - Err(Error { message: "just because".to_string() }) + unsafe { + device.destroy_shader_module(vertex_module, None); + device.destroy_shader_module(fragment_module, None); + }; + } + + Ok(()) } // To Vulkan, a "physical" device is the actual GPU, and a "logical" @@ -918,6 +1080,25 @@ impl Surreality { } } + #[allow(unsafe_code)] + fn load_spirv_shader_module(&mut self, binary: &[u8]) + -> Result<vk::ShaderModule> + { + let device = self.device.get().unwrap(); + + let bytecode = Bytecode::new(binary)?; + + let module_info = vk::ShaderModuleCreateInfo::builder() + .code(bytecode.code()) + .code_size(bytecode.code_size()); + + let module = unsafe { + device.create_shader_module(&module_info, None) + }?; + + Ok(module) + } + fn render(&mut self, window_id: WindowId) -> Result<()> { if let Some(window) = self.window.get() && window_id == window.id() @@ -934,6 +1115,24 @@ impl Surreality { impl Drop for Surreality { #[allow(unsafe_code)] fn drop(&mut self) { + if let Some(pipeline) = self.pipeline.get() + && let Some(device) = self.device.get() + { + unsafe { device.destroy_pipeline(*pipeline, None) }; + } + + if let Some(render_pass) = self.render_pass.get() + && let Some(device) = self.device.get() + { + unsafe { device.destroy_render_pass(*render_pass, None) }; + } + + if let Some(pipeline_layout) = self.pipeline_layout.get() + && let Some(device) = self.device.get() + { + unsafe { device.destroy_pipeline_layout(*pipeline_layout, None) }; + } + if let Some(image_views) = self.swapchain_image_views.get() && let Some(device) = self.device.get() { |