render: Add AsBindableDescriptorSet

This commit is contained in:
Florian RICHER 2025-06-05 13:30:55 +02:00
parent b7bc6478e2
commit 5539381f46
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
4 changed files with 115 additions and 47 deletions

View file

@ -1,4 +1,25 @@
use std::{collections::BTreeMap, sync::Arc};
use vulkano::{
Validated, VulkanError,
descriptor_set::{
DescriptorSet,
allocator::StandardDescriptorSetAllocator,
layout::{DescriptorSetLayout, DescriptorSetLayoutBinding},
},
};
pub mod camera;
pub mod mvp;
pub mod transform;
pub mod vertex;
pub trait AsBindableDescriptorSet<T> {
fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding>;
fn as_descriptor_set(
descriptor_set_allocator: &Arc<StandardDescriptorSetAllocator>,
layout: &Arc<DescriptorSetLayout>,
data: &T,
) -> Result<Arc<DescriptorSet>, Validated<VulkanError>>;
}

View file

@ -1,10 +1,19 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use vulkano::Validated;
use vulkano::buffer::{
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
};
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
use vulkano::descriptor_set::layout::{
DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType,
};
use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet};
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator};
use vulkano::shader::ShaderStages;
use vulkano::{Validated, VulkanError};
use crate::core::render::primitives::AsBindableDescriptorSet;
#[derive(BufferContents, Clone, Copy)]
#[repr(C)]
@ -34,3 +43,28 @@ impl Mvp {
)
}
}
impl AsBindableDescriptorSet<Subbuffer<[Mvp]>> for Mvp {
fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding> {
BTreeMap::<u32, DescriptorSetLayoutBinding>::from_iter([(
0,
DescriptorSetLayoutBinding {
stages: ShaderStages::VERTEX,
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
},
)])
}
fn as_descriptor_set(
descriptor_set_allocator: &Arc<StandardDescriptorSetAllocator>,
layout: &Arc<DescriptorSetLayout>,
data: &Subbuffer<[Mvp]>,
) -> Result<Arc<DescriptorSet>, Validated<VulkanError>> {
DescriptorSet::new(
descriptor_set_allocator.clone(),
layout.clone(),
[WriteDescriptorSet::buffer(0, data.clone())],
[],
)
}
}

View file

@ -1,10 +1,15 @@
use std::{path::Path, sync::Arc};
use std::{collections::BTreeMap, error::Error, sync::Arc};
use anyhow::Error;
use image::{DynamicImage, EncodableLayout};
use image::DynamicImage;
use vulkano::{
Validated, VulkanError,
buffer::{Buffer, BufferCreateInfo, BufferUsage},
command_buffer::{AutoCommandBufferBuilder, CopyBufferToImageInfo, PrimaryAutoCommandBuffer},
descriptor_set::{
DescriptorSet, WriteDescriptorSet,
allocator::StandardDescriptorSetAllocator,
layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType},
},
device::Device,
format::Format,
image::{
@ -13,8 +18,11 @@ use vulkano::{
view::ImageView,
},
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
shader::ShaderStages,
};
use crate::core::render::primitives::AsBindableDescriptorSet;
pub struct Texture {
texture: Arc<ImageView>,
sampler: Arc<Sampler>,
@ -30,7 +38,7 @@ impl Texture {
memory_allocator: &Arc<StandardMemoryAllocator>,
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
path: &str,
) -> Result<Self, Error> {
) -> Result<Self, Box<dyn Error>> {
let _span = tracing::info_span!("texture_load_from_file", path = path);
let bytes = std::fs::read(path)?;
@ -42,7 +50,7 @@ impl Texture {
memory_allocator: &Arc<StandardMemoryAllocator>,
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
bytes: &[u8],
) -> Result<Self, Error> {
) -> Result<Self, Box<dyn Error>> {
let image = image::load_from_memory(bytes)?;
Self::from_dynamic_image(device, memory_allocator, builder, image)
}
@ -52,7 +60,7 @@ impl Texture {
memory_allocator: &Arc<StandardMemoryAllocator>,
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
image: DynamicImage,
) -> Result<Self, Error> {
) -> Result<Self, Box<dyn Error>> {
let _span = tracing::info_span!("texture_from_dynamic_image");
let image_data = image.to_rgba8();
@ -121,3 +129,40 @@ impl Texture {
&self.sampler
}
}
impl AsBindableDescriptorSet<Texture> for Texture {
fn as_descriptor_set_layout_bindings() -> BTreeMap<u32, DescriptorSetLayoutBinding> {
BTreeMap::<u32, DescriptorSetLayoutBinding>::from_iter([
(
0,
DescriptorSetLayoutBinding {
stages: ShaderStages::FRAGMENT,
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler)
},
),
(
1,
DescriptorSetLayoutBinding {
stages: ShaderStages::FRAGMENT,
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::SampledImage)
},
),
])
}
fn as_descriptor_set(
descriptor_set_allocator: &Arc<StandardDescriptorSetAllocator>,
layout: &Arc<DescriptorSetLayout>,
data: &Texture,
) -> Result<Arc<DescriptorSet>, Validated<VulkanError>> {
DescriptorSet::new(
descriptor_set_allocator.clone(),
layout.clone(),
[
WriteDescriptorSet::sampler(0, data.sampler.clone()),
WriteDescriptorSet::image_view(1, data.texture.clone()),
],
[],
)
}
}

View file

@ -31,7 +31,7 @@ use vulkano::{
};
use crate::core::render::{
primitives::{mvp::Mvp, transform::TransformRaw, vertex::Vertex3D},
primitives::{AsBindableDescriptorSet, mvp::Mvp, transform::TransformRaw, vertex::Vertex3D},
texture::Texture,
};
@ -130,29 +130,8 @@ impl Square {
PipelineShaderStageCreateInfo::new(fs),
];
let vertex_bindings = BTreeMap::<u32, DescriptorSetLayoutBinding>::from_iter([(
0,
DescriptorSetLayoutBinding {
stages: ShaderStages::VERTEX,
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
},
)]);
let fragment_bindings = BTreeMap::<u32, DescriptorSetLayoutBinding>::from_iter([
(
0,
DescriptorSetLayoutBinding {
stages: ShaderStages::FRAGMENT,
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler)
},
),
(
1,
DescriptorSetLayoutBinding {
stages: ShaderStages::FRAGMENT,
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::SampledImage)
},
),
]);
let vertex_bindings = Mvp::as_descriptor_set_layout_bindings();
let texture_bindings = Texture::as_descriptor_set_layout_bindings();
let vertex_descriptor_set_layout = DescriptorSetLayoutCreateInfo {
bindings: vertex_bindings,
@ -160,7 +139,7 @@ impl Square {
};
let fragment_descriptor_set_layout = DescriptorSetLayoutCreateInfo {
bindings: fragment_bindings,
bindings: texture_bindings,
..Default::default()
};
@ -220,22 +199,11 @@ impl Square {
) -> Result<(), Box<dyn Error>> {
let layouts = self.pipeline.layout().set_layouts();
let uniform_descriptor_set = DescriptorSet::new(
descriptor_set_allocator.clone(),
layouts[0].clone(),
[WriteDescriptorSet::buffer(0, mvp_uniform.clone())],
[],
)?;
let uniform_descriptor_set =
Mvp::as_descriptor_set(descriptor_set_allocator, &layouts[0], mvp_uniform)?;
let texture_descriptor_set = DescriptorSet::new(
descriptor_set_allocator.clone(),
layouts[1].clone(),
[
WriteDescriptorSet::sampler(0, texture.get_sampler().clone()),
WriteDescriptorSet::image_view(1, texture.get_texture().clone()),
],
[],
)?;
let texture_descriptor_set =
Texture::as_descriptor_set(descriptor_set_allocator, &layouts[1], texture)?;
command_buffer.bind_pipeline_graphics(self.pipeline.clone())?;
command_buffer.bind_descriptor_sets(