Я планирую использовать один из примеров синхронизации vulkan в качестве справки о том, как обрабатывать редко обновляемые унифицированные буферы. В частности, я смотрел на это:
vkBeginCommandBuffer(...);
// Submission guarantees the host write being complete, as per
// https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-submission-host-writes
// So no need for a barrier before the transfer
// Copy the staging buffer contents to the vertex buffer
VkBufferCopy vertexCopyRegion = {
.srcOffset = stagingMemoryOffset,
.dstOffset = vertexMemoryOffset,
.size = vertexDataSize};
vkCmdCopyBuffer(
commandBuffer,
stagingBuffer,
vertexBuffer,
1,
&vertexCopyRegion);
// If the graphics queue and transfer queue are the same queue
if (isUnifiedGraphicsAndTransferQueue)
{
// If there is a semaphore signal + wait between this being submitted and
// the vertex buffer being used, then skip this pipeline barrier.
// Pipeline barrier before using the vertex data
// Note that this can apply to all buffers uploaded in the same way, so
// ideally batch all copies before this.
VkMemoryBarrier memoryBarrier = {
...
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT};
vkCmdPipelineBarrier(
...
VK_PIPELINE_STAGE_TRANSFER_BIT , // srcStageMask
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, // dstStageMask
1, // memoryBarrierCount
&memoryBarrier, // pMemoryBarriers
...);
vkEndCommandBuffer(...);
vkQueueSubmit(unifiedQueue, ...);
}
else
{
// Pipeline barrier to start a queue ownership transfer after the copy
VkBufferMemoryBarrier bufferMemoryBarrier = {
...
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = 0,
.srcQueueFamilyIndex = transferQueueFamilyIndex,
.dstQueueFamilyIndex = graphicsQueueFamilyIndex,
.buffer = vertexBuffer,
...};
vkCmdPipelineBarrier(
...
VK_PIPELINE_STAGE_TRANSFER_BIT , // srcStageMask
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask
1, // bufferMemoryBarrierCount
&bufferMemoryBarrier, // pBufferMemoryBarriers
...);
vkEndCommandBuffer(...);
// Ensure a semaphore is signalled here which will be waited on by the graphics queue.
vkQueueSubmit(transferQueue, ...);
// Record a command buffer for the graphics queue.
vkBeginCommandBuffer(...);
// Pipeline barrier before using the vertex buffer, after finalising the ownership transfer
VkBufferMemoryBarrier bufferMemoryBarrier = {
...
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
.srcQueueFamilyIndex = transferQueueFamilyIndex,
.dstQueueFamilyIndex = graphicsQueueFamilyIndex,
.buffer = vertexBuffer,
...};
vkCmdPipelineBarrier(
...
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, // dstStageMask
...
1, // bufferMemoryBarrierCount
&bufferMemoryBarrier, // pBufferMemoryBarriers
...);
vkEndCommandBuffer(...);
vkQueueSubmit(graphicsQueue, ...);
}
В этом примере я упрощаю его до значения:
map updated buffer which is host coherent
perform transfer in transfer queue to device local memory
make sure to put a buffer memory barrier to handle the queue ownership transfer
perform normal draw commands
make sure to put a buffer memory barrier to handle receiving of buffer in queue ownership
Должен ли я затем вернуть возможность для очереди передачи скопировать эти данные снова ? Кажется, ни один из примеров не упоминает об этом, но я мог пропустить это. Я действительно не могу понять, как добавление еще одного буферного барьера будет работать для того же буфера команд рисования, поскольку он остановится при следующей отправке, даже если у меня не будет ничего для передачи, поэтому мне просто нужно было бы отправить другой буфер команд только для Передача владения очередью перед отправкой моей следующей операции передачи?
ie
//begin with transfer ownership
submit(copy)
submit(ownership to graphics)
submit(draw)
submit(ownership to transfer)
submit(copy)
submit(ownership to graphics)
submit(draw)
submit(draw)
submit(draw)
submit(ownership to transfer)
submit(copy)
submit(ownership to graphics)
submit(draw)
Если это так, я не уверен в том, как обрабатывать передачу сигналов семафора между отрисовкой и передачей и копировать и рисовать. Вначале это легко, но потом становится странно из-за нескольких фреймов, так как не будет никакой зависимости между отправками при рисовании. По сути, я полагаю, что мне нужно было бы установить, какую самую последнюю команду рисования, которую я отправил, иметь семафор, чтобы сигнализировать о передаче права собственности, который будет сигнализировать о копии, которая будет сигнализировать о владении графикой, и если она будет в отдельном потоке Затем я проверил, была ли отправлена эта копия, и потребовал бы ожидания владения передачей графики и сброса проверки представленной копии. Но я не уверен, что произойдет со следующим кадром, который не имеет этой зависимости и может закончить sh до того, что будет хронологически предыдущим кадром?