use std::sync::Arc; use vulkano::{ buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}, command_buffer::{ allocator::StandardCommandBufferAllocator, CommandBuffer, CommandBufferBeginInfo, CommandBufferInheritanceInfo, CommandBufferLevel, CommandBufferUsage, RecordingCommandBuffer, }, device::Queue, memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, pipeline::{ graphics::{ color_blend::{ColorBlendAttachmentState, ColorBlendState}, depth_stencil::{DepthState, DepthStencilState}, input_assembly::InputAssemblyState, multisample::MultisampleState, rasterization::RasterizationState, vertex_input::{Vertex, VertexDefinition}, viewport::{Viewport, ViewportState}, GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }, render_pass::Subpass, }; pub struct TriangleDrawSystem { gfx_queue: Arc, vertex_buffer: Subbuffer<[TriangleVertex]>, subpass: Subpass, pipeline: Arc, command_buffer_allocator: Arc, } impl TriangleDrawSystem { /// Initializes a triangle drawing system. pub fn new( gfx_queue: Arc, subpass: Subpass, memory_allocator: Arc, command_buffer_allocator: Arc, ) -> TriangleDrawSystem { let vertices = [ TriangleVertex { position: [-0.5, -0.25], }, TriangleVertex { position: [0.0, 0.5], }, TriangleVertex { position: [0.25, -0.1], }, ]; let vertex_buffer = Buffer::from_iter( memory_allocator, BufferCreateInfo { usage: BufferUsage::VERTEX_BUFFER, ..Default::default() }, AllocationCreateInfo { memory_type_filter: MemoryTypeFilter::PREFER_DEVICE | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, ..Default::default() }, vertices, ) .expect("failed to create buffer"); let pipeline = { let device = gfx_queue.device(); let vs = vs::load(device.clone()) .expect("failed to create shader module") .entry_point("main") .expect("shader entry point not found"); let fs = fs::load(device.clone()) .expect("failed to create shader module") .entry_point("main") .expect("shader entry point not found"); let vertex_input_state = TriangleVertex::per_vertex() .definition(&vs.info().input_interface) .unwrap(); let stages = [ PipelineShaderStageCreateInfo::new(vs), PipelineShaderStageCreateInfo::new(fs), ]; let layout = PipelineLayout::new( device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) .into_pipeline_layout_create_info(device.clone()) .unwrap(), ) .unwrap(); 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()), depth_stencil_state: Some(DepthStencilState { depth: Some(DepthState::simple()), ..Default::default() }), multisample_state: Some(MultisampleState::default()), color_blend_state: Some(ColorBlendState::with_attachment_states( subpass.num_color_attachments(), ColorBlendAttachmentState::default(), )), dynamic_state: [DynamicState::Viewport].into_iter().collect(), subpass: Some(subpass.clone().into()), ..GraphicsPipelineCreateInfo::layout(layout) }, ) .unwrap() }; TriangleDrawSystem { gfx_queue, vertex_buffer, subpass, pipeline, command_buffer_allocator, } } /// Builds a secondary command buffer that draws the triangle on the current subpass. pub fn draw(&self, viewport_dimensions: [u32; 2]) -> Arc { let mut builder = RecordingCommandBuffer::new( self.command_buffer_allocator.clone(), self.gfx_queue.queue_family_index(), CommandBufferLevel::Secondary, CommandBufferBeginInfo { usage: CommandBufferUsage::MultipleSubmit, inheritance_info: Some(CommandBufferInheritanceInfo { render_pass: Some(self.subpass.clone().into()), ..Default::default() }), ..Default::default() }, ) .unwrap(); builder .set_viewport( 0, [Viewport { offset: [0.0, 0.0], extent: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32], depth_range: 0.0..=1.0, }] .into_iter() .collect(), ) .unwrap() .bind_pipeline_graphics(self.pipeline.clone()) .unwrap() .bind_vertex_buffers(0, self.vertex_buffer.clone()) .unwrap(); unsafe { builder .draw(self.vertex_buffer.len() as u32, 1, 0, 0) .unwrap(); } builder.end().unwrap() } } #[derive(BufferContents, Vertex)] #[repr(C)] struct TriangleVertex { #[format(R32G32_SFLOAT)] position: [f32; 2], } mod vs { vulkano_shaders::shader! { ty: "vertex", src: r" #version 450 layout(location = 0) in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } ", } } mod fs { vulkano_shaders::shader! { ty: "fragment", src: r" #version 450 layout(location = 0) out vec4 f_color; layout(location = 1) out vec4 f_normal; void main() { f_color = vec4(1.0, 1.0, 1.0, 1.0); f_normal = vec4(0.0, 0.0, 1.0, 0.0); } ", } }