This commit is contained in:
zack 2024-12-29 14:56:13 -05:00
parent ca14ad7d08
commit 0877a91373
No known key found for this signature in database
GPG key ID: 5F873416BCF59F35
5 changed files with 803 additions and 257 deletions

122
Cargo.lock generated
View file

@ -216,6 +216,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bincode"
version = "1.3.3"
@ -303,6 +309,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
version = "1.9.0"
@ -751,6 +763,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "flate2"
version = "1.0.35"
@ -859,6 +880,45 @@ dependencies = [
"libm",
]
[[package]]
name = "gltf"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7"
dependencies = [
"base64",
"byteorder",
"gltf-json",
"image",
"lazy_static",
"serde_json",
"urlencoding",
]
[[package]]
name = "gltf-derive"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51"
dependencies = [
"inflections",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gltf-json"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14"
dependencies = [
"gltf-derive",
"serde",
"serde_derive",
"serde_json",
]
[[package]]
name = "gpu-allocator"
version = "0.25.0"
@ -1066,6 +1126,20 @@ dependencies = [
"icu_properties",
]
[[package]]
name = "image"
version = "0.25.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
dependencies = [
"bytemuck",
"byteorder-lite",
"num-traits",
"png",
"zune-core",
"zune-jpeg",
]
[[package]]
name = "indenter"
version = "0.3.3"
@ -1083,6 +1157,12 @@ dependencies = [
"serde",
]
[[package]]
name = "inflections"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a"
[[package]]
name = "internal-iterator"
version = "0.2.3"
@ -1274,6 +1354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
@ -1723,6 +1804,19 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "png"
version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide 0.8.2",
]
[[package]]
name = "polling"
version = "3.7.4"
@ -2136,6 +2230,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "slab"
version = "0.4.9"
@ -2579,6 +2679,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf16_iter"
version = "1.0.5"
@ -2621,6 +2727,7 @@ dependencies = [
"egui",
"egui-ash",
"glam 0.22.0",
"gltf",
"gpu-allocator",
"gpu-profiler",
"puffin",
@ -3447,3 +3554,18 @@ dependencies = [
"quote",
"syn",
]
[[package]]
name = "zune-core"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
[[package]]
name = "zune-jpeg"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
dependencies = [
"zune-core",
]

View file

@ -1,7 +1,7 @@
#![cfg_attr(target_arch = "spirv", no_std)]
use shaders_shared::UniformBufferObject;
use spirv_std::spirv;
use spirv_std::{glam::Vec2, image::Image2d, spirv, Image, Sampler};
use glam::{Mat3, Vec3, Vec4, Vec4Swizzles};
@ -35,10 +35,13 @@ pub fn main_vs(
pub fn main_fs(
frag_world_position: Vec3,
frag_world_normal: Vec3,
out_color: &mut Vec4,
frag_tex_coord: Vec2,
#[spirv(uniform, descriptor_set = 0, binding = 0)] ubo: &UniformBufferObject,
#[spirv(descriptor_set = 0, binding = 1)] texture: &Image2d,
#[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler,
out_color: &mut Vec4,
) {
let base_color = ubo.model_color;
let base_color = texture.sample(*sampler, frag_tex_coord);
let light_pos = Vec3::new(2.0, 2.0, -2.0);
// Calculate light direction
@ -49,9 +52,13 @@ pub fn main_fs(
let lambertian = f32::max(n.dot(l), 0.0);
// Ambient lighting
let ambient = Vec3::splat(0.1);
let ambient = Vec3::splat(0.2);
// Combine texture color with model color
let color_from_texture = Vec3::new(base_color.x, base_color.y, base_color.z);
let combined_color = color_from_texture * ubo.model_color;
// Final color calculation with gamma correction
let color = (base_color * lambertian + ambient).powf(2.2);
let color = (combined_color * lambertian + ambient).powf(2.2);
*out_color = Vec4::from((color, 1.0));
}

View file

@ -22,6 +22,7 @@ puffin_egui = { git = "https://github.com/EmbarkStudios/puffin", rev = "5ac4e541
gpu-profiler = { git = "https://github.com/zackartz/gpu-profiler", features = [
"use-ash",
] }
gltf = { version = "1.4.1", features = ["import"] }
[build-dependencies]
spirv-builder.workspace = true

Binary file not shown.

View file

@ -1,16 +1,18 @@
use ash::{
extensions::khr::{Surface, Swapchain},
vk::{self, Buffer},
vk::{self, Buffer, ImageAspectFlags},
Device,
};
use color_eyre::owo_colors::Color;
use egui::Vec2;
use egui_ash::EguiCommand;
use glam::{Mat4, Vec3};
use gpu_allocator::vulkan::{Allocation, Allocator};
use gltf::json::buffer::View;
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, Allocator};
use shaders_shared::UniformBufferObject;
use std::{
ffi::CString,
mem::ManuallyDrop,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
@ -34,6 +36,7 @@ macro_rules! include_spirv {
struct Vertex {
position: Vec3,
normal: Vec3,
tex_coords: Vec2,
}
impl Vertex {
fn get_binding_descriptions() -> [vk::VertexInputBindingDescription; 1] {
@ -44,7 +47,7 @@ impl Vertex {
.build()]
}
fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] {
[
vk::VertexInputAttributeDescription::builder()
.binding(0)
@ -58,10 +61,605 @@ impl Vertex {
.format(vk::Format::R32G32B32_SFLOAT)
.offset(4 * 3)
.build(),
vk::VertexInputAttributeDescription::builder()
.binding(0)
.location(2)
.format(vk::Format::R32G32_SFLOAT)
.offset(24)
.build(),
]
}
}
pub struct Texture {
image: vk::Image,
image_allocation: Option<Allocation>,
image_view: vk::ImageView,
sampler: vk::Sampler,
}
impl Texture {
fn new(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
width: u32,
height: u32,
data: &[u8],
) -> Self {
let mut allocator = allocator.lock().unwrap();
let buffer_size = data.len() as u64;
let staging_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(buffer_size)
.usage(vk::BufferUsageFlags::TRANSFER_SRC),
None,
)
.expect("failed to create_buffer")
};
let staging_allocation = allocator
.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "staging_buffer",
requirements: unsafe { device.get_buffer_memory_requirements(staging_buffer) },
location: gpu_allocator::MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
staging_buffer,
staging_allocation.memory(),
staging_allocation.offset(),
)
.expect("failed to bind_buffer_memory");
let ptr = staging_allocation.mapped_ptr().unwrap().as_ptr() as *mut u8;
ptr.copy_from_nonoverlapping(data.as_ptr(), data.len());
}
let image = unsafe {
device
.create_image(
&vk::ImageCreateInfo::builder()
.image_type(vk::ImageType::TYPE_2D)
.format(vk::Format::R8G8B8A8_SRGB)
.extent(vk::Extent3D {
width,
height,
depth: 1,
})
.mip_levels(1)
.array_layers(1)
.samples(vk::SampleCountFlags::TYPE_1)
.tiling(vk::ImageTiling::OPTIMAL)
.usage(vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED)
.initial_layout(vk::ImageLayout::UNDEFINED),
None,
)
.expect("failed to create image")
};
let image_allocation = allocator
.allocate(&AllocationCreateDesc {
name: "texture image",
requirements: unsafe { device.get_image_memory_requirements(image) },
location: gpu_allocator::MemoryLocation::GpuOnly,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("failed to allocate memory");
unsafe {
device
.bind_image_memory(image, image_allocation.memory(), image_allocation.offset())
.expect("failed to bind image memory")
};
let command_buffer = unsafe {
let command_buffer = device
.allocate_command_buffers(
&vk::CommandBufferAllocateInfo::builder()
.command_pool(command_pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1),
)
.expect("failed to allocate command_buffer")[0];
device
.begin_command_buffer(
command_buffer,
&vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
)
.expect("failed to begin_command_buffer");
let barrier = vk::ImageMemoryBarrier::builder()
.old_layout(vk::ImageLayout::UNDEFINED)
.new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 0,
level_count: 1,
base_array_layer: 0,
layer_count: 1,
})
.src_access_mask(vk::AccessFlags::empty())
.dst_access_mask(vk::AccessFlags::TRANSFER_WRITE);
device.cmd_pipeline_barrier(
command_buffer,
vk::PipelineStageFlags::TOP_OF_PIPE,
vk::PipelineStageFlags::TRANSFER,
vk::DependencyFlags::empty(),
&[],
&[],
&[barrier.build()],
);
let region = vk::BufferImageCopy::builder()
.image_subresource(vk::ImageSubresourceLayers {
aspect_mask: vk::ImageAspectFlags::COLOR,
mip_level: 0,
base_array_layer: 0,
layer_count: 1,
})
.image_extent(vk::Extent3D {
width,
height,
depth: 1,
});
device.cmd_copy_buffer_to_image(
command_buffer,
staging_buffer,
image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[region.build()],
);
let barrier = vk::ImageMemoryBarrier::builder()
.old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
.new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 0,
level_count: 1,
base_array_layer: 0,
layer_count: 1,
})
.src_access_mask(vk::AccessFlags::TRANSFER_WRITE)
.dst_access_mask(vk::AccessFlags::SHADER_READ);
device.cmd_pipeline_barrier(
command_buffer,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::DependencyFlags::empty(),
&[],
&[],
&[barrier.build()],
);
device
.end_command_buffer(command_buffer)
.expect("failed to end the command buffer");
device
.queue_submit(
queue,
&[vk::SubmitInfo::builder()
.command_buffers(&[command_buffer])
.build()],
vk::Fence::null(),
)
.expect("failed to submit queue");
device.queue_wait_idle(queue).expect("failed to wait queue");
device.free_command_buffers(command_pool, &[command_buffer]);
device.destroy_buffer(staging_buffer, None);
allocator
.free(staging_allocation)
.expect("failed to free memory");
};
let image_view = unsafe {
device
.create_image_view(
&vk::ImageViewCreateInfo::builder()
.image(image)
.view_type(vk::ImageViewType::TYPE_2D)
.format(vk::Format::R8G8B8A8_SRGB)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 0,
level_count: 1,
base_array_layer: 0,
layer_count: 1,
}),
None,
)
.expect("failed to create image view")
};
let sampler = unsafe {
device
.create_sampler(
&vk::SamplerCreateInfo::builder()
.mag_filter(vk::Filter::LINEAR)
.min_filter(vk::Filter::LINEAR)
.address_mode_u(vk::SamplerAddressMode::REPEAT)
.address_mode_v(vk::SamplerAddressMode::REPEAT)
.address_mode_w(vk::SamplerAddressMode::REPEAT)
.anisotropy_enable(true)
.max_anisotropy(16.0)
.border_color(vk::BorderColor::INT_OPAQUE_BLACK)
.unnormalized_coordinates(false)
.compare_enable(false)
.compare_op(vk::CompareOp::ALWAYS)
.mipmap_mode(vk::SamplerMipmapMode::LINEAR)
.mip_lod_bias(0.0)
.min_lod(0.0)
.max_lod(0.0),
None,
)
.expect("failed to create sampler")
};
Self {
image,
image_allocation: Some(image_allocation),
image_view,
sampler,
}
}
fn destroy(&mut self, device: &Device, allocator: &mut Allocator) {
unsafe {
device.destroy_sampler(self.sampler, None);
device.destroy_image_view(self.image_view, None);
device.destroy_image(self.image, None);
}
if let Some(allocation) = self.image_allocation.take() {
allocator.free(allocation).expect("failed to free memory");
}
}
}
pub struct Mesh {
vertex_buffer: Buffer,
vertex_buffer_allocation: Option<Allocation>,
vertex_count: u32,
transform: Mat4,
texture: Option<Texture>,
}
pub struct Model {
meshes: Vec<Mesh>,
}
fn load_texture_from_gltf(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
texture: &gltf::Texture,
buffers: &[gltf::buffer::Data],
path: &Path,
) -> Option<Texture> {
let image = texture.source();
let data = match image.source() {
gltf::image::Source::View { view, .. } => {
// Handle embedded buffer view
match view.buffer().source() {
gltf::buffer::Source::Bin => {
let start = view.offset();
let end = start + view.length();
buffers[0][start..end].to_vec()
}
_ => return None,
}
}
gltf::image::Source::Uri { .. } => {
// For URI sources, we'll get the data directly from gltf::image::Data
let img_data =
gltf::image::Data::from_source(image.source(), Some(path), buffers).ok()?;
img_data.pixels.clone().to_vec()
}
};
let img_data = gltf::image::Data::from_source(image.source(), Some(path), buffers).ok()?;
Some(Texture::new(
device,
allocator,
command_pool,
queue,
img_data.width,
img_data.height,
&data,
))
}
impl Model {
fn load(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
path: &str,
) -> Self {
let path = Path::new(path);
let base_path = path.parent();
let (document, buffers, _) = gltf::import(path).expect("failed to load GLTF");
let mut meshes = Vec::new();
for scene in document.scenes() {
for node in scene.nodes() {
meshes.extend(process_node(
node,
Mat4::IDENTITY,
&buffers,
device,
allocator.clone(),
command_pool,
queue,
base_path.unwrap(),
));
}
}
Self { meshes }
}
}
fn process_node(
node: gltf::Node,
parent_transform: Mat4,
buffers: &[gltf::buffer::Data],
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
path: &Path,
) -> Vec<Mesh> {
let mut meshes = Vec::new();
let local_transform = {
let (translation, rotation, scale) = node.transform().decomposed();
Mat4::from_scale_rotation_translation(
Vec3::from(scale),
glam::Quat::from_array(rotation),
Vec3::from(translation),
)
};
let world_transform = parent_transform * local_transform;
if let Some(mesh) = node.mesh() {
for primitive in mesh.primitives() {
let texture = primitive
.material()
.pbr_metallic_roughness()
.base_color_texture()
.and_then(|tex| {
load_texture_from_gltf(
device,
allocator.clone(),
command_pool,
queue,
&tex.texture(),
buffers,
path,
)
});
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
if let (Some(positions), Some(normals), Some(tex_coords)) = (
reader.read_positions(),
reader.read_normals(),
reader.read_tex_coords(0),
) {
let mut vertices = Vec::new();
let indicies = reader
.read_indices()
.map(|indicies| indicies.into_u32().collect::<Vec<_>>())
.unwrap_or_else(|| (0..positions.len() as u32).collect());
let positions: Vec<_> = positions.collect();
let normals: Vec<_> = normals.collect();
let tex_coords: Vec<_> = tex_coords.into_f32().collect();
for &index in indicies.iter() {
let i = index as usize;
let vertex = Vertex {
position: Vec3::new(positions[i][0], positions[i][1], positions[i][2]),
normal: Vec3::new(normals[i][0], normals[i][1], normals[i][2]),
tex_coords: Vec2::new(tex_coords[i][0], tex_coords[i][1]),
};
vertices.push(vertex);
}
let (vertex_buffer, vertex_buffer_allocation) =
create_vertex_buffer(device, allocator.clone(), command_pool, queue, &vertices);
meshes.push(Mesh {
vertex_buffer,
vertex_buffer_allocation: Some(vertex_buffer_allocation),
vertex_count: vertices.len() as u32,
transform: world_transform,
texture,
});
}
}
}
for child in node.children() {
meshes.extend(process_node(
child,
world_transform,
buffers,
device,
allocator.clone(),
command_pool,
queue,
path,
));
}
meshes
}
fn create_vertex_buffer(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
vertices: &[Vertex],
) -> (Buffer, Allocation) {
let mut allocator = allocator.lock().unwrap();
let vertex_buffer_size = std::mem::size_of_val(vertices) as u64;
let staging_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(vertex_buffer_size)
.usage(vk::BufferUsageFlags::TRANSFER_SRC),
None,
)
.expect("failed to create buffer")
};
let staging_allocation = allocator
.allocate(&AllocationCreateDesc {
name: "Staging vertex buffer",
requirements: unsafe { device.get_buffer_memory_requirements(staging_buffer) },
location: gpu_allocator::MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
staging_buffer,
staging_allocation.memory(),
staging_allocation.offset(),
)
.expect("failed to bind buffer memory");
let ptr = staging_allocation.mapped_ptr().unwrap().as_ptr() as *mut Vertex;
ptr.copy_from_nonoverlapping(vertices.as_ptr(), vertices.len());
}
let vertex_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(vertex_buffer_size)
.usage(
vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
),
None,
)
.expect("failed to create buffer")
};
let vertex_allocation = allocator
.allocate(&AllocationCreateDesc {
name: "Vertex Buffer",
requirements: unsafe { device.get_buffer_memory_requirements(vertex_buffer) },
location: gpu_allocator::MemoryLocation::GpuOnly,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
vertex_buffer,
vertex_allocation.memory(),
vertex_allocation.offset(),
)
.expect("failed to bind buffer memory");
}
let command_buffer = unsafe {
device
.allocate_command_buffers(
&vk::CommandBufferAllocateInfo::builder()
.command_pool(command_pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1),
)
.expect("failed to allocate command buffer")[0]
};
unsafe {
device
.begin_command_buffer(
command_buffer,
&vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT)
.build(),
)
.expect("failed to begin command_buffer");
device.cmd_copy_buffer(
command_buffer,
staging_buffer,
vertex_buffer,
&[vk::BufferCopy::builder().size(vertex_buffer_size).build()],
);
device
.end_command_buffer(command_buffer)
.expect("Failed to end command buffer");
device
.queue_submit(
queue,
&[vk::SubmitInfo::builder()
.command_buffers(&[command_buffer])
.build()],
vk::Fence::null(),
)
.expect("failed to submit queue");
device.queue_wait_idle(queue).expect("failed to wait queue");
device.free_command_buffers(command_pool, &[command_buffer]);
}
unsafe {
device.destroy_buffer(staging_buffer, None);
}
allocator
.free(staging_allocation)
.expect("failed to free memory");
(vertex_buffer, vertex_allocation)
}
pub struct RendererInner {
width: u32,
height: u32,
@ -90,9 +688,9 @@ pub struct RendererInner {
depth_image_views: Vec<vk::ImageView>,
pipeline: vk::Pipeline,
pipeline_layout: vk::PipelineLayout,
vertex_buffer: Buffer,
vertex_buffer_allocation: Option<Allocation>,
vertex_count: u32,
model: Model,
command_buffers: Vec<vk::CommandBuffer>,
in_flight_fences: Vec<vk::Fence>,
image_available_semaphores: Vec<vk::Semaphore>,
@ -541,7 +1139,7 @@ impl RendererInner {
.rasterizer_discard_enable(false)
.polygon_mode(vk::PolygonMode::FILL)
.cull_mode(vk::CullModeFlags::BACK)
.front_face(vk::FrontFace::CLOCKWISE)
.front_face(vk::FrontFace::COUNTER_CLOCKWISE)
.depth_bias_enable(false)
.line_width(1.0);
let stencil_op = vk::StencilOpState::builder()
@ -603,178 +1201,6 @@ impl RendererInner {
(graphics_pipeline, pipeline_layout)
}
fn load_model_and_create_vertex_buffer(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
) -> (Buffer, Allocation, u32) {
let mut allocator = allocator.lock().unwrap();
let vertices = {
let model_obj = tobj::load_obj(
"./assets/suzanne.obj",
&tobj::LoadOptions {
single_index: true,
triangulate: true,
ignore_points: true,
ignore_lines: true,
},
)
.expect("Failed to load model");
let mut vertices = vec![];
let (models, _) = model_obj;
for m in models.iter() {
let mesh = &m.mesh;
for &i in mesh.indices.iter() {
let i = i as usize;
let vertex = Vertex {
position: Vec3::new(
mesh.positions[3 * i],
mesh.positions[3 * i + 1],
mesh.positions[3 * i + 2],
),
normal: Vec3::new(
mesh.normals[3 * i],
mesh.normals[3 * i + 1],
mesh.normals[3 * i + 2],
),
};
vertices.push(vertex);
}
}
vertices
};
let vertex_buffer_size = vertices.len() as u64 * std::mem::size_of::<Vertex>() as u64;
let temporary_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(vertex_buffer_size)
.usage(vk::BufferUsageFlags::TRANSFER_SRC),
None,
)
.expect("Failed to create buffer")
};
let temporary_buffer_memory_requirements =
unsafe { device.get_buffer_memory_requirements(temporary_buffer) };
let temporary_buffer_allocation = allocator
.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "Temporary Vertex Buffer",
requirements: temporary_buffer_memory_requirements,
location: gpu_allocator::MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("Failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
temporary_buffer,
temporary_buffer_allocation.memory(),
temporary_buffer_allocation.offset(),
)
.expect("Failed to bind buffer memory")
}
unsafe {
let ptr = temporary_buffer_allocation.mapped_ptr().unwrap().as_ptr() as *mut Vertex;
ptr.copy_from_nonoverlapping(vertices.as_ptr(), vertices.len());
}
let vertex_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(vertex_buffer_size)
.usage(
vk::BufferUsageFlags::TRANSFER_DST
| vk::BufferUsageFlags::VERTEX_BUFFER,
),
None,
)
.expect("Failed to create buffer")
};
let vertex_buffer_memory_requirements =
unsafe { device.get_buffer_memory_requirements(vertex_buffer) };
let vertex_buffer_allocation = allocator
.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "Vertex Buffer",
requirements: vertex_buffer_memory_requirements,
location: gpu_allocator::MemoryLocation::GpuOnly,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("Failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
vertex_buffer,
vertex_buffer_allocation.memory(),
vertex_buffer_allocation.offset(),
)
.expect("Failed to bind buffer memory")
}
let cmd = unsafe {
device
.allocate_command_buffers(
&vk::CommandBufferAllocateInfo::builder()
.command_pool(command_pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1),
)
.expect("Failed to allocate command buffer")[0]
};
unsafe {
device
.begin_command_buffer(
cmd,
&vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
)
.expect("Failed to begin command buffer");
device.cmd_copy_buffer(
cmd,
temporary_buffer,
vertex_buffer,
&[vk::BufferCopy::builder()
.src_offset(0)
.dst_offset(0)
.size(vertex_buffer_size)
.build()],
);
device
.end_command_buffer(cmd)
.expect("Failed to end command buffer");
device
.queue_submit(
queue,
&[vk::SubmitInfo::builder().command_buffers(&[cmd]).build()],
vk::Fence::null(),
)
.expect("Failed to submit queue");
device.queue_wait_idle(queue).expect("Failed to wait queue");
device.free_command_buffers(command_pool, &[cmd]);
}
allocator
.free(temporary_buffer_allocation)
.expect("Failed to free memory");
unsafe {
device.destroy_buffer(temporary_buffer, None);
}
(
vertex_buffer,
vertex_buffer_allocation,
vertices.len() as u32,
)
}
fn create_command_buffers(
device: &Device,
command_pool: vk::CommandPool,
@ -1036,13 +1462,15 @@ impl RendererInner {
);
let (pipeline, pipeline_layout) =
Self::create_graphics_pipeline(&device, &descriptor_set_layouts, render_pass);
let (vertex_buffer, vertex_buffer_allocation, vertex_count) =
Self::load_model_and_create_vertex_buffer(
println!("loading model!");
let model = Model::load(
&device,
allocator.clone(),
command_pool,
queue,
"./sponza/NewSponza_Main_glTF_003.gltf",
);
println!("loaded!");
let command_buffers =
Self::create_command_buffers(&device, command_pool, swapchain_images.len());
let (in_flight_fences, image_available_semaphores, render_finished_semaphores) =
@ -1074,9 +1502,7 @@ impl RendererInner {
depth_image_views,
pipeline,
pipeline_layout,
vertex_buffer,
vertex_buffer_allocation: Some(vertex_buffer_allocation),
vertex_count,
model,
command_buffers,
in_flight_fences,
image_available_semaphores,
@ -1144,22 +1570,6 @@ impl RendererInner {
self.recreate_swapchain(width, height, &mut egui_cmd);
}
// unsafe {
// self.device
// .wait_for_fences(
// std::slice::from_ref(&self.in_flight_fences[self.current_frame]),
// true,
// u64::MAX,
// )
// .expect("failed to wait for fences");
//
// self.device
// .reset_fences(std::slice::from_ref(
// &self.in_flight_fences[self.current_frame],
// ))
// .expect("failed to reset fences");
// }
unsafe {
puffin::profile_scope!("wait_for_fences");
self.device.wait_for_fences(
@ -1210,26 +1620,6 @@ impl RendererInner {
)
};
let ubo = UniformBufferObject {
model: Mat4::from_rotation_y(rotate_y.to_radians()),
view,
proj: Mat4::perspective_rh(
self.camera_fov.to_radians(),
width as f32 / height as f32,
0.1,
10.0,
),
model_color: self.model_color,
};
unsafe {
let ptr = self.uniform_buffer_allocations[self.current_frame]
.mapped_ptr()
.unwrap()
.as_ptr() as *mut UniformBufferObject;
ptr.copy_from_nonoverlapping([ubo].as_ptr(), 1);
}
let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
unsafe {
@ -1272,6 +1662,7 @@ impl RendererInner {
vk::PipelineBindPoint::GRAPHICS,
self.pipeline,
);
self.device.cmd_set_viewport(
self.command_buffers[self.current_frame],
0,
@ -1292,6 +1683,28 @@ impl RendererInner {
.extent(self.surface_extent),
),
);
for mesh in &self.model.meshes {
let model_matrix = Mat4::from_rotation_y(rotate_y.to_radians()) * mesh.transform;
let ubo = UniformBufferObject {
model: model_matrix,
view,
proj: Mat4::perspective_rh(
self.camera_fov.to_radians(),
width as f32 / height as f32,
0.1,
1000.0,
),
model_color: self.model_color,
};
let ptr = self.uniform_buffer_allocations[self.current_frame]
.mapped_ptr()
.unwrap()
.as_ptr() as *mut UniformBufferObject;
ptr.copy_from_nonoverlapping(&ubo, 1);
self.device.cmd_bind_descriptor_sets(
self.command_buffers[self.current_frame],
vk::PipelineBindPoint::GRAPHICS,
@ -1304,16 +1717,17 @@ impl RendererInner {
self.device.cmd_bind_vertex_buffers(
self.command_buffers[self.current_frame],
0,
&[self.vertex_buffer],
&[mesh.vertex_buffer],
&[0],
);
self.device.cmd_draw(
self.command_buffers[self.current_frame],
self.vertex_count,
mesh.vertex_count,
1,
0,
0,
);
}
self.device
.cmd_end_render_pass(self.command_buffers[self.current_frame]);
@ -1393,12 +1807,14 @@ impl RendererInner {
for semaphore in self.render_finished_semaphores.drain(..) {
self.device.destroy_semaphore(semaphore, None);
}
self.device.destroy_buffer(self.vertex_buffer, None);
if let Some(vertex_buffer_allocation) = self.vertex_buffer_allocation.take() {
for mesh in &mut self.model.meshes {
self.device.destroy_buffer(mesh.vertex_buffer, None);
if let Some(vertex_buffer_allocation) = mesh.vertex_buffer_allocation.take() {
allocator
.free(vertex_buffer_allocation)
.expect("Failed to free memory");
}
}
self.device.destroy_pipeline(self.pipeline, None);
self.device
.destroy_pipeline_layout(self.pipeline_layout, None);