diff options
| -rw-r--r-- | shaders/shader.frag | 7 | ||||
| -rw-r--r-- | shaders/shader.vert | 12 | ||||
| -rw-r--r-- | src/main.rs | 225 |
3 files changed, 231 insertions, 13 deletions
diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000..f79ee65 --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,7 @@ +#version 460 + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000..c1bfd9f --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,12 @@ +#version 460 + +vec2 triangle[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +void main() { + gl_Position = vec4(triangle[gl_VertexIndex], 0.0, 1.0); +} + 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() { |