vkCmdCopyBuffer не влияет на передачу промежуточного буфера

#c #vulkan

#c #vulkan

Вопрос:

для средства визуализации vulkan, использующего vulkan-hpp и Vulkan Memory Allocator, я пытаюсь передать данные вершин на графический процессор с использованием промежуточного буфера. Без использования промежуточного промежуточного буфера передача работает, и сетки могут быть отрисованы без проблем (просто один буфер, созданный с помощью VMA_MEMORY_USAGE_CPU_TO_GPU). Но при вызове vkCmdCopyBuffer результирующий VertexBuffer содержит только 0 (проверено с помощью NSight). Думая, что может потребоваться синхронизация с использованием барьеров, я попробовал следующий код, но все еще сталкиваюсь с той же проблемой.

Может быть, есть необходимость синхронизировать командный буфер, выполняющий копирование, с более поздней привязкой командного буфера и извлечением из буфера вершин? Хотя я не видел, чтобы это делалось или упоминалось ни в каких руководствах, с которыми я сталкивался.

 // vulkan initialization
// VmaAllocator initialization

std::vector<Vertex> vertices = { /*filled*/ };
auto vertexBufferSize = vertices.size() * sizeof(Vertex);

vk::Buffer stagingBuffer;
auto ci = vk::BufferCreateInfo().
    setUsage(vk::BufferUsageFlagBits::eTransferSrc).
    setSharingMode(vk::SharingMode::eExclusive).
    setSize(vertexBufferSize );
VmaAllocationCreateInfo allocationCI = {};
allocationCI.usage = VMA_MEMORY_USAGE_CPU_ONLY;
vmaCreateBuffer(allocator, (VkBufferCreateInfo*)amp;ci,
    amp;allocationCI, (VkBuffer*)amp;stagingBuffer, amp;allocation, nullptr);
void* pVBufMem = nullptr;
vmaMapMemory(allocator, allocation, amp;pVBufMem);
std::memcpy(pVBufMem, vertices.size(), vertexBufferSize );
vmaUnmapMemory(allocator, allocation);

vk::Buffer vertexBuffer;
ci = vk::BufferCreateInfo().
    setUsage(vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eVertexBuffer).
    setSharingMode(vk::SharingMode::eExclusive).
    setSize(vertexBufferSize);
allocationCI = {};
allocationCI.usage = VMA_MEMORY_USAGE_GPU_ONLY;
vmaCreateBuffer(allocator, (VkBufferCreateInfo*)amp;ci,
    amp;allocationCI, (VkBuffer*)amp;vertexBuffer, amp;allocation, nullptr);

// copy staging buffer to vertex buffer
auto allocCI = vk::CommandBufferAllocateInfo().
    setCommandBufferCount(1).
    setCommandPool(pool).
    setLevel(vk::CommandBufferLevel::ePrimary);
auto cmd = device.allocateCommandBuffers(allocCI)[0];
cmd.begin({ vk::CommandBufferUsageFlagBits::eOneTimeSubmit });

// barrier host write -> copyBuffer read
auto bufferMemoryBarrier = vk::BufferMemoryBarrier()
.setBuffer(stagingBuffer)
.setSize(vertexBufferSize)
.setSrcAccessMask(vk::AccessFlagBits::eMemoryWrite)
.setDstAccessMask(vk::AccessFlagBits::eTransferRead)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
cmd.pipelineBarrier(
    vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands, {},
    { }, { bufferMemoryBarrier }, { });

cmd.copyBuffer(stagingBuffer, vertexBuffer, { 0, 0, vertexBufferSize });

// copyBuffer write -> vertex read
bufferMemoryBarrier = vk::BufferMemoryBarrier()
.setBuffer(vertexBuffer)
.setSize(vertexBufferSize)
.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite)
.setDstAccessMask(vk::AccessFlagBits::eVertexAttributeRead)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
cmd.pipelineBarrier(
    vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands, {},
    { }, { bufferMemoryBarrier }, { });

cmd.end();
auto submitInfo = vk::SubmitInfo().
    setCommandBufferCount(1).
    setPCommandBuffers(amp;cmdBuffer);
queue.submit({ submitInfo }, {});
queue.waitIdle();
  

Комментарии:

1. Есть какое-либо сообщение от уровней проверки?

2. стандартная проверка включена и не выдает сообщений

3. vmaCreateBuffer записывает llocation , но ваш vmaMapMemory использует allocation . Также memcpy использует pData и size . Можно было бы предположить, что это должно быть vertices.data() и vertexBufferSize . Также vertices является пустым вектором.

4. спасибо, что указали на ошибки, я ввел ошибки при копировании и упрощении моего кода.

Ответ №1:

Это исправлено. Третий аргумент copybuffer был неправильно инициализирован. Правильный вызов должен быть таким:

 cmd.copyBuffer(stagingBuffer, vertexBuffer, {{ 0, 0, vertexBufferSize }});
  

Строка

 cmd.copyBuffer(stagingBuffer, vertexBuffer, { 0, 0, vertexBufferSize });
  

фактически создает три отдельные области копирования.