-1

I was able to update my vertex buffer using the vkCmdUpdateBuffer method, while following the solution to a similar problem asked in this stack thread. However, I am struggling to implement the solution utilizing a staging buffer and the vkCmdCopyBuffer method, and I don't quite understand how the synchronization would work. My attempts so far have only crashed my application and have not triggered any validation layers.

The error code in the command prompt is (process 27240) exited with code -1073741819.

My current render-loop looks like this:

while (!glfwWindowShouldClose(window)) {
    glfwPollEvents();
    std::jthread t1(glfwSetKeyCallback, window, userInput);

    uniforms.update(window, Extent); //updates uniform values
    ubo.update(currentFrame, &uniforms); //updates uniform buffer with new values

    uint32_t imageIndex;

    vkAquireImage(imageIndex);

    // Compute Queue
    vkComputeSync();
    computePpln.computeCommand(computeBuffers[currentFrame], setCount, sets);
    vkSubmitComputeQueue();

    // Render Queue
    
    //pipeline.model.update(testVtx.data()); // Line where I had my various different update functions
    // the size required to update the buffer is unchanged, testVtx is the same size as the original vector<Vertex> content  
    beginRender(commandBuffers[currentFrame], swapChainFramebuffers[imageIndex]); //Begins recording of render commands
    
    ptclPpln.render(commandBuffers[currentFrame], ssbo.Buffer[currentFrame], setCount, sets); // Draws points indexed
    pipeline.render(commandBuffers[currentFrame], setCount, sets); // Draws pipeline.model
    
    endRender(commandBuffers[currentFrame]); //ends recording of render commands

    VkSemaphore waitSemaphores[] = { computeFinishedSemaphores[currentFrame], imageAvailableSemaphores[currentFrame]};
    VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };

    vkSubmitGraphicsQueue<2>(waitSemaphores, waitStages); // submits render commands
    vkPresentImage(imageIndex);

    currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}
vkDeviceWaitIdle(device);

All of the attempts that I made to the model.update() function have not worked except for unmapping the memory used by the buffer and remapping the memory to void* data[0]:

void updateVTX(VkCPU& CPU, uint32_t currentFrame, const void* content) {
    vkUnmapMemory(VkGPU::device, map[0][1].mMemory);

    vkMapMemory(VkGPU::device, map[0][1].mMemory, 0, map[0][1].mSize, 0, &data[0]);
    memcpy(data[0], content, (size_t)map[0][1].mSize);

    CPU.beginSingleTimeCommands(CPU.commandBuffers[currentFrame]);

    VkBufferCopy copyRegion{};
    copyRegion.size = map[0][1].mSize;
    copyRegion.srcOffset = 0; //Tried implementing something like the solution in the other thread here, but could not get it to work without remapping the memory
    copyRegion.dstOffset = 0;
    vkCmdCopyBuffer(CPU.commandBuffers[currentFrame], map[0][1].mBuffer, map[0][0].mBuffer, 1, &copyRegion);

    vkEndCommandBuffer(CPU.commandBuffers[currentFrame]);

    VkSubmitInfo submitInfo
    { VK_STRUCTURE_TYPE_SUBMIT_INFO };
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &CPU.commandBuffers[currentFrame];

    vkQueueSubmit(VkGPU::graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
    vkQueueWaitIdle(VkGPU::graphicsQueue);
}

As other threads have made me aware of, unmapping and remapping memory unnecessarily should be avoided, so I am really trying to avoid using this method. Adapting the update method used by my UBO class to my VBO results in the application crashing without triggering any validation layers.

My only clue into the solution is how I am creating my buffers. My UBO is created by:

// Staging Buffer
createBuffer(stagingBuffer, stagingBufferMemory, bufferSize,
            VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Buffer
createBuffer(Buffer[i], Memory[i], bufferSize,
                VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
                VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

Whereas my VBO buffers are created by:

// Staging Buffer
createBuffer(stagingBuffer, stagingBufferMemory, bufferSize,
            VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Buffer
createBuffer(Buffer, BufferMemory, bufferSize,
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

I tried changing the memory properties for the VBO buffer to match the UBO buffer, but that did not fix the problem. Please help, I am at a complete loss for a solution.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174

1 Answers1

-1

Based on the code you provided, there are a few issues that could be causing the crashes in your application. Let's go through them and provide possible solutions:

  1. Buffer creation: In your VBO buffer creation code, you are mistakenly reusing the staging buffer and staging buffer memory instead of creating separate buffers for the staging and vertex buffer. This can lead to memory access issues and crashes. Make sure to create distinct buffers and memory objects for the staging and vertex buffer.

  2. Staging buffer usage: In the VBO buffer creation, you are creating a staging buffer, but it seems that you are not actually using it during the update process. To use the staging buffer correctly, you should:

    • Map the staging buffer memory and copy the updated vertex data to the mapped memory.
    • Create a device-local vertex buffer with the VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT flags and VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT memory properties.
    • Use the vkCmdCopyBuffer command to copy the data from the staging buffer to the vertex buffer.
  3. Synchronization issues: It seems that you are not properly synchronizing the staging buffer updates and the copy command. To ensure correct synchronization, you should use Vulkan synchronization primitives such as fences and semaphores. Here's a high-level overview of the steps involved:

    • Create a fence (vkCreateFence) to synchronize the CPU updates and GPU copy.
    • Submit the copy command to the graphics queue (vkCmdCopyBuffer) and signal the fence.
    • Wait for the fence to be signaled before mapping the staging buffer memory and updating the vertex data again.
    • Reset the fence (vkResetFences) before reusing it in the next frame.

Here's a modified version of your update function, taking into account the above suggestions:

void updateVTX(VkCPU& CPU, VkBuffer stagingBuffer, VkDeviceMemory stagingBufferMemory, VkBuffer vertexBuffer, size_t bufferSize, uint32_t currentFrame, const void* content) {
    // Copy vertex data directly to the mapped staging buffer memory
    void* mappedData;
    vkMapMemory(VkGPU::device, stagingBufferMemory, 0, bufferSize, 0, &mappedData);
    memcpy(mappedData, content, bufferSize);

    // Create a fence for synchronization
    VkFenceCreateInfo fenceCreateInfo{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
    VkFence copyFence;
    vkCreateFence(VkGPU::device, &fenceCreateInfo, nullptr, &copyFence);

    // Submit the copy command to the graphics queue
    VkCommandBuffer copyCommandBuffer = CPU.beginSingleTimeCommands();
    VkBufferCopy copyRegion{};
    copyRegion.size = bufferSize;
    vkCmdCopyBuffer(copyCommandBuffer, stagingBuffer, vertexBuffer, 1, &copyRegion);
    CPU.endSingleTimeCommands(copyCommandBuffer);

    // Submit the copy command buffer and signal the fence
    VkSubmitInfo submitInfo{ VK_STRUCTURE_TYPE_SUBMIT_INFO };
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &copyCommandBuffer;
    vkQueueSubmit(VkGPU::graphicsQueue, 1, &submitInfo, copyFence);

    // Wait for the fence to be signaled
    vkWaitForFences(VkGPU::device, 1, &copyFence, VK_TRUE, UINT64_MAX);
    vkResetFences(VkGPU::device, 1, &copyFence);

    // No need to unmap staging buffer memory if it was already mapped
}

Note that the above code assumes that you have correctly set up the stagingBuffer, stagingBufferMemory, vertexBuffer, and vertexBufferMemory variables. Make sure that you create and destroy these objects correctly.

Additionally, make sure you have proper error handling and validation layer checks in place to catch any potential issues during Vulkan API calls.

Remember to adapt the code to fit your specific application architecture, as the provided code is a general guideline.

  • 1
    "*Map the staging buffer memory*" No, the staging memory should already be mapped. The only reason to unmap mappable memory is if you're going to delete it. – Nicol Bolas Jul 11 '23 at 23:16
  • Apologies for the confusion. If the staging memory is already mapped, there is no need to unmap it unless you intend to delete or release it. You can omit the `vkUnmapMemory` call in that case. The mapping of mappable memory can persist as long as it's needed and can be accessed by the CPU. Thank you for pointing out the correction. – Maurice Moss Jul 11 '23 at 23:18
  • 1
    @Nicol Bolas, he's literally using ChatGPT. I've used it for some of my problems before and it replies in *exactly* the same manner. However, I will try the fence part of his answer, since that is different to what I am doing at the moment and could be a potential solution. – ModernEraCaveman Jul 12 '23 at 00:54
  • @Maurice Moss, adding the fence did not solve the problem, and my application still crashes with the same exit code. – ModernEraCaveman Jul 12 '23 at 01:00
  • 1
    MauriceMoss - Your seven answers (and even your comments) this month appear likely to have been entirely or partially written by AI (e.g., ChatGPT). Please be aware that [posting AI-generated content is not allowed here](//meta.stackoverflow.com/q/421831). If you used an AI tool to assist with any answer, I would encourage you to delete it. – NotTheDr01ds Jul 12 '23 at 16:06
  • 1
    **Readers should review this answer carefully and critically, as AI-generated information often contains fundamental errors and misinformation.** If you observe quality issues and/or have reason to believe that this answer was generated by AI, please leave feedback accordingly. – NotTheDr01ds Jul 12 '23 at 16:06