diff --git a/src/core/app.rs b/src/core/app.rs index e05d971..bcdb82d 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -19,7 +19,7 @@ use vulkano_util::context::VulkanoContext; use vulkano_util::renderer::VulkanoWindowRenderer; use vulkano_util::window::{VulkanoWindows, WindowDescriptor}; use winit::application::ApplicationHandler; -use winit::event::{DeviceEvent, WindowEvent}; +use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; use winit::window::WindowId; diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs index 0a718e4..a50c5da 100644 --- a/src/core/render/mod.rs +++ b/src/core/render/mod.rs @@ -1,4 +1,3 @@ -pub mod pipelines; pub mod primitives; pub mod render_context; pub mod texture; diff --git a/src/core/render/pipelines/mod.rs b/src/core/render/pipelines/mod.rs deleted file mode 100644 index e5f30a7..0000000 --- a/src/core/render/pipelines/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod triangle_pipeline; diff --git a/src/core/render/pipelines/triangle_pipeline.rs b/src/core/render/pipelines/triangle_pipeline.rs deleted file mode 100644 index 8893f7e..0000000 --- a/src/core/render/pipelines/triangle_pipeline.rs +++ /dev/null @@ -1,140 +0,0 @@ -use std::collections::BTreeMap; -use std::error::Error; -use std::sync::Arc; -use vulkano::descriptor_set::layout::{ - DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType, -}; -use vulkano::device::Device; -use vulkano::format::Format; -use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; -use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; -use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology}; -use vulkano::pipeline::graphics::multisample::MultisampleState; -use vulkano::pipeline::graphics::rasterization::RasterizationState; -use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo; -use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; -use vulkano::pipeline::graphics::viewport::ViewportState; -use vulkano::pipeline::layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}; -use vulkano::pipeline::{ - DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, -}; -use vulkano::shader::{EntryPoint, ShaderStages}; - -use crate::core::render::primitives::vertex::Vertex2D; - -pub mod shaders { - pub mod vs { - vulkano_shaders::shader! { - ty: "vertex", - path: r"res/shaders/vertex.vert", - generate_structs: false, - } - } - - pub mod fs { - vulkano_shaders::shader! { - ty: "fragment", - path: r"res/shaders/vertex.frag", - generate_structs: false, - } - } -} - -pub fn create_triangle_pipeline( - device: &Arc, - swapchain_format: Format, -) -> Result, Box> { - let (vs, fs) = load_shaders(device)?; - let vertex_input_state = Vertex2D::per_vertex().definition(&vs)?; - log::trace!("vertex_input_state: {:#?}", vertex_input_state); - - let stages = [ - PipelineShaderStageCreateInfo::new(vs), - PipelineShaderStageCreateInfo::new(fs), - ]; - - let vertex_bindings = BTreeMap::::from_iter([( - 0, - DescriptorSetLayoutBinding { - stages: ShaderStages::VERTEX, - ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer) - }, - )]); - let fragment_bindings = BTreeMap::::from_iter([ - ( - 0, - DescriptorSetLayoutBinding { - stages: ShaderStages::FRAGMENT, - ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler) - }, - ), - ( - 1, - DescriptorSetLayoutBinding { - stages: ShaderStages::FRAGMENT, - ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::SampledImage) - }, - ), - ]); - - let vertex_descriptor_set_layout = DescriptorSetLayoutCreateInfo { - bindings: vertex_bindings, - ..Default::default() - }; - - let fragment_descriptor_set_layout = DescriptorSetLayoutCreateInfo { - bindings: fragment_bindings, - ..Default::default() - }; - - let create_info = PipelineDescriptorSetLayoutCreateInfo { - set_layouts: vec![vertex_descriptor_set_layout, fragment_descriptor_set_layout], - flags: PipelineLayoutCreateFlags::default(), - push_constant_ranges: vec![], - } - .into_pipeline_layout_create_info(device.clone())?; - - let layout = PipelineLayout::new(device.clone(), create_info)?; - - let subpass = PipelineRenderingCreateInfo { - color_attachment_formats: vec![Some(swapchain_format)], - ..Default::default() - }; - - let pipeline = GraphicsPipeline::new( - device.clone(), - None, - GraphicsPipelineCreateInfo { - stages: stages.into_iter().collect(), - vertex_input_state: Some(vertex_input_state), - input_assembly_state: Some(InputAssemblyState { - topology: PrimitiveTopology::TriangleStrip, - ..Default::default() - }), - viewport_state: Some(ViewportState::default()), - rasterization_state: Some(RasterizationState::default()), - multisample_state: Some(MultisampleState::default()), - color_blend_state: Some(ColorBlendState::with_attachment_states( - subpass.color_attachment_formats.len() as u32, - ColorBlendAttachmentState::default(), - )), - dynamic_state: [DynamicState::Viewport].into_iter().collect(), - subpass: Some(subpass.into()), - ..GraphicsPipelineCreateInfo::layout(layout) - }, - )?; - - Ok(pipeline) -} - -fn load_shaders(device: &Arc) -> Result<(EntryPoint, EntryPoint), Box> { - let vs = shaders::vs::load(device.clone())? - .entry_point("main") - .ok_or("Failed find main entry point of vertex shader".to_string())?; - - let fs = shaders::fs::load(device.clone())? - .entry_point("main") - .ok_or("Failed find main entry point of fragment shader".to_string())?; - - Ok((vs, fs)) -} diff --git a/src/core/render/primitives/mod.rs b/src/core/render/primitives/mod.rs index fd0b762..606c12d 100644 --- a/src/core/render/primitives/mod.rs +++ b/src/core/render/primitives/mod.rs @@ -1,4 +1,4 @@ pub mod camera; -mod mvp; +pub mod mvp; pub mod transform; pub mod vertex; diff --git a/src/game/assets/mod.rs b/src/game/assets/mod.rs new file mode 100644 index 0000000..d793a66 --- /dev/null +++ b/src/game/assets/mod.rs @@ -0,0 +1 @@ +pub mod square; diff --git a/src/game/assets/square.rs b/src/game/assets/square.rs new file mode 100644 index 0000000..3dba163 --- /dev/null +++ b/src/game/assets/square.rs @@ -0,0 +1,247 @@ +use std::{collections::BTreeMap, error::Error, sync::Arc}; + +use vulkano::{ + buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}, + command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}, + descriptor_set::{ + DescriptorSet, WriteDescriptorSet, + allocator::StandardDescriptorSetAllocator, + layout::{DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType}, + }, + device::Device, + format::Format, + memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, + pipeline::{ + DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, + graphics::{ + GraphicsPipelineCreateInfo, + color_blend::{ColorBlendAttachmentState, ColorBlendState}, + input_assembly::{InputAssemblyState, PrimitiveTopology}, + multisample::MultisampleState, + rasterization::RasterizationState, + subpass::PipelineRenderingCreateInfo, + vertex_input::{Vertex, VertexDefinition}, + viewport::ViewportState, + }, + layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}, + }, + shader::ShaderStages, +}; + +use crate::core::render::{ + primitives::{mvp::MVP, vertex::Vertex2D}, + texture::Texture, +}; + +const VERTICES: [Vertex2D; 4] = [ + Vertex2D { + position: [0.0, 0.0], + uv: [0.0, 0.0], + }, + Vertex2D { + position: [0.0, 5.0], + uv: [0.0, 0.5], + }, + Vertex2D { + position: [10.0, 0.0], + uv: [1.0, 0.0], + }, + Vertex2D { + position: [10.0, 5.0], + uv: [1.0, 0.5], + }, +]; + +const INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; + +pub mod shaders { + pub mod vs { + vulkano_shaders::shader! { + ty: "vertex", + path: r"res/shaders/vertex.vert", + generate_structs: false, + } + } + + pub mod fs { + vulkano_shaders::shader! { + ty: "fragment", + path: r"res/shaders/vertex.frag", + generate_structs: false, + } + } +} + +pub struct Square { + vertex_buffer: Subbuffer<[Vertex2D]>, + index_buffer: Subbuffer<[u32]>, + pipeline: Arc, +} + +impl Square { + pub fn new( + device: &Arc, + memory_allocator: &Arc, + swapchain_format: Format, + ) -> Result> { + let vertex_buffer = Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + Vec::from_iter(VERTICES), + )?; + let index_buffer = Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::INDEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + Vec::from_iter(INDICES), + )?; + + let vs = shaders::vs::load(device.clone())? + .entry_point("main") + .ok_or("Failed find main entry point of vertex shader".to_string())?; + + let fs = shaders::fs::load(device.clone())? + .entry_point("main") + .ok_or("Failed find main entry point of fragment shader".to_string())?; + + let vertex_input_state = Vertex2D::per_vertex().definition(&vs)?; + + let stages = [ + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), + ]; + + let vertex_bindings = BTreeMap::::from_iter([( + 0, + DescriptorSetLayoutBinding { + stages: ShaderStages::VERTEX, + ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer) + }, + )]); + let fragment_bindings = BTreeMap::::from_iter([ + ( + 0, + DescriptorSetLayoutBinding { + stages: ShaderStages::FRAGMENT, + ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler) + }, + ), + ( + 1, + DescriptorSetLayoutBinding { + stages: ShaderStages::FRAGMENT, + ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::SampledImage) + }, + ), + ]); + + let vertex_descriptor_set_layout = DescriptorSetLayoutCreateInfo { + bindings: vertex_bindings, + ..Default::default() + }; + + let fragment_descriptor_set_layout = DescriptorSetLayoutCreateInfo { + bindings: fragment_bindings, + ..Default::default() + }; + + let create_info = PipelineDescriptorSetLayoutCreateInfo { + set_layouts: vec![vertex_descriptor_set_layout, fragment_descriptor_set_layout], + flags: PipelineLayoutCreateFlags::default(), + push_constant_ranges: vec![], + } + .into_pipeline_layout_create_info(device.clone())?; + + let layout = PipelineLayout::new(device.clone(), create_info)?; + + let subpass = PipelineRenderingCreateInfo { + color_attachment_formats: vec![Some(swapchain_format)], + ..Default::default() + }; + + let pipeline = GraphicsPipeline::new( + device.clone(), + None, + GraphicsPipelineCreateInfo { + stages: stages.into_iter().collect(), + vertex_input_state: Some(vertex_input_state), + input_assembly_state: Some(InputAssemblyState::default()), + viewport_state: Some(ViewportState::default()), + rasterization_state: Some(RasterizationState::default()), + multisample_state: Some(MultisampleState::default()), + color_blend_state: Some(ColorBlendState::with_attachment_states( + subpass.color_attachment_formats.len() as u32, + ColorBlendAttachmentState::default(), + )), + dynamic_state: [DynamicState::Viewport].into_iter().collect(), + subpass: Some(subpass.into()), + ..GraphicsPipelineCreateInfo::layout(layout) + }, + )?; + + Ok(Self { + vertex_buffer, + index_buffer, + pipeline, + }) + } + + pub fn render( + &self, + command_buffer: &mut AutoCommandBufferBuilder, + descriptor_set_allocator: &Arc, + mvp_uniform: &Subbuffer<[MVP]>, + texture: &Texture, + ) -> Result<(), Box> { + let layouts = self.pipeline.layout().set_layouts(); + + let uniform_descriptor_set = DescriptorSet::new( + descriptor_set_allocator.clone(), + layouts[0].clone(), + [WriteDescriptorSet::buffer(0, mvp_uniform.clone())], + [], + )?; + + let texture_descriptor_set = DescriptorSet::new( + descriptor_set_allocator.clone(), + layouts[1].clone(), + [ + WriteDescriptorSet::sampler(0, texture.get_sampler().clone()), + WriteDescriptorSet::image_view(1, texture.get_texture().clone()), + ], + [], + )?; + + command_buffer.bind_pipeline_graphics(self.pipeline.clone())?; + command_buffer.bind_descriptor_sets( + PipelineBindPoint::Graphics, + self.pipeline.layout().clone(), + 0, + vec![uniform_descriptor_set, texture_descriptor_set], + )?; + command_buffer.bind_vertex_buffers(0, self.vertex_buffer.clone())?; + command_buffer.bind_index_buffer(self.index_buffer.clone())?; + + unsafe { + command_buffer.draw_indexed(INDICES.len() as u32, 1, 0, 0, 0)?; + } + + Ok(()) + } +} diff --git a/src/game/main_scene.rs b/src/game/main_scene.rs index 38c5bc5..c3d08ca 100644 --- a/src/game/main_scene.rs +++ b/src/game/main_scene.rs @@ -1,43 +1,19 @@ use crate::core::input::InputManager; -use crate::core::render::pipelines::triangle_pipeline::create_triangle_pipeline; use crate::core::render::primitives::camera::Camera; -use crate::core::render::primitives::vertex::Vertex2D; use crate::core::render::render_context::RenderContext; use crate::core::render::texture::Texture; use crate::core::scene::Scene; use crate::core::timer::Timer; use glam::{Mat4, Vec3}; -use std::sync::Arc; -use vulkano::buffer::Subbuffer; use vulkano::command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, PrimaryCommandBufferAbstract, }; -use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; -use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; -const VERTICES: [Vertex2D; 4] = [ - Vertex2D { - position: [0.0, 0.0], - uv: [0.0, 0.0], - }, - Vertex2D { - position: [0.0, 5.0], - uv: [0.0, 0.5], - }, - Vertex2D { - position: [10.0, 0.0], - uv: [1.0, 0.0], - }, - Vertex2D { - position: [10.0, 5.0], - uv: [1.0, 0.5], - }, -]; +use super::assets::square::Square; pub struct MainSceneState { - pipeline: Arc, - vertex_buffer: Subbuffer<[Vertex2D]>, + square: Square, camera: Camera, texture: Texture, speed: f32, @@ -54,12 +30,12 @@ impl Scene for MainScene { } fn load(&mut self, render_context: &RenderContext) { - let pipeline = - create_triangle_pipeline(render_context.device(), render_context.swapchain_format()) - .unwrap(); - let vertex_buffer = - Vertex2D::create_buffer(Vec::from_iter(VERTICES), render_context.memory_allocator()) - .unwrap(); + let square = Square::new( + render_context.device(), + render_context.memory_allocator(), + render_context.swapchain_format(), + ) + .unwrap(); let camera = Camera::new( Mat4::look_at_rh( @@ -97,8 +73,7 @@ impl Scene for MainScene { .unwrap(); self.state = Some(MainSceneState { - pipeline, - vertex_buffer, + square, camera, texture, speed: 50.0, @@ -128,49 +103,20 @@ impl Scene for MainScene { builder: &mut AutoCommandBufferBuilder, ) { let state = self.state.as_ref().unwrap(); - let vertex_count = state.vertex_buffer.len() as u32; - let instance_count = vertex_count / 4; - - let layouts = state.pipeline.layout().set_layouts(); - let uniform_buffer = state + let camera_uniform = state .camera .create_buffer(render_context.memory_allocator()) .unwrap(); - let uniform_descriptor_set = DescriptorSet::new( - render_context.descriptor_set_allocator().clone(), - layouts[0].clone(), - [WriteDescriptorSet::buffer(0, uniform_buffer)], - [], - ) - .unwrap(); - let texture_descriptor_set = DescriptorSet::new( - render_context.descriptor_set_allocator().clone(), - layouts[1].clone(), - [ - WriteDescriptorSet::sampler(0, state.texture.get_sampler().clone()), - WriteDescriptorSet::image_view(1, state.texture.get_texture().clone()), - ], - [], - ) - .unwrap(); - - unsafe { - builder - .bind_pipeline_graphics(state.pipeline.clone()) - .unwrap() - .bind_descriptor_sets( - PipelineBindPoint::Graphics, - state.pipeline.layout().clone(), - 0, - vec![uniform_descriptor_set, texture_descriptor_set], - ) - .unwrap() - .bind_vertex_buffers(0, state.vertex_buffer.clone()) - .unwrap() - .draw(vertex_count, instance_count, 0, 0) - .unwrap(); - } + state + .square + .render( + builder, + render_context.descriptor_set_allocator(), + &camera_uniform, + &state.texture, + ) + .unwrap(); } fn unload(&mut self) {} diff --git a/src/game/mod.rs b/src/game/mod.rs index 53eb070..e8924d3 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1 +1,2 @@ +pub mod assets; pub mod main_scene;