Refactor vertex buffer creations

This commit is contained in:
Florian RICHER 2024-12-11 20:41:04 +01:00
parent 1169c76b41
commit 11a5083513
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
7 changed files with 132 additions and 108 deletions

View file

@ -1,20 +1,24 @@
use crate::renderer::render_context::RenderContext;
use crate::renderer::{window_size_dependent_setup, Scene};
use std::sync::Arc; use std::sync::Arc;
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags}; use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo,
};
use vulkano::device::physical::PhysicalDeviceType; use vulkano::device::physical::PhysicalDeviceType;
use vulkano::device::{
Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags,
};
use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo};
use vulkano::memory::allocator::StandardMemoryAllocator; use vulkano::memory::allocator::StandardMemoryAllocator;
use vulkano::swapchain::{acquire_next_image, Surface, SwapchainCreateInfo, SwapchainPresentInfo};
use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo};
use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp};
use vulkano::swapchain::{acquire_next_image, Surface, SwapchainCreateInfo, SwapchainPresentInfo};
use vulkano::sync::GpuFuture; use vulkano::sync::GpuFuture;
use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary};
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::event::WindowEvent; use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::window::WindowId; use winit::window::WindowId;
use crate::renderer::render_context::RenderContext;
use crate::renderer::{window_size_dependent_setup, Scene};
pub struct App { pub struct App {
instance: Arc<Instance>, instance: Arc<Instance>,
@ -47,7 +51,7 @@ impl App {
..Default::default() ..Default::default()
}, },
) )
.unwrap(); .unwrap();
let mut device_extensions = DeviceExtensions { let mut device_extensions = DeviceExtensions {
khr_swapchain: true, khr_swapchain: true,
@ -60,9 +64,7 @@ impl App {
.filter(|p| { .filter(|p| {
p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
}) })
.filter(|p| { .filter(|p| p.supported_extensions().contains(&device_extensions))
p.supported_extensions().contains(&device_extensions)
})
.filter_map(|p| { .filter_map(|p| {
p.queue_family_properties() p.queue_family_properties()
.iter() .iter()
@ -73,15 +75,13 @@ impl App {
}) })
.map(|i| (p, i as u32)) .map(|i| (p, i as u32))
}) })
.min_by_key(|(p, _)| { .min_by_key(|(p, _)| match p.properties().device_type {
match p.properties().device_type { PhysicalDeviceType::DiscreteGpu => 0,
PhysicalDeviceType::DiscreteGpu => 0, PhysicalDeviceType::IntegratedGpu => 1,
PhysicalDeviceType::IntegratedGpu => 1, PhysicalDeviceType::VirtualGpu => 2,
PhysicalDeviceType::VirtualGpu => 2, PhysicalDeviceType::Cpu => 3,
PhysicalDeviceType::Cpu => 3, PhysicalDeviceType::Other => 4,
PhysicalDeviceType::Other => 4, _ => 5,
_ => 5,
}
}) })
.expect("no suitable physical device found"); .expect("no suitable physical device found");
@ -110,7 +110,7 @@ impl App {
..Default::default() ..Default::default()
}, },
) )
.unwrap(); .unwrap();
let queue = queues.next().unwrap(); let queue = queues.next().unwrap();
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
@ -141,16 +141,16 @@ impl ApplicationHandler for App {
f64::from(600), f64::from(600),
)); ));
let window = Arc::new( let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
event_loop
.create_window(window_attributes)
.unwrap(),
);
let surface = Surface::from_window(self.instance.clone(), window.clone()).unwrap(); let surface = Surface::from_window(self.instance.clone(), window.clone()).unwrap();
self.rcx = Some(RenderContext::new(window, surface, &self.device)); self.rcx = Some(RenderContext::new(window, surface, &self.device));
self.scene = Some(Scene::initialize(&self.device, &self.rcx.as_ref().unwrap().swapchain, &self.memory_allocator)); self.scene = Some(Scene::initialize(
&self.device,
&self.rcx.as_ref().unwrap().swapchain,
&self.memory_allocator,
));
} }
fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
@ -192,7 +192,7 @@ impl ApplicationHandler for App {
rcx.swapchain.clone(), rcx.swapchain.clone(),
None, None,
) )
.map_err(Validated::unwrap) .map_err(Validated::unwrap)
{ {
Ok(r) => r, Ok(r) => r,
Err(VulkanError::OutOfDate) => { Err(VulkanError::OutOfDate) => {
@ -211,7 +211,7 @@ impl ApplicationHandler for App {
self.queue.queue_family_index(), self.queue.queue_family_index(),
CommandBufferUsage::OneTimeSubmit, CommandBufferUsage::OneTimeSubmit,
) )
.unwrap(); .unwrap();
builder builder
.begin_rendering(RenderingInfo { .begin_rendering(RenderingInfo {
@ -233,9 +233,7 @@ impl ApplicationHandler for App {
scene.render(&mut builder); scene.render(&mut builder);
} }
builder builder.end_rendering().unwrap();
.end_rendering()
.unwrap();
let command_buffer = builder.build().unwrap(); let command_buffer = builder.build().unwrap();

View file

@ -1,7 +1,7 @@
mod render_context;
mod app; mod app;
mod vertex;
mod pipelines; mod pipelines;
mod render_context;
mod vertex;
pub use app::App; pub use app::App;
pub use pipelines::create_triangle_pipeline; pub use pipelines::create_triangle_pipeline;
@ -10,8 +10,8 @@ pub use scene::Scene;
pub use vertex::Vertex2D; pub use vertex::Vertex2D;
use std::sync::Arc; use std::sync::Arc;
use vulkano::image::Image;
use vulkano::image::view::ImageView; use vulkano::image::view::ImageView;
use vulkano::image::Image;
/// This function is called once during initialization, then again whenever the window is resized. /// This function is called once during initialization, then again whenever the window is resized.
fn window_size_dependent_setup(images: &[Arc<Image>]) -> Vec<Arc<ImageView>> { fn window_size_dependent_setup(images: &[Arc<Image>]) -> Vec<Arc<ImageView>> {

View file

@ -1,2 +1,2 @@
mod triangle_pipeline; mod triangle_pipeline;
pub use triangle_pipeline::create_triangle_pipeline; pub use triangle_pipeline::create_triangle_pipeline;

View file

@ -1,15 +1,17 @@
use std::sync::Arc; use std::sync::Arc;
use vulkano::device::Device; use vulkano::device::Device;
use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition};
use vulkano::pipeline::{DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo};
use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState};
use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState; use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::multisample::MultisampleState; use vulkano::pipeline::graphics::multisample::MultisampleState;
use vulkano::pipeline::graphics::rasterization::RasterizationState; use vulkano::pipeline::graphics::rasterization::RasterizationState;
use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo; use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo;
use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition};
use vulkano::pipeline::graphics::viewport::ViewportState; use vulkano::pipeline::graphics::viewport::ViewportState;
use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo;
use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo;
use vulkano::pipeline::{
DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo,
};
use vulkano::swapchain::Swapchain; use vulkano::swapchain::Swapchain;
use crate::renderer::Vertex2D; use crate::renderer::Vertex2D;
@ -30,7 +32,10 @@ mod shaders {
} }
} }
pub fn create_triangle_pipeline(device: &Arc<Device>, swapchain: &Arc<Swapchain>) -> Arc<GraphicsPipeline> { pub fn create_triangle_pipeline(
device: &Arc<Device>,
swapchain: &Arc<Swapchain>,
) -> Arc<GraphicsPipeline> {
let vs = shaders::vs::load(device.clone()) let vs = shaders::vs::load(device.clone())
.unwrap() .unwrap()
.entry_point("main") .entry_point("main")
@ -40,9 +45,7 @@ pub fn create_triangle_pipeline(device: &Arc<Device>, swapchain: &Arc<Swapchain>
.entry_point("main") .entry_point("main")
.unwrap(); .unwrap();
let vertex_input_state = Vertex2D::per_vertex() let vertex_input_state = Vertex2D::per_vertex().definition(&vs).unwrap();
.definition(&vs)
.unwrap();
let stages = [ let stages = [
PipelineShaderStageCreateInfo::new(vs), PipelineShaderStageCreateInfo::new(vs),
@ -55,7 +58,7 @@ pub fn create_triangle_pipeline(device: &Arc<Device>, swapchain: &Arc<Swapchain>
.into_pipeline_layout_create_info(device.clone()) .into_pipeline_layout_create_info(device.clone())
.unwrap(), .unwrap(),
) )
.unwrap(); .unwrap();
let subpass = PipelineRenderingCreateInfo { let subpass = PipelineRenderingCreateInfo {
color_attachment_formats: vec![Some(swapchain.image_format())], color_attachment_formats: vec![Some(swapchain.image_format())],
@ -81,5 +84,5 @@ pub fn create_triangle_pipeline(device: &Arc<Device>, swapchain: &Arc<Swapchain>
..GraphicsPipelineCreateInfo::layout(layout) ..GraphicsPipelineCreateInfo::layout(layout)
}, },
) )
.unwrap() .unwrap()
} }

View file

@ -1,13 +1,13 @@
use crate::renderer::window_size_dependent_setup;
use std::sync::Arc; use std::sync::Arc;
use vulkano::device::Device; use vulkano::device::Device;
use vulkano::image::ImageUsage;
use vulkano::image::view::ImageView; use vulkano::image::view::ImageView;
use vulkano::image::ImageUsage;
use vulkano::pipeline::graphics::viewport::Viewport; use vulkano::pipeline::graphics::viewport::Viewport;
use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo};
use vulkano::sync; use vulkano::sync;
use vulkano::sync::GpuFuture; use vulkano::sync::GpuFuture;
use winit::window::Window; use winit::window::Window;
use crate::renderer::window_size_dependent_setup;
pub struct RenderContext { pub struct RenderContext {
pub(super) window: Arc<Window>, pub(super) window: Arc<Window>,
@ -51,7 +51,7 @@ impl RenderContext {
..Default::default() ..Default::default()
}, },
) )
.unwrap() .unwrap()
}; };
let attachment_image_views = window_size_dependent_setup(&images); let attachment_image_views = window_size_dependent_setup(&images);

View file

@ -1,12 +1,67 @@
use std::sync::Arc; use std::sync::Arc;
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; use vulkano::buffer::Subbuffer;
use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer};
use vulkano::device::Device; use vulkano::device::Device;
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; use vulkano::memory::allocator::StandardMemoryAllocator;
use vulkano::pipeline::GraphicsPipeline; use vulkano::pipeline::GraphicsPipeline;
use vulkano::swapchain::Swapchain; use vulkano::swapchain::Swapchain;
use crate::renderer::{Vertex2D, create_triangle_pipeline}; use crate::renderer::{create_triangle_pipeline, Vertex2D};
const VERTICES: [Vertex2D; 12] = [
// Triangle en haut à gauche
Vertex2D {
position: [-0.5, -0.75],
color: [1.0, 0.0, 0.0],
},
Vertex2D {
position: [-0.75, -0.25],
color: [0.0, 1.0, 0.0],
},
Vertex2D {
position: [-0.25, -0.25],
color: [0.0, 0.0, 1.0],
},
// Triangle en bas à gauche
Vertex2D {
position: [-0.5, 0.25],
color: [0.5, 0.5, 0.5],
},
Vertex2D {
position: [-0.75, 0.75],
color: [0.2, 0.8, 0.2],
},
Vertex2D {
position: [-0.25, 0.75],
color: [0.8, 0.2, 0.2],
},
// Triangle en haut à droite
Vertex2D {
position: [0.5, -0.75],
color: [1.0, 1.0, 0.0],
},
Vertex2D {
position: [0.25, -0.25],
color: [0.0, 1.0, 1.0],
},
Vertex2D {
position: [0.75, -0.25],
color: [1.0, 0.0, 1.0],
},
// Triangle en bas à droite
Vertex2D {
position: [0.5, 0.25],
color: [0.1, 0.5, 0.8],
},
Vertex2D {
position: [0.25, 0.75],
color: [0.8, 0.6, 0.1],
},
Vertex2D {
position: [0.75, 0.75],
color: [0.3, 0.4, 0.6],
},
];
pub struct Scene { pub struct Scene {
pipeline: Arc<GraphicsPipeline>, pipeline: Arc<GraphicsPipeline>,
@ -14,66 +69,14 @@ pub struct Scene {
} }
impl Scene { impl Scene {
fn create_vertex_buffer(
memory_allocator: &Arc<StandardMemoryAllocator>,
) -> Subbuffer<[Vertex2D]> {
let vertices = [
// Triangle en haut à gauche
Vertex2D::new([-0.5, -0.75], // Coin supérieur gauche
[1.0, 0.0, 0.0]), // Couleur rouge
Vertex2D::new([-0.75, -0.25], // Coin supérieur
[0.0, 1.0, 0.0]), // Couleur verte
Vertex2D::new([-0.25, -0.25], // Coin supérieur droit
[0.0, 0.0, 1.0]), // Couleur bleue
// Triangle en bas à gauche
Vertex2D::new([-0.5, 0.25], // Coin inférieur gauche
[0.5, 0.5, 0.5]), // Couleur gris
Vertex2D::new([-0.75, 0.75], // Coin inférieur
[0.2, 0.8, 0.2]), // Couleur vert clair
Vertex2D::new([-0.25, 0.75], // Coin inférieur droit
[0.8, 0.2, 0.2]), // Couleur rouge clair
// Triangle en haut à droite
Vertex2D::new([0.5, -0.75], // Coin gauche supérieur
[1.0, 1.0, 0.0]), // Couleur jaune
Vertex2D::new([0.25, -0.25], // Coin gauche
[0.0, 1.0, 1.0]), // Couleur cyan
Vertex2D::new([0.75, -0.25], // Coin gauche inférieur
[1.0, 0.0, 1.0]), // Couleur magenta
// Triangle en bas à droite
Vertex2D::new([0.5, 0.25], // Coin droit supérieur
[0.1, 0.5, 0.8]), // Couleur bleu clair
Vertex2D::new([0.25, 0.75], // Coin droit
[0.8, 0.6, 0.1]), // Couleur or
Vertex2D::new([0.75, 0.75], // Coin droit inférieur
[0.3, 0.4, 0.6]), // Couleur bleu foncé
];
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()
},
vertices,
)
.unwrap()
}
pub fn initialize( pub fn initialize(
device: &Arc<Device>, device: &Arc<Device>,
swapchain: &Arc<Swapchain>, swapchain: &Arc<Swapchain>,
memory_allocator: &Arc<StandardMemoryAllocator>, memory_allocator: &Arc<StandardMemoryAllocator>,
) -> Scene { ) -> Scene {
let pipeline = create_triangle_pipeline(device, swapchain); let pipeline = create_triangle_pipeline(device, swapchain);
let vertex_buffer = Self::create_vertex_buffer(memory_allocator); let vertex_buffer =
Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator).unwrap();
Scene { Scene {
pipeline, pipeline,
@ -93,4 +96,4 @@ impl Scene {
unsafe { builder.draw(vertex_count, instance_count, 0, 0) }.unwrap(); unsafe { builder.draw(vertex_count, instance_count, 0, 0) }.unwrap();
} }
} }

View file

@ -1,5 +1,10 @@
use vulkano::buffer::BufferContents; use std::sync::Arc;
use vulkano::buffer::{
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
};
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator};
use vulkano::pipeline::graphics::vertex_input::Vertex; use vulkano::pipeline::graphics::vertex_input::Vertex;
use vulkano::Validated;
#[derive(BufferContents, Vertex)] #[derive(BufferContents, Vertex)]
#[repr(C)] #[repr(C)]
@ -12,7 +17,22 @@ pub struct Vertex2D {
} }
impl Vertex2D { impl Vertex2D {
pub fn new(position: [f32; 2], color: [f32; 3]) -> Self { pub fn create_buffer(
Self { position, color } vertices: Vec<Vertex2D>,
memory_allocator: &Arc<StandardMemoryAllocator>,
) -> Result<Subbuffer<[Vertex2D]>, Validated<AllocateBufferError>> {
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()
},
vertices,
)
} }
} }