summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs225
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()
     {