简体   繁体   中英

Memcpy Fails with access violation - Vulkan copying to vertex buffer

I'm trying to pass some data to the GPU in Vulkan. AFAIK, the only way to do this is using memcpy. This works with a smaller vector, but with a larger model, I get a an access violation exception when I try to do it. The same method working in another implementation on the same machine. What should I be looking for? Thanks

Here's the code

void VulkanAllocator::createVertexBuffer(std::vector<HE2_Vertex>* vertices, VkBuffer& vertexBuffer, VkDeviceMemory& vertexBufferMemory)
{
VkDeviceSize bufferSize = sizeof(HE2_Vertex) * vertices->size();

VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;

createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);

VkMemoryRequirements memReqs;

vkGetBufferMemoryRequirements(vdi->device, stagingBuffer, &memReqs);


void* data;

if (vkMapMemory(vdi->device, stagingBufferMemory, 0, (size_t)memReqs.size, 0, &data) != VK_SUCCESS)
{
    throw std::exception("Bad Memory map!");
}

memcpy(data, vertices->data(), (size_t)memReqs.size); //Crash after this line


vkUnmapMemory(vdi->device, stagingBufferMemory);

createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);

copyBuffer(stagingBuffer, vertexBuffer, bufferSize);

vkDestroyBuffer(vdi->device, stagingBuffer, nullptr);
vkFreeMemory(vdi->device, stagingBufferMemory, nullptr);
}

And CreateBuffer looks like this

void VulkanAllocator::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory)
{
    VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

if (vkCreateBuffer(vdi->device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS)
{
    throw std::runtime_error("Unable to create vertex buffer");
}

VkMemoryRequirements memRequirements;

vkGetBufferMemoryRequirements(vdi->device, buffer, &memRequirements);

VkMemoryAllocateInfo allocInfo = {};

allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

if (vkAllocateMemory(vdi->device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS)
{
    throw std::runtime_error("failed to allocate vertex buffer memory");
}

vkBindBufferMemory(vdi->device, buffer, bufferMemory, 0);
}

The vector is created like so (if you've gone through https://vulkan-tutorial.com/ you're probably recognizing my refactoring). HE2_Model simply contains a vector of HE2_Vertex s and a vector of uint32_t s. I don't know if relevant but I haven't written a copy constructor for HE2_Vertex .

HE2_Model* model = new HE2_Model();

//Using tiny_obj_loader to pull in from a file
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;

std::string warn, err;

if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename.c_str()))
{
    throw std::runtime_error("Couldn't load model!");
}

std::unordered_map<HE2_Vertex, uint32_t> uniqueVertices = { };

for (const auto& shape : shapes)
{
    for (const auto& index : shape.mesh.indices)
    {
        HE2_Vertex vertex = {};

        vertex.pos = {
            attrib.vertices[3 * index.vertex_index + 0],
            attrib.vertices[3 * index.vertex_index + 1],
            attrib.vertices[3 * index.vertex_index + 2] };


        vertex.texCoord = {
            attrib.texcoords[2 * index.texcoord_index + 0],
            1.0f - attrib.texcoords[2 * index.texcoord_index + 1] };

        if (uniqueVertices.count(vertex) == 0)
        {
            uniqueVertices[vertex] = static_cast<uint32_t>(model->vertices.size());
            model->vertices.push_back(vertex);
        }

        model->indices.push_back(uniqueVertices[vertex]);
    }
}


HE2_Instance::renderBackend->onAddModel(model);

return model;

This is the line that's crashing:

memcpy(data, vertices->data(), (size_t)memReqs.size); //Crash after this line

You've said in comments that "Memreqs size is slightly larger than the bufferSize" ie memReqs.size is larger than bufferSize which is the full size of the vector ( sizeof(HE2_Vertex) * vertices->size(); ), so your memcpy is going to be reading more data from vertices->data() than it's allowed to, this is undefined behaviour which would crash sometimes. You should use this instead:

memcpy(data, vertices->data(), (size_t)bufferSize);

(and probably add something like assert(bufferSize <= memReqs.size); too)

Infuriatingly enough, this was fixed with a rebuild. I have multiple projects within the one visual studio solution, and I simply need to learn not to rely on project dependencies, the first thing I always need to do with memory error and exceptions is rebuild every project. Top tip for anyone with weird access violations and behavior etc - Rebuild Rebuild Rebuild!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM