I am learning how to use Vulkan. I am using the Vulkan bindings for Rust called Ash. I am trying to write the index buffer data to the vkDeviceMemory. the program is crashing when index_slice.copy_from_slice(&index_buffer_data)
is called. The issue only arises when I am using my own model loader. the model loader returns a vector of vertex objects, and an index buffer. its ok when I hard code in the vertex buffer data and index buffer data, and when I hard code in their lengths to their respective buffer create infos, but when I move to using the model loader, and size_of_val() on the buffers returned by the model loader, I get the error.
This is the area that it crashes in:
let (vertex_buffer_data, index_buffer_data) = loader::load(path_to_obj).unwrap();
// let index_buffer_data = [0u32, 1, 2];
let index_buffer_create_info = vk::BufferCreateInfo {
size: std::mem::size_of_val(&index_buffer_data) as u64,
usage: vk::BufferUsageFlags::INDEX_BUFFER,
sharing_mode: vk::SharingMode::EXCLUSIVE,
..Default::default()
};
let index_buffer = base.device.create_buffer(&index_buffer_create_info, None).unwrap();
let index_buffer_memory_req = base.device.get_buffer_memory_requirements(index_buffer);
let index_buffer_memory_index = find_memory_type_index(
&index_buffer_memory_req,
&base.device_memory_properties,
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
)
.expect("cant find subtable memory type for index buffer");
let index_allocate_info = vk::MemoryAllocateInfo {
allocation_size: index_buffer_memory_req.size,
memory_type_index: index_buffer_memory_index,
..Default::default()
};
let index_buffer_memory = base
.device
.allocate_memory(&index_allocate_info, None)
.unwrap();
let index_ptr = base
.device
.map_memory(
index_buffer_memory,
0, // offset
index_buffer_memory_req.size,
vk::MemoryMapFlags::empty(),
)
.unwrap();
assert_eq!(index_buffer_memory_req.size, std::mem::size_of_val(&index_buffer_data) as u64);
let mut index_slice = Align::new(
index_ptr,
align_of::<u32>() as u64,
index_buffer_memory_req.size
);
println!("This prints");
index_slice.copy_from_slice(&index_buffer_data); // <---- causes the crash
println!("This will not print");
base.device.unmap_memory(index_buffer_memory); connectiont that map memory creates.
base.device
.bind_buffer_memory(index_buffer, index_buffer_memory, 0)
.unwrap();
Here is the model loader code:
use std::fs::metadata;
use std::fs::File;
use std::io::Read;
use std::io::{BufRead, BufReader};
use std::time::{Duration, Instant};
use crate::types::Vertex;
pub fn load(
path: &str,
) -> Result<(Vec<Vertex>, Vec<u32>), Box<dyn std::error::Error>> {
let file = File::open(path)?;
let reader = BufReader::new(&file);
let metadata = file.metadata();
let predicted_size = if metadata.is_ok() {
metadata.unwrap().len() / 3.0 as u64
} else {
0
};
let mut vertex_buffer: Vec<(f32, f32, f32)> = Vec::with_capacity(predicted_size as usize);
let mut vertex_normals: Vec<(f32, f32, f32)> = Vec::with_capacity(predicted_size as usize);
let mut index_buffer: Vec<u32> = Vec::with_capacity(predicted_size as usize);
for line in reader.lines() {
let line = line?;
if line.is_empty() {
continue;
}
let line_split: Vec<&str> = line.split_whitespace().collect();
match line_split[0] {
"v" => {
let parsed: Vec<f32> = line_split[1..]
.iter()
.map(|str| str.parse::<f32>().unwrap())
.collect();
vertex_buffer.push((parsed[0], parsed[1], parsed[2]));
},
"vn" => {
let parsed: Vec<f32> = line_split[1..]
.iter()
.map(|str| str.parse::<f32>().unwrap())
.collect();
vertex_normals.push((parsed[0], parsed[1], parsed[2]));
}
"f" => {
let parsed: Vec<u32> = line_split[1..]
.iter()
.map(|str| str.parse::<u32>().unwrap() - 1)
.collect();
index_buffer.extend(parsed);
},
_ => {}
}
}
let vertex_normals_included = vertex_buffer.len() == vertex_normals.len();
let mut vertices: Vec<Vertex> = Vec::with_capacity(vertex_buffer.len());
if vertex_normals_included {
for index in 0..vertex_buffer.len() {
let vertex = vertex_buffer[index];
let normal = vertex_normals[index];
let vertex_struct = Vertex {
pos: [vertex.0, vertex.1, vertex.2, 1.0],
color: [0.0; 4],
normal: [normal.0, normal.1, normal.2]
};
vertices.push(vertex_struct);
}
} else {
for index in 0..vertex_buffer.len() {
let vertex = vertex_buffer[index];
let vertex_struct = Vertex {
pos: [vertex.0, vertex.1, vertex.2, 1.0],
color: [0.0; 4],
normal: [0.0; 3]
};
vertices.push(vertex_struct);
}
}
Ok((vertices, index_buffer))
}
This is the source code for .copy_from_slice()
:
impl<T: Copy> Align<T> {
pub fn copy_from_slice(&mut self, slice: &[T]) {
use std::slice::from_raw_parts_mut;
if self.elem_size == size_of::<T>() as u64 {
unsafe {
let mapped_slice = from_raw_parts_mut(self.ptr.cast(), slice.len());
mapped_slice.copy_from_slice(slice);
}
} else {
for (i, val) in self.iter_mut().enumerate().take(slice.len()) {
*val = slice[i];
}
}
}
}
I tried many things. When I print out the vertex_buffer_data and index_buffer_data it looks good. I checked to make sure all the buffer create info had the right size and usage. I checked that the alignments are correct.
The main issue was with the std::mem::size_of_val()
function. For some reason, it was giving incorrect values.