vulkano/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs

279 lines
9.2 KiB
Rust
Raw Normal View History

// Copyright (c) 2021 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::sync::Arc;
use vulkano::{
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer},
command_buffer::{
allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder,
CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer,
},
descriptor_set::{
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
},
device::Queue,
image::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode},
view::ImageView,
},
memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryUsage},
pipeline::{
graphics::{
color_blend::ColorBlendState,
input_assembly::InputAssemblyState,
multisample::MultisampleState,
rasterization::RasterizationState,
vertex_input::{Vertex, VertexDefinition},
viewport::{Viewport, ViewportState},
GraphicsPipelineCreateInfo,
},
layout::PipelineDescriptorSetLayoutCreateInfo,
GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
PipelineShaderStageCreateInfo,
},
render_pass::Subpass,
};
/// Vertex for textured quads.
#[derive(BufferContents, Vertex)]
2021-11-24 14:19:57 +00:00
#[repr(C)]
pub struct TexturedVertex {
Refactor Vertex trait to allow user-defined formats (#2106) * Refactor Vertex trait to not rely on ShaderInterfaceEntryType::to_format and instead rely on Format provided by VertexMember trait. * Add test for impl_vertex macro, remove tuple implementations as they do not implement Pod, minor cleanups to impl_vertex macro. * #[derive(Vertex)] proc-macro implementation with support for format and name attributes. Tests are implemented for both attributes and inferral matching impl_vertex macro * Rename num_elements into num_locations to make purpose clear, add helper function to calculate num_components and check them properly in BufferDefinition's VertexDefinition implementation. * Rename num_locations back to num_elements to make distinction to locations clear. Updated VertexDefinition implementation for BuffersDefinition to support double precision formats exceeding a single location. * Add additional validation for vertex attributes with formats exceeding their location. * Collect unnecessary, using iterator in loop to avoid unnecessary allocations. * Use field type directly and avoid any form of unsafe blocks. * Match shader scalar type directly in GraphicsPipelineBuilder * Rename impl_vertex test to fit macro name * Add VertexMember implementatinos for nalgebra and cgmath (incl matrices). * Add missing copyright headers to new files in proc macro crate * Document derive vertex with field-attribute options on the Vertex trait * Add example for vertex derive approach. * Do not publish internal macros crate as it is re-exported by vulkano itself * Deprecate impl_vertex and VertexMember and update documentation for Vertex accordingly * Make format field-level attribute mandatory for derive vertex * Update all examples to derive Vertex trait instead of impl_vertex macro * Fix doctests by adding missing imports and re-exporting crate self as vulkano to workaround limitations of distinguishing doctests in proc-macros
2022-12-28 10:23:36 +00:00
#[format(R32G32_SFLOAT)]
pub position: [f32; 2],
Refactor Vertex trait to allow user-defined formats (#2106) * Refactor Vertex trait to not rely on ShaderInterfaceEntryType::to_format and instead rely on Format provided by VertexMember trait. * Add test for impl_vertex macro, remove tuple implementations as they do not implement Pod, minor cleanups to impl_vertex macro. * #[derive(Vertex)] proc-macro implementation with support for format and name attributes. Tests are implemented for both attributes and inferral matching impl_vertex macro * Rename num_elements into num_locations to make purpose clear, add helper function to calculate num_components and check them properly in BufferDefinition's VertexDefinition implementation. * Rename num_locations back to num_elements to make distinction to locations clear. Updated VertexDefinition implementation for BuffersDefinition to support double precision formats exceeding a single location. * Add additional validation for vertex attributes with formats exceeding their location. * Collect unnecessary, using iterator in loop to avoid unnecessary allocations. * Use field type directly and avoid any form of unsafe blocks. * Match shader scalar type directly in GraphicsPipelineBuilder * Rename impl_vertex test to fit macro name * Add VertexMember implementatinos for nalgebra and cgmath (incl matrices). * Add missing copyright headers to new files in proc macro crate * Document derive vertex with field-attribute options on the Vertex trait * Add example for vertex derive approach. * Do not publish internal macros crate as it is re-exported by vulkano itself * Deprecate impl_vertex and VertexMember and update documentation for Vertex accordingly * Make format field-level attribute mandatory for derive vertex * Update all examples to derive Vertex trait instead of impl_vertex macro * Fix doctests by adding missing imports and re-exporting crate self as vulkano to workaround limitations of distinguishing doctests in proc-macros
2022-12-28 10:23:36 +00:00
#[format(R32G32_SFLOAT)]
pub tex_coords: [f32; 2],
}
pub fn textured_quad(width: f32, height: f32) -> (Vec<TexturedVertex>, Vec<u32>) {
(
vec![
TexturedVertex {
position: [-(width / 2.0), -(height / 2.0)],
tex_coords: [0.0, 1.0],
},
TexturedVertex {
position: [-(width / 2.0), height / 2.0],
tex_coords: [0.0, 0.0],
},
TexturedVertex {
position: [width / 2.0, height / 2.0],
tex_coords: [1.0, 0.0],
},
TexturedVertex {
position: [width / 2.0, -(height / 2.0)],
tex_coords: [1.0, 1.0],
},
],
vec![0, 2, 1, 0, 3, 2],
)
}
/// A subpass pipeline that fills a quad over frame.
pub struct PixelsDrawPipeline {
gfx_queue: Arc<Queue>,
subpass: Subpass,
pipeline: Arc<GraphicsPipeline>,
command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
vertices: Subbuffer<[TexturedVertex]>,
indices: Subbuffer<[u32]>,
}
impl PixelsDrawPipeline {
pub fn new(
gfx_queue: Arc<Queue>,
subpass: Subpass,
2022-10-26 14:25:01 +00:00
memory_allocator: &impl MemoryAllocator,
command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
) -> PixelsDrawPipeline {
let (vertices, indices) = textured_quad(2.0, 2.0);
let vertex_buffer = Buffer::from_iter(
2022-10-26 14:25:01 +00:00
memory_allocator,
BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
usage: MemoryUsage::Upload,
..Default::default()
},
vertices,
)
.unwrap();
let index_buffer = Buffer::from_iter(
2022-10-26 14:25:01 +00:00
memory_allocator,
BufferCreateInfo {
usage: BufferUsage::INDEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
usage: MemoryUsage::Upload,
..Default::default()
},
indices,
)
.unwrap();
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 = TexturedVertex::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::viewport_dynamic_scissor_irrelevant()),
rasterization_state: Some(RasterizationState::default()),
multisample_state: Some(MultisampleState::default()),
color_blend_state: Some(ColorBlendState::new(subpass.num_color_attachments())),
subpass: Some(subpass.clone().into()),
..GraphicsPipelineCreateInfo::layout(layout)
},
)
.unwrap()
};
PixelsDrawPipeline {
gfx_queue,
subpass,
pipeline,
command_buffer_allocator,
descriptor_set_allocator,
vertices: vertex_buffer,
indices: index_buffer,
}
}
fn create_descriptor_set(&self, image: Arc<ImageView>) -> Arc<PersistentDescriptorSet> {
let layout = self.pipeline.layout().set_layouts().get(0).unwrap();
let sampler = Sampler::new(
self.gfx_queue.device().clone(),
SamplerCreateInfo {
mag_filter: Filter::Linear,
min_filter: Filter::Linear,
address_mode: [SamplerAddressMode::Repeat; 3],
mipmap_mode: SamplerMipmapMode::Linear,
..Default::default()
},
)
.unwrap();
PersistentDescriptorSet::new(
&self.descriptor_set_allocator,
layout.clone(),
[WriteDescriptorSet::image_view_sampler(0, image, sampler)],
[],
)
.unwrap()
}
/// Draws input `image` over a quad of size -1.0 to 1.0.
pub fn draw(
&self,
viewport_dimensions: [u32; 2],
image: Arc<ImageView>,
) -> Arc<SecondaryAutoCommandBuffer> {
let mut builder = AutoCommandBufferBuilder::secondary(
self.command_buffer_allocator.as_ref(),
self.gfx_queue.queue_family_index(),
CommandBufferUsage::MultipleSubmit,
CommandBufferInheritanceInfo {
render_pass: Some(self.subpass.clone().into()),
..Default::default()
},
)
.unwrap();
let desc_set = self.create_descriptor_set(image);
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(),
)
.bind_pipeline_graphics(self.pipeline.clone())
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
self.pipeline.layout().clone(),
0,
desc_set,
)
.bind_vertex_buffers(0, self.vertices.clone())
.bind_index_buffer(self.indices.clone())
.draw_indexed(self.indices.len() as u32, 1, 0, 0, 0)
.unwrap();
builder.build().unwrap()
}
}
mod vs {
vulkano_shaders::shader! {
ty: "vertex",
src: r"
#version 450
layout(location=0) in vec2 position;
layout(location=1) in vec2 tex_coords;
layout(location = 0) out vec2 f_tex_coords;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
f_tex_coords = tex_coords;
}
",
}
}
mod fs {
vulkano_shaders::shader! {
ty: "fragment",
src: r"
#version 450
layout(location = 0) in vec2 v_tex_coords;
layout(location = 0) out vec4 f_color;
layout(set = 0, binding = 0) uniform sampler2D tex;
void main() {
f_color = texture(tex, v_tex_coords);
}
",
}
}