Add traits

This commit is contained in:
Florian RICHER 2025-06-07 20:25:45 +02:00
parent 5539381f46
commit 1a61aab218
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
9 changed files with 663 additions and 94 deletions

View file

@ -0,0 +1,83 @@
use std::{error::Error, sync::Arc};
use vulkano::{
Validated,
buffer::{AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, Subbuffer},
memory::allocator::{AllocationCreateInfo, StandardMemoryAllocator},
};
pub trait AsBindableBuffer<T> {
type BufferData: BufferContents + Clone;
fn buffer_create_info() -> BufferCreateInfo;
fn allocation_create_info() -> AllocationCreateInfo;
fn to_buffer_data(data: &T) -> Self::BufferData;
fn create_buffer(
memory_allocator: &Arc<StandardMemoryAllocator>,
data: &T,
) -> Result<Subbuffer<[Self::BufferData]>, Validated<AllocateBufferError>> {
let buffer_data = Self::to_buffer_data(data);
Buffer::from_iter(
memory_allocator.clone(),
Self::buffer_create_info(),
Self::allocation_create_info(),
[buffer_data],
)
}
fn update_buffer(
buffer: &Subbuffer<[Self::BufferData]>,
data: &T,
) -> Result<(), Box<dyn Error>> {
let buffer_data = Self::to_buffer_data(data);
let mut write_guard = buffer.write()?;
write_guard[0] = buffer_data;
Ok(())
}
}
pub trait AsUniformBuffer<T>: AsBindableBuffer<T> {
fn create_uniform_buffer(
memory_allocator: &Arc<StandardMemoryAllocator>,
data: &T,
) -> Result<Subbuffer<[Self::BufferData]>, Validated<AllocateBufferError>> {
Self::create_buffer(memory_allocator, data)
}
}
pub trait AsVertexBuffer<T>: AsBindableBuffer<T> {
fn create_vertex_buffer(
memory_allocator: &Arc<StandardMemoryAllocator>,
vertices: &[T],
) -> Result<Subbuffer<[Self::BufferData]>, Validated<AllocateBufferError>> {
let buffer_data: Vec<Self::BufferData> =
vertices.iter().map(|v| Self::to_buffer_data(v)).collect();
Buffer::from_iter(
memory_allocator.clone(),
Self::buffer_create_info(),
Self::allocation_create_info(),
buffer_data,
)
}
}
pub trait AsIndexBuffer<T>: AsBindableBuffer<T> {
fn create_index_buffer(
memory_allocator: &Arc<StandardMemoryAllocator>,
indices: &[T],
) -> Result<Subbuffer<[Self::BufferData]>, Validated<AllocateBufferError>> {
let buffer_data: Vec<Self::BufferData> =
indices.iter().map(|i| Self::to_buffer_data(i)).collect();
Buffer::from_iter(
memory_allocator.clone(),
Self::buffer_create_info(),
Self::allocation_create_info(),
buffer_data,
)
}
}

View file

@ -9,7 +9,7 @@ use vulkano::{
use crate::core::{input::InputManager, timer::Timer}; use crate::core::{input::InputManager, timer::Timer};
use super::mvp::Mvp; use super::{AsUniformBuffer, mvp::Mvp};
// See docs/OPENGL_VULKAN_DIFF.md // See docs/OPENGL_VULKAN_DIFF.md
const OPENGL_TO_VULKAN_Y_AXIS_FLIP: Mat4 = Mat4 { const OPENGL_TO_VULKAN_Y_AXIS_FLIP: Mat4 = Mat4 {
@ -112,11 +112,12 @@ impl Camera3D {
Vec3::Y, Vec3::Y,
); );
Mvp { let mvp = Mvp {
model: OPENGL_TO_VULKAN_Y_AXIS_FLIP.to_cols_array_2d(), model: OPENGL_TO_VULKAN_Y_AXIS_FLIP.to_cols_array_2d(),
view: view_matrix.to_cols_array_2d(), view: view_matrix.to_cols_array_2d(),
projection: self.projection.to_cols_array_2d(), projection: self.projection.to_cols_array_2d(),
} };
.into_buffer(memory_allocator)
Mvp::create_uniform_buffer(memory_allocator, &mvp)
} }
} }

View file

@ -0,0 +1,110 @@
use std::{error::Error, sync::Arc};
use vulkano::{
command_buffer::{
AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, RenderPassBeginInfo, SubpassBeginInfo,
SubpassEndInfo,
},
descriptor_set::DescriptorSet,
pipeline::{GraphicsPipeline, Pipeline},
render_pass::{Framebuffer, RenderPass},
};
pub trait AsRecordable<T> {
fn record_render_commands(
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
data: &T,
pipeline: &Arc<GraphicsPipeline>,
descriptor_sets: &[Arc<DescriptorSet>],
) -> Result<(), Box<dyn Error>>;
}
pub trait AsDrawable<T> {
type VertexBuffer;
type IndexBuffer;
fn vertex_buffer(data: &T) -> &Self::VertexBuffer;
fn index_buffer(_data: &T) -> Option<&Self::IndexBuffer> {
None
}
fn vertex_count(data: &T) -> u32;
fn index_count(_data: &T) -> u32 {
0
}
fn instance_count(_data: &T) -> u32 {
1
}
fn first_vertex(_data: &T) -> u32 {
0
}
fn first_index(_data: &T) -> u32 {
0
}
fn first_instance(_data: &T) -> u32 {
0
}
}
pub trait AsRenderPassRecordable<T> {
fn begin_render_pass(
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
_render_pass: &Arc<RenderPass>,
framebuffer: &Arc<Framebuffer>,
clear_values: Vec<Option<vulkano::format::ClearValue>>,
) -> Result<(), Box<dyn Error>> {
builder.begin_render_pass(
RenderPassBeginInfo {
clear_values,
..RenderPassBeginInfo::framebuffer(framebuffer.clone())
},
SubpassBeginInfo {
contents: vulkano::command_buffer::SubpassContents::Inline,
..Default::default()
},
)?;
Ok(())
}
fn end_render_pass(
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
) -> Result<(), Box<dyn Error>> {
builder.end_render_pass(SubpassEndInfo::default())?;
Ok(())
}
fn record_render_pass_commands(
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
data: &T,
) -> Result<(), Box<dyn Error>>;
}
pub trait AsRenderableObject<T>: AsRecordable<T> + AsDrawable<T> {
fn record_complete_render(
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
data: &T,
pipeline: &Arc<GraphicsPipeline>,
descriptor_sets: &[Arc<DescriptorSet>],
) -> Result<(), Box<dyn Error>> {
builder.bind_pipeline_graphics(pipeline.clone())?;
if !descriptor_sets.is_empty() {
builder.bind_descriptor_sets(
vulkano::pipeline::PipelineBindPoint::Graphics,
pipeline.layout().clone(),
0,
descriptor_sets.iter().cloned().collect::<Vec<_>>(),
)?;
}
Self::record_render_commands(builder, data, pipeline, descriptor_sets)?;
Ok(())
}
}

View file

@ -14,6 +14,13 @@ pub mod mvp;
pub mod transform; pub mod transform;
pub mod vertex; pub mod vertex;
pub mod buffer;
pub mod command;
pub mod resource;
pub use buffer::{AsBindableBuffer, AsIndexBuffer, AsUniformBuffer, AsVertexBuffer};
pub use command::{AsDrawable, AsRecordable};
pub trait AsBindableDescriptorSet<T> { pub trait AsBindableDescriptorSet<T> {
fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding>; fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding>;

View file

@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use std::sync::Arc; use std::sync::Arc;
use vulkano::buffer::{ use vulkano::buffer::{
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, AllocateBufferError, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
}; };
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
use vulkano::descriptor_set::layout::{ use vulkano::descriptor_set::layout::{
@ -13,7 +13,7 @@ use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, Standar
use vulkano::shader::ShaderStages; use vulkano::shader::ShaderStages;
use vulkano::{Validated, VulkanError}; use vulkano::{Validated, VulkanError};
use crate::core::render::primitives::AsBindableDescriptorSet; use crate::core::render::primitives::{AsBindableBuffer, AsBindableDescriptorSet, AsUniformBuffer};
#[derive(BufferContents, Clone, Copy)] #[derive(BufferContents, Clone, Copy)]
#[repr(C)] #[repr(C)]
@ -28,22 +28,35 @@ impl Mvp {
self, self,
memory_allocator: &Arc<StandardMemoryAllocator>, memory_allocator: &Arc<StandardMemoryAllocator>,
) -> Result<Subbuffer<[Mvp]>, Validated<AllocateBufferError>> { ) -> Result<Subbuffer<[Mvp]>, Validated<AllocateBufferError>> {
Buffer::from_iter( Self::create_uniform_buffer(memory_allocator, &self)
memory_allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::UNIFORM_BUFFER,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
[self],
)
} }
} }
impl AsBindableBuffer<Mvp> for Mvp {
type BufferData = Mvp;
fn buffer_create_info() -> BufferCreateInfo {
BufferCreateInfo {
usage: BufferUsage::UNIFORM_BUFFER,
..Default::default()
}
}
fn allocation_create_info() -> AllocationCreateInfo {
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
}
}
fn to_buffer_data(data: &Mvp) -> Self::BufferData {
*data
}
}
impl AsUniformBuffer<Mvp> for Mvp {}
impl AsBindableDescriptorSet<Subbuffer<[Mvp]>> for Mvp { impl AsBindableDescriptorSet<Subbuffer<[Mvp]>> for Mvp {
fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding> { fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding> {
BTreeMap::<u32, DescriptorSetLayoutBinding>::from_iter([( BTreeMap::<u32, DescriptorSetLayoutBinding>::from_iter([(

View file

@ -0,0 +1,208 @@
use std::{
collections::HashMap,
error::Error,
fmt::{self, Debug, Display},
hash::Hash,
sync::Arc,
};
#[derive(Debug, Clone)]
pub struct ResourceLoadError {
pub message: String,
}
impl Display for ResourceLoadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Resource load error: {}", self.message)
}
}
impl Error for ResourceLoadError {}
impl ResourceLoadError {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
}
pub trait AsResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
/// Type d'erreur lors du chargement
type LoadError: Error;
/// Charge une ressource avec l'handle donné
fn load(&mut self, handle: THandle, resource: TResource) -> Result<(), Self::LoadError>;
/// Récupère une ressource par son handle
fn get(&self, handle: &THandle) -> Option<&TResource>;
/// Récupère une ressource mutable par son handle
fn get_mut(&mut self, handle: &THandle) -> Option<&mut TResource>;
/// Supprime une ressource
fn unload(&mut self, handle: &THandle) -> Option<TResource>;
/// Vérifie si une ressource est chargée
fn is_loaded(&self, handle: &THandle) -> bool;
/// Retourne tous les handles chargés
fn loaded_handles(&self) -> Vec<THandle>;
/// Nettoie toutes les ressources
fn clear(&mut self);
}
/// Implémentation basique d'un gestionnaire de ressources
pub struct BasicResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
resources: HashMap<THandle, TResource>,
}
impl<THandle, TResource> BasicResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
pub fn new() -> Self {
Self {
resources: HashMap::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
resources: HashMap::with_capacity(capacity),
}
}
}
impl<THandle, TResource> Default for BasicResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
fn default() -> Self {
Self::new()
}
}
impl<THandle, TResource> AsResourceManager<THandle, TResource>
for BasicResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
type LoadError = ResourceLoadError;
fn load(&mut self, handle: THandle, resource: TResource) -> Result<(), Self::LoadError> {
self.resources.insert(handle, resource);
Ok(())
}
fn get(&self, handle: &THandle) -> Option<&TResource> {
self.resources.get(handle)
}
fn get_mut(&mut self, handle: &THandle) -> Option<&mut TResource> {
self.resources.get_mut(handle)
}
fn unload(&mut self, handle: &THandle) -> Option<TResource> {
self.resources.remove(handle)
}
fn is_loaded(&self, handle: &THandle) -> bool {
self.resources.contains_key(handle)
}
fn loaded_handles(&self) -> Vec<THandle> {
self.resources.keys().cloned().collect()
}
fn clear(&mut self) {
self.resources.clear();
}
}
pub struct ThreadSafeResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
resources: Arc<std::sync::RwLock<HashMap<THandle, Arc<TResource>>>>,
}
impl<THandle, TResource> ThreadSafeResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
pub fn new() -> Self {
Self {
resources: Arc::new(std::sync::RwLock::new(HashMap::new())),
}
}
pub fn load(&self, handle: THandle, resource: TResource) -> Result<(), ResourceLoadError> {
let mut resources = self
.resources
.write()
.map_err(|_| ResourceLoadError::new("Failed to acquire write lock"))?;
resources.insert(handle, Arc::new(resource));
Ok(())
}
pub fn get(&self, handle: &THandle) -> Option<Arc<TResource>> {
let resources = self.resources.read().ok()?;
resources.get(handle).cloned()
}
pub fn unload(&self, handle: &THandle) -> Option<Arc<TResource>> {
let mut resources = self.resources.write().ok()?;
resources.remove(handle)
}
pub fn is_loaded(&self, handle: &THandle) -> bool {
if let Ok(resources) = self.resources.read() {
resources.contains_key(handle)
} else {
false
}
}
pub fn loaded_handles(&self) -> Vec<THandle> {
if let Ok(resources) = self.resources.read() {
resources.keys().cloned().collect()
} else {
Vec::new()
}
}
pub fn clear(&self) {
if let Ok(mut resources) = self.resources.write() {
resources.clear();
}
}
}
impl<THandle, TResource> Clone for ThreadSafeResourceManager<THandle, TResource>
where
THandle: Clone + Eq + Hash + Debug,
{
fn clone(&self) -> Self {
Self {
resources: Arc::clone(&self.resources),
}
}
}
pub trait AsAsyncLoadable<THandle>
where
THandle: Clone + Eq + Hash + Debug + Send + Sync,
{
type Resource: Send + Sync;
type LoadError: Error + Send + Sync;
async fn load_async(handle: THandle) -> Result<Self::Resource, Self::LoadError>;
}

View file

@ -3,20 +3,20 @@ use std::sync::Arc;
use glam::{Mat4, Quat, Vec3}; use glam::{Mat4, Quat, Vec3};
use vulkano::{ use vulkano::{
Validated, Validated,
buffer::{ buffer::{AllocateBufferError, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer},
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
},
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
pipeline::graphics::vertex_input::Vertex, pipeline::graphics::vertex_input::Vertex,
}; };
use crate::core::render::primitives::{AsBindableBuffer, AsVertexBuffer};
pub struct Transform { pub struct Transform {
pub position: Vec3, pub position: Vec3,
pub rotation: Quat, pub rotation: Quat,
pub scale: Vec3, pub scale: Vec3,
} }
#[derive(BufferContents, Vertex)] #[derive(BufferContents, Vertex, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct TransformRaw { pub struct TransformRaw {
#[format(R32G32B32A32_SFLOAT)] #[format(R32G32B32A32_SFLOAT)]
@ -59,23 +59,37 @@ impl Transform {
memory_allocator: &Arc<StandardMemoryAllocator>, memory_allocator: &Arc<StandardMemoryAllocator>,
transforms: &[Transform], transforms: &[Transform],
) -> Result<Subbuffer<[TransformRaw]>, Validated<AllocateBufferError>> { ) -> Result<Subbuffer<[TransformRaw]>, Validated<AllocateBufferError>> {
let transform_raws: Vec<TransformRaw> = TransformRaw::create_vertex_buffer(
transforms.iter().map(|t| t.to_raw_tranform()).collect(); memory_allocator,
&transforms
let buffer = Buffer::from_iter( .iter()
memory_allocator.clone(), .map(|t| t.to_raw_tranform())
BufferCreateInfo { .collect::<Vec<_>>(),
usage: BufferUsage::VERTEX_BUFFER, )
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
transform_raws,
)?;
Ok(buffer)
} }
} }
impl AsBindableBuffer<TransformRaw> for TransformRaw {
type BufferData = TransformRaw;
fn buffer_create_info() -> BufferCreateInfo {
BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER,
..Default::default()
}
}
fn allocation_create_info() -> AllocationCreateInfo {
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
}
}
fn to_buffer_data(data: &TransformRaw) -> Self::BufferData {
*data
}
}
impl AsVertexBuffer<TransformRaw> for TransformRaw {}

View file

@ -1,7 +1,11 @@
use vulkano::buffer::BufferContents; use vulkano::buffer::BufferContents;
use vulkano::buffer::{BufferCreateInfo, BufferUsage};
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter};
use vulkano::pipeline::graphics::vertex_input::Vertex; use vulkano::pipeline::graphics::vertex_input::Vertex;
#[derive(BufferContents, Vertex)] use crate::core::render::primitives::{AsBindableBuffer, AsIndexBuffer, AsVertexBuffer};
#[derive(BufferContents, Vertex, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct Vertex2D { pub struct Vertex2D {
#[format(R32G32_SFLOAT)] #[format(R32G32_SFLOAT)]
@ -11,7 +15,7 @@ pub struct Vertex2D {
pub uv: [f32; 2], pub uv: [f32; 2],
} }
#[derive(BufferContents, Vertex)] #[derive(BufferContents, Vertex, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct Vertex3D { pub struct Vertex3D {
#[format(R32G32B32_SFLOAT)] #[format(R32G32B32_SFLOAT)]
@ -20,3 +24,78 @@ pub struct Vertex3D {
#[format(R32G32_SFLOAT)] #[format(R32G32_SFLOAT)]
pub uv: [f32; 2], pub uv: [f32; 2],
} }
impl AsBindableBuffer<Vertex2D> for Vertex2D {
type BufferData = Vertex2D;
fn buffer_create_info() -> BufferCreateInfo {
BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER,
..Default::default()
}
}
fn allocation_create_info() -> AllocationCreateInfo {
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
}
}
fn to_buffer_data(data: &Vertex2D) -> Self::BufferData {
*data
}
}
impl AsVertexBuffer<Vertex2D> for Vertex2D {}
impl AsBindableBuffer<Vertex3D> for Vertex3D {
type BufferData = Vertex3D;
fn buffer_create_info() -> BufferCreateInfo {
BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER,
..Default::default()
}
}
fn allocation_create_info() -> AllocationCreateInfo {
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
}
}
fn to_buffer_data(data: &Vertex3D) -> Self::BufferData {
*data
}
}
impl AsVertexBuffer<Vertex3D> for Vertex3D {}
impl AsBindableBuffer<u32> for u32 {
type BufferData = u32;
fn buffer_create_info() -> BufferCreateInfo {
BufferCreateInfo {
usage: BufferUsage::INDEX_BUFFER,
..Default::default()
}
}
fn allocation_create_info() -> AllocationCreateInfo {
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
}
}
fn to_buffer_data(data: &u32) -> Self::BufferData {
*data
}
}
impl AsIndexBuffer<u32> for u32 {}

View file

@ -1,16 +1,15 @@
use std::{collections::BTreeMap, error::Error, sync::Arc}; use std::{error::Error, sync::Arc};
use vulkano::{ use vulkano::{
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}, buffer::Subbuffer,
command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}, command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer},
descriptor_set::{ descriptor_set::{
DescriptorSet, WriteDescriptorSet, DescriptorSet, allocator::StandardDescriptorSetAllocator,
allocator::StandardDescriptorSetAllocator, layout::DescriptorSetLayoutCreateInfo,
layout::{DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType},
}, },
device::Device, device::Device,
format::Format, format::Format,
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, memory::allocator::StandardMemoryAllocator,
pipeline::{ pipeline::{
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
PipelineShaderStageCreateInfo, PipelineShaderStageCreateInfo,
@ -27,11 +26,13 @@ use vulkano::{
}, },
layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}, layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags},
}, },
shader::ShaderStages,
}; };
use crate::core::render::{ use crate::core::render::{
primitives::{AsBindableDescriptorSet, mvp::Mvp, transform::TransformRaw, vertex::Vertex3D}, primitives::{
AsBindableDescriptorSet, AsDrawable, AsIndexBuffer, AsRecordable, AsVertexBuffer, mvp::Mvp,
transform::TransformRaw, vertex::Vertex3D,
},
texture::Texture, texture::Texture,
}; };
@ -80,6 +81,14 @@ pub struct Square {
pipeline: Arc<GraphicsPipeline>, pipeline: Arc<GraphicsPipeline>,
} }
/// Structure pour encapsuler les données de rendu du Square
pub struct SquareRenderData<'a> {
pub square: &'a Square,
pub mvp_uniform: &'a Subbuffer<[Mvp]>,
pub transform_uniform: &'a Subbuffer<[TransformRaw]>,
pub texture: &'a Texture,
}
impl Square { impl Square {
pub fn new( pub fn new(
device: &Arc<Device>, device: &Arc<Device>,
@ -87,32 +96,9 @@ impl Square {
swapchain_format: Format, swapchain_format: Format,
depth_format: Format, depth_format: Format,
) -> Result<Self, Box<dyn Error>> { ) -> Result<Self, Box<dyn Error>> {
let vertex_buffer = Buffer::from_iter( let vertex_buffer = Vertex3D::create_vertex_buffer(memory_allocator, &VERTICES)?;
memory_allocator.clone(),
BufferCreateInfo { let index_buffer = u32::create_index_buffer(memory_allocator, &INDICES)?;
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())? let vs = shaders::vs::load(device.clone())?
.entry_point("main") .entry_point("main")
@ -197,6 +183,13 @@ impl Square {
transform_uniform: &Subbuffer<[TransformRaw]>, transform_uniform: &Subbuffer<[TransformRaw]>,
texture: &Texture, texture: &Texture,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let render_data = SquareRenderData {
square: self,
mvp_uniform,
transform_uniform,
texture,
};
let layouts = self.pipeline.layout().set_layouts(); let layouts = self.pipeline.layout().set_layouts();
let uniform_descriptor_set = let uniform_descriptor_set =
@ -205,25 +198,86 @@ impl Square {
let texture_descriptor_set = let texture_descriptor_set =
Texture::as_descriptor_set(descriptor_set_allocator, &layouts[1], texture)?; Texture::as_descriptor_set(descriptor_set_allocator, &layouts[1], texture)?;
command_buffer.bind_pipeline_graphics(self.pipeline.clone())?; // Utiliser les nouveaux traits pour le rendu
command_buffer.bind_descriptor_sets( Self::record_render_commands(
PipelineBindPoint::Graphics, command_buffer,
self.pipeline.layout().clone(), &render_data,
0, &self.pipeline,
vec![uniform_descriptor_set, texture_descriptor_set], &[uniform_descriptor_set, texture_descriptor_set],
)?; )?;
command_buffer
.bind_vertex_buffers(0, (self.vertex_buffer.clone(), transform_uniform.clone()))?;
command_buffer.bind_index_buffer(self.index_buffer.clone())?;
unsafe { Ok(())
command_buffer.draw_indexed( }
INDICES.len() as u32, }
transform_uniform.len() as u32,
0, // Implémentation des nouveaux traits pour Square
0, impl<'a> AsDrawable<SquareRenderData<'a>> for Square {
0, type VertexBuffer = Subbuffer<[Vertex3D]>;
)?; type IndexBuffer = Subbuffer<[u32]>;
fn vertex_buffer(data: &SquareRenderData<'a>) -> &'a Self::VertexBuffer {
&data.square.vertex_buffer
}
fn index_buffer(data: &SquareRenderData<'a>) -> Option<&'a Self::IndexBuffer> {
Some(&data.square.index_buffer)
}
fn vertex_count(_data: &SquareRenderData<'a>) -> u32 {
VERTICES.len() as u32
}
fn index_count(_data: &SquareRenderData<'a>) -> u32 {
INDICES.len() as u32
}
fn instance_count(data: &SquareRenderData<'a>) -> u32 {
data.transform_uniform.len() as u32
}
}
impl<'a> AsRecordable<SquareRenderData<'a>> for Square {
fn record_render_commands(
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
data: &SquareRenderData<'a>,
pipeline: &Arc<GraphicsPipeline>,
descriptor_sets: &[Arc<DescriptorSet>],
) -> Result<(), Box<dyn Error>> {
// Bind pipeline
builder.bind_pipeline_graphics(pipeline.clone())?;
// Bind descriptor sets
builder.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline.layout().clone(),
0,
descriptor_sets.iter().cloned().collect::<Vec<_>>(),
)?;
// Bind buffers
builder.bind_vertex_buffers(
0,
(
Self::vertex_buffer(data).clone(),
data.transform_uniform.clone(),
),
)?;
if let Some(index_buffer) = Self::index_buffer(data) {
builder.bind_index_buffer(index_buffer.clone())?;
unsafe {
builder.draw_indexed(
Self::index_count(data),
Self::instance_count(data),
0,
0,
0,
)?;
}
} else {
unsafe {
builder.draw(Self::vertex_count(data), Self::instance_count(data), 0, 0)?;
}
} }
Ok(()) Ok(())