Search code examples
rustvulkanunsafe

Why am I getting "(exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)" when trying to map a vkDeviceMemory into application address space?


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.


Solution

  • The main issue was with the std::mem::size_of_val() function. For some reason, it was giving incorrect values.