vulkano/examples/deferred/triangle_draw_system.rs
2024-03-04 22:58:27 +01:00

210 lines
6.9 KiB
Rust

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<Queue>,
vertex_buffer: Subbuffer<[TriangleVertex]>,
subpass: Subpass,
pipeline: Arc<GraphicsPipeline>,
command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
}
impl TriangleDrawSystem {
/// Initializes a triangle drawing system.
pub fn new(
gfx_queue: Arc<Queue>,
subpass: Subpass,
memory_allocator: Arc<StandardMemoryAllocator>,
command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
) -> 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).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<CommandBuffer> {
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);
}
",
}
}