From 160abad59278003378530eea7d43e3b50c103f0c Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 4 Dec 2017 18:06:02 -0500 Subject: [PATCH] Vulkan: Implement buffer transitions --- src/backend/Buffer.cpp | 2 +- src/backend/Buffer.h | 2 +- src/backend/vulkan/BufferVk.cpp | 79 +++++++++++++++++++++++++- src/backend/vulkan/BufferVk.h | 4 ++ src/backend/vulkan/CommandBufferVk.cpp | 7 ++- 5 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/backend/Buffer.cpp b/src/backend/Buffer.cpp index a16cad4dca..d3401dec03 100644 --- a/src/backend/Buffer.cpp +++ b/src/backend/Buffer.cpp @@ -41,7 +41,7 @@ namespace backend { return new BufferViewBuilder(mDevice, this); } - DeviceBase* BufferBase::GetDevice() { + DeviceBase* BufferBase::GetDevice() const { return mDevice; } diff --git a/src/backend/Buffer.h b/src/backend/Buffer.h index ea9f2a60d3..43e6db6221 100644 --- a/src/backend/Buffer.h +++ b/src/backend/Buffer.h @@ -37,7 +37,7 @@ namespace backend { bool HasFrozenUsage(nxt::BufferUsageBit usage) const; void UpdateUsageInternal(nxt::BufferUsageBit usage); - DeviceBase* GetDevice(); + DeviceBase* GetDevice() const; // NXT API BufferViewBuilder* CreateBufferViewBuilder(); diff --git a/src/backend/vulkan/BufferVk.cpp b/src/backend/vulkan/BufferVk.cpp index 8eae6b3e27..01ec76bea7 100644 --- a/src/backend/vulkan/BufferVk.cpp +++ b/src/backend/vulkan/BufferVk.cpp @@ -49,6 +49,58 @@ namespace backend { namespace vulkan { return flags; } + VkPipelineStageFlags VulkanPipelineStage(nxt::BufferUsageBit usage) { + VkPipelineStageFlags flags = 0; + + if (usage & (nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapWrite)) { + flags |= VK_PIPELINE_STAGE_HOST_BIT; + } + if (usage & (nxt::BufferUsageBit::TransferSrc | nxt::BufferUsageBit::TransferDst)) { + flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; + } + if (usage & (nxt::BufferUsageBit::Index | nxt::BufferUsageBit::Vertex)) { + flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + } + if (usage & (nxt::BufferUsageBit::Uniform | nxt::BufferUsageBit::Storage)) { + flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + } + + return flags; + } + + VkAccessFlags VulkanAccessFlags(nxt::BufferUsageBit usage) { + VkAccessFlags flags = 0; + + if (usage & nxt::BufferUsageBit::MapRead) { + flags |= VK_ACCESS_HOST_READ_BIT; + } + if (usage & nxt::BufferUsageBit::MapWrite) { + flags |= VK_ACCESS_HOST_WRITE_BIT; + } + if (usage & nxt::BufferUsageBit::TransferSrc) { + flags |= VK_ACCESS_TRANSFER_READ_BIT; + } + if (usage & nxt::BufferUsageBit::TransferDst) { + flags |= VK_ACCESS_TRANSFER_WRITE_BIT; + } + if (usage & nxt::BufferUsageBit::Index) { + flags |= VK_ACCESS_INDEX_READ_BIT; + } + if (usage & nxt::BufferUsageBit::Vertex) { + flags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + } + if (usage & nxt::BufferUsageBit::Uniform) { + flags |= VK_ACCESS_UNIFORM_READ_BIT; + } + if (usage & nxt::BufferUsageBit::Storage) { + flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + } + + return flags; + } + } // namespace Buffer::Buffer(BufferBuilder* builder) : BufferBase(builder) { @@ -106,6 +158,28 @@ namespace backend { namespace vulkan { return mHandle; } + void Buffer::RecordBarrier(VkCommandBuffer commands, + nxt::BufferUsageBit currentUsage, + nxt::BufferUsageBit targetUsage) const { + VkPipelineStageFlags srcStages = VulkanPipelineStage(currentUsage); + VkPipelineStageFlags dstStages = VulkanPipelineStage(targetUsage); + + VkBufferMemoryBarrier barrier; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrier.pNext = nullptr; + barrier.srcAccessMask = VulkanAccessFlags(currentUsage); + barrier.dstAccessMask = VulkanAccessFlags(targetUsage); + barrier.srcQueueFamilyIndex = 0; + barrier.dstQueueFamilyIndex = 0; + barrier.buffer = mHandle; + barrier.offset = 0; + barrier.size = GetSize(); + + ToBackend(GetDevice()) + ->fn.CmdPipelineBarrier(commands, srcStages, dstStages, 0, 0, nullptr, 1, &barrier, 0, + nullptr); + } + void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) { BufferUploader* uploader = ToBackend(GetDevice())->GetBufferUploader(); uploader->BufferSubData(mHandle, start * sizeof(uint32_t), count * sizeof(uint32_t), data); @@ -123,7 +197,10 @@ namespace backend { namespace vulkan { // No need to do anything, we keep CPU-visible memory mapped at all time. } - void Buffer::TransitionUsageImpl(nxt::BufferUsageBit, nxt::BufferUsageBit) { + void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, + nxt::BufferUsageBit targetUsage) { + VkCommandBuffer commands = ToBackend(GetDevice())->GetPendingCommandBuffer(); + RecordBarrier(commands, currentUsage, targetUsage); } MapReadRequestTracker::MapReadRequestTracker(Device* device) : mDevice(device) { diff --git a/src/backend/vulkan/BufferVk.h b/src/backend/vulkan/BufferVk.h index a7a31cf86d..dce8758ef3 100644 --- a/src/backend/vulkan/BufferVk.h +++ b/src/backend/vulkan/BufferVk.h @@ -34,6 +34,10 @@ namespace backend { namespace vulkan { VkBuffer GetHandle() const; + void RecordBarrier(VkCommandBuffer commands, + nxt::BufferUsageBit currentUsage, + nxt::BufferUsageBit targetUsage) const; + private: void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override; void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override; diff --git a/src/backend/vulkan/CommandBufferVk.cpp b/src/backend/vulkan/CommandBufferVk.cpp index 75e6f824ac..dd0bb6a993 100644 --- a/src/backend/vulkan/CommandBufferVk.cpp +++ b/src/backend/vulkan/CommandBufferVk.cpp @@ -52,7 +52,12 @@ namespace backend { namespace vulkan { } break; case Command::TransitionBufferUsage: { - SkipCommand(&mCommands, type); + TransitionBufferUsageCmd* cmd = + mCommands.NextCommand(); + + Buffer* buffer = ToBackend(cmd->buffer.Get()); + buffer->RecordBarrier(commands, buffer->GetUsage(), cmd->usage); + buffer->UpdateUsageInternal(cmd->usage); } break; default: { UNREACHABLE(); } break;