|
@@ -4,12 +4,13 @@
|
|
|
#include "BsVulkanCommandBufferManager.h"
|
|
#include "BsVulkanCommandBufferManager.h"
|
|
|
#include "BsVulkanUtility.h"
|
|
#include "BsVulkanUtility.h"
|
|
|
#include "BsVulkanDevice.h"
|
|
#include "BsVulkanDevice.h"
|
|
|
|
|
+#include "BsVulkanGpuParams.h"
|
|
|
#include "BsVulkanQueue.h"
|
|
#include "BsVulkanQueue.h"
|
|
|
|
|
|
|
|
namespace BansheeEngine
|
|
namespace BansheeEngine
|
|
|
{
|
|
{
|
|
|
VulkanCmdBufferPool::VulkanCmdBufferPool(VulkanDevice& device)
|
|
VulkanCmdBufferPool::VulkanCmdBufferPool(VulkanDevice& device)
|
|
|
- :mDevice(device), mPools{}, mBuffers{}, mNextId(1)
|
|
|
|
|
|
|
+ :mDevice(device), mNextId(1)
|
|
|
{
|
|
{
|
|
|
for (UINT32 i = 0; i < GQT_COUNT; i++)
|
|
for (UINT32 i = 0; i < GQT_COUNT; i++)
|
|
|
{
|
|
{
|
|
@@ -18,51 +19,48 @@ namespace BansheeEngine
|
|
|
if (familyIdx == (UINT32)-1)
|
|
if (familyIdx == (UINT32)-1)
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
- VkCommandPoolCreateInfo poolInfo;
|
|
|
|
|
- poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
|
|
|
- poolInfo.pNext = nullptr;
|
|
|
|
|
- poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
|
|
|
- poolInfo.queueFamilyIndex = familyIdx;
|
|
|
|
|
|
|
+ VkCommandPoolCreateInfo poolCI;
|
|
|
|
|
+ poolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
|
|
|
+ poolCI.pNext = nullptr;
|
|
|
|
|
+ poolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
|
|
|
+ poolCI.queueFamilyIndex = familyIdx;
|
|
|
|
|
|
|
|
- mPools[i].queueFamily = familyIdx;
|
|
|
|
|
- vkCreateCommandPool(device.getLogical(), &poolInfo, gVulkanAllocator, &mPools[i].pool);
|
|
|
|
|
|
|
+ PoolInfo& poolInfo = mPools[familyIdx];
|
|
|
|
|
+ poolInfo.queueFamily = familyIdx;
|
|
|
|
|
+ memset(poolInfo.buffers, 0, sizeof(poolInfo.buffers));
|
|
|
|
|
+
|
|
|
|
|
+ vkCreateCommandPool(device.getLogical(), &poolCI, gVulkanAllocator, &poolInfo.pool);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VulkanCmdBufferPool::~VulkanCmdBufferPool()
|
|
VulkanCmdBufferPool::~VulkanCmdBufferPool()
|
|
|
{
|
|
{
|
|
|
- for (UINT32 i = 0; i < GQT_COUNT; i++)
|
|
|
|
|
|
|
+ for(auto& entry : mPools)
|
|
|
{
|
|
{
|
|
|
- for(UINT32 j = 0; j < BS_MAX_QUEUES_PER_TYPE; j++)
|
|
|
|
|
|
|
+ PoolInfo& poolInfo = entry.second;
|
|
|
|
|
+ for (UINT32 i = 0; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
|
|
|
{
|
|
{
|
|
|
- VulkanCmdBuffer** buffers = mBuffers[i][j];
|
|
|
|
|
- for(UINT32 k = 0; k < BS_MAX_VULKAN_COMMAND_BUFFERS_PER_QUEUE; k++)
|
|
|
|
|
- {
|
|
|
|
|
- if (buffers[k] == nullptr)
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- bs_delete(buffers[k]);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ VulkanCmdBuffer* buffer = poolInfo.buffers[i];
|
|
|
|
|
+ if (buffer == nullptr)
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- for (UINT32 i = 0; i < GQT_COUNT; i++)
|
|
|
|
|
- {
|
|
|
|
|
- if (mPools[i].pool == VK_NULL_HANDLE)
|
|
|
|
|
- continue;
|
|
|
|
|
|
|
+ bs_delete(buffer);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- vkDestroyCommandPool(mDevice.getLogical(), mPools[i].pool, gVulkanAllocator);
|
|
|
|
|
|
|
+ vkDestroyCommandPool(mDevice.getLogical(), poolInfo.pool, gVulkanAllocator);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- VulkanCmdBuffer* VulkanCmdBufferPool::getBuffer(GpuQueueType type, UINT32 queueIdx, bool secondary)
|
|
|
|
|
|
|
+ VulkanCmdBuffer* VulkanCmdBufferPool::getBuffer(UINT32 queueFamily, bool secondary)
|
|
|
{
|
|
{
|
|
|
- assert(queueIdx < BS_MAX_QUEUES_PER_TYPE);
|
|
|
|
|
|
|
+ auto iterFind = mPools.find(queueFamily);
|
|
|
|
|
+ if (iterFind != mPools.end())
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
|
|
|
- VulkanCmdBuffer** buffers = mBuffers[type][queueIdx];
|
|
|
|
|
|
|
+ VulkanCmdBuffer** buffers = iterFind->second.buffers;
|
|
|
|
|
|
|
|
UINT32 i = 0;
|
|
UINT32 i = 0;
|
|
|
- for(; i < BS_MAX_VULKAN_COMMAND_BUFFERS_PER_QUEUE; i++)
|
|
|
|
|
|
|
+ for(; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
|
|
|
{
|
|
{
|
|
|
if (buffers[i] == nullptr)
|
|
if (buffers[i] == nullptr)
|
|
|
break;
|
|
break;
|
|
@@ -74,33 +72,28 @@ namespace BansheeEngine
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- assert(i < BS_MAX_VULKAN_COMMAND_BUFFERS_PER_QUEUE &&
|
|
|
|
|
- "Too many command buffers allocated. Increment BS_MAX_VULKAN_COMMAND_BUFFERS_PER_QUEUE to a higher value. ");
|
|
|
|
|
|
|
+ assert(i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY &&
|
|
|
|
|
+ "Too many command buffers allocated. Increment BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY to a higher value. ");
|
|
|
|
|
|
|
|
- buffers[i] = createBuffer(type, secondary);
|
|
|
|
|
|
|
+ buffers[i] = createBuffer(queueFamily, secondary);
|
|
|
buffers[i]->begin();
|
|
buffers[i]->begin();
|
|
|
|
|
|
|
|
return buffers[i];
|
|
return buffers[i];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- VulkanCmdBuffer* VulkanCmdBufferPool::createBuffer(GpuQueueType type, bool secondary)
|
|
|
|
|
|
|
+ VulkanCmdBuffer* VulkanCmdBufferPool::createBuffer(UINT32 queueFamily, bool secondary)
|
|
|
{
|
|
{
|
|
|
- const PoolInfo& poolInfo = getPool(type);
|
|
|
|
|
|
|
+ auto iterFind = mPools.find(queueFamily);
|
|
|
|
|
+ if (iterFind != mPools.end())
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
|
|
|
- return bs_new<VulkanCmdBuffer>(mDevice, mNextId++, poolInfo.pool, poolInfo.queueFamily, secondary);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const PoolInfo& poolInfo = iterFind->second;
|
|
|
|
|
|
|
|
- const VulkanCmdBufferPool::PoolInfo& VulkanCmdBufferPool::getPool(GpuQueueType type)
|
|
|
|
|
- {
|
|
|
|
|
- const PoolInfo* poolInfo = &mPools[type];
|
|
|
|
|
- if (poolInfo->pool == VK_NULL_HANDLE)
|
|
|
|
|
- poolInfo = &mPools[GQT_GRAPHICS]; // Graphics queue is guaranteed to exist
|
|
|
|
|
-
|
|
|
|
|
- return *poolInfo;
|
|
|
|
|
|
|
+ return bs_new<VulkanCmdBuffer>(mDevice, mNextId++, poolInfo.pool, poolInfo.queueFamily, secondary);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
|
|
VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
|
|
|
- :mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool), mFenceCounter(0)
|
|
|
|
|
|
|
+ : mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool), mFenceCounter(0)
|
|
|
{
|
|
{
|
|
|
VkCommandBufferAllocateInfo cmdBufferAllocInfo;
|
|
VkCommandBufferAllocateInfo cmdBufferAllocInfo;
|
|
|
cmdBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
cmdBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
@@ -149,6 +142,11 @@ namespace BansheeEngine
|
|
|
vkFreeCommandBuffers(device, mPool, 1, &mCmdBuffer);
|
|
vkFreeCommandBuffers(device, mPool, 1, &mCmdBuffer);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ UINT32 VulkanCmdBuffer::getDeviceIdx() const
|
|
|
|
|
+ {
|
|
|
|
|
+ return mDevice.getIndex();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
void VulkanCmdBuffer::begin()
|
|
void VulkanCmdBuffer::begin()
|
|
|
{
|
|
{
|
|
|
assert(mState == State::Ready);
|
|
assert(mState == State::Ready);
|
|
@@ -217,6 +215,7 @@ namespace BansheeEngine
|
|
|
entry.first->notifyDone(this);
|
|
entry.first->notifyDone(this);
|
|
|
|
|
|
|
|
mResources.clear();
|
|
mResources.clear();
|
|
|
|
|
+ mBoundParams.clear();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -228,10 +227,19 @@ namespace BansheeEngine
|
|
|
mResources[res].flags |= flags;
|
|
mResources[res].flags |= flags;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void VulkanCmdBuffer::notifySubmit()
|
|
|
|
|
|
|
+ void VulkanCmdBuffer::registerGpuParams(const SPtr<VulkanGpuParams>& params)
|
|
|
{
|
|
{
|
|
|
- // TODO - Issue pipeline barrier for resources transitioning to a new queue family
|
|
|
|
|
|
|
+ mBoundParams.insert(params);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void VulkanCmdBuffer::prepareForSubmit(UnorderedMap<UINT32, TransitionInfo>& transitionInfo)
|
|
|
|
|
+ {
|
|
|
|
|
+ for (auto& entry : mBoundParams)
|
|
|
|
|
+ entry->prepareForSubmit(this, transitionInfo);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ void VulkanCmdBuffer::notifySubmit()
|
|
|
|
|
+ {
|
|
|
for (auto& entry : mResources)
|
|
for (auto& entry : mResources)
|
|
|
entry.first->notifyUsed(this, entry.second.flags);
|
|
entry.first->notifyUsed(this, entry.second.flags);
|
|
|
}
|
|
}
|
|
@@ -241,22 +249,20 @@ namespace BansheeEngine
|
|
|
: CommandBuffer(id, type, deviceIdx, queueIdx, secondary), mBuffer(nullptr), mSubmittedBuffer(nullptr)
|
|
: CommandBuffer(id, type, deviceIdx, queueIdx, secondary), mBuffer(nullptr), mSubmittedBuffer(nullptr)
|
|
|
, mDevice(device), mQueue(nullptr), mIdMask(0)
|
|
, mDevice(device), mQueue(nullptr), mIdMask(0)
|
|
|
{
|
|
{
|
|
|
- GpuQueueType queueType = mType;
|
|
|
|
|
-
|
|
|
|
|
- UINT32 numQueues = device.getNumQueues(queueType);
|
|
|
|
|
- if (numQueues == 0) // Fallback to graphics queue
|
|
|
|
|
|
|
+ UINT32 numQueues = device.getNumQueues(mType);
|
|
|
|
|
+ if (numQueues == 0) // Fall back to graphics queue
|
|
|
{
|
|
{
|
|
|
- queueType = GQT_GRAPHICS;
|
|
|
|
|
|
|
+ mType = GQT_GRAPHICS;
|
|
|
numQueues = device.getNumQueues(GQT_GRAPHICS);
|
|
numQueues = device.getNumQueues(GQT_GRAPHICS);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- mQueue = device.getQueue(queueType, mQueueIdx % numQueues);
|
|
|
|
|
|
|
+ mQueue = device.getQueue(mType, mQueueIdx % numQueues);
|
|
|
|
|
|
|
|
// If multiple command buffer IDs map to the same queue, mark them in the mask
|
|
// If multiple command buffer IDs map to the same queue, mark them in the mask
|
|
|
UINT32 curIdx = mQueueIdx;
|
|
UINT32 curIdx = mQueueIdx;
|
|
|
while (curIdx < BS_MAX_QUEUES_PER_TYPE)
|
|
while (curIdx < BS_MAX_QUEUES_PER_TYPE)
|
|
|
{
|
|
{
|
|
|
- mIdMask |= CommandSyncMask::getGlobalQueueIdx(queueType, curIdx);
|
|
|
|
|
|
|
+ mIdMask |= CommandSyncMask::getGlobalQueueIdx(mType, curIdx);
|
|
|
curIdx += numQueues;
|
|
curIdx += numQueues;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -281,7 +287,8 @@ namespace BansheeEngine
|
|
|
assert(mBuffer->isSubmitted());
|
|
assert(mBuffer->isSubmitted());
|
|
|
|
|
|
|
|
mSubmittedBuffer = mBuffer;
|
|
mSubmittedBuffer = mBuffer;
|
|
|
- mBuffer = pool.getBuffer(mType, mQueueIdx, mIsSecondary);
|
|
|
|
|
|
|
+ UINT32 queueFamily = mDevice.getQueueFamily(mType);
|
|
|
|
|
+ mBuffer = pool.getBuffer(queueFamily, mIsSecondary);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void VulkanCommandBuffer::submit(UINT32 syncMask)
|
|
void VulkanCommandBuffer::submit(UINT32 syncMask)
|
|
@@ -303,6 +310,57 @@ namespace BansheeEngine
|
|
|
// Ignore myself
|
|
// Ignore myself
|
|
|
syncMask &= ~mIdMask;
|
|
syncMask &= ~mIdMask;
|
|
|
|
|
|
|
|
|
|
+ // Issue pipeline barriers for queue transitions (need to happen on original queue first, then on new queue)
|
|
|
|
|
+ mBuffer->prepareForSubmit(mTransitionInfoTemp);
|
|
|
|
|
+
|
|
|
|
|
+ UINT32 queueFamily = mDevice.getQueueFamily(mType);
|
|
|
|
|
+ for(auto& entry : mTransitionInfoTemp)
|
|
|
|
|
+ {
|
|
|
|
|
+ UINT32 entryQueueFamily = entry.first;
|
|
|
|
|
+
|
|
|
|
|
+ // No queue transition needed for entries on this queue (this entry is most likely an in image layout transition)
|
|
|
|
|
+ if (entryQueueFamily == queueFamily)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ VkCommandBuffer cmdBuffer; // TODO - Get the command buffer on entryQueueFamily
|
|
|
|
|
+
|
|
|
|
|
+ TransitionInfo& barriers = entry.second;
|
|
|
|
|
+ UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
|
|
|
|
|
+ UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
|
|
|
|
|
+
|
|
|
|
|
+ vkCmdPipelineBarrier(cmdBuffer,
|
|
|
|
|
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
|
|
|
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
|
|
|
+ 0, 0, nullptr,
|
|
|
|
|
+ numBufferBarriers, barriers.bufferBarriers.data(),
|
|
|
|
|
+ numImgBarriers, barriers.imageBarriers.data());
|
|
|
|
|
+
|
|
|
|
|
+ // TODO - Submit the command buffer
|
|
|
|
|
+ // TODO - Register the command buffer in the sync mask so we wait on it
|
|
|
|
|
+
|
|
|
|
|
+ // If there are any layout transitions, reset them as we don't need them for the second pipeline barrier
|
|
|
|
|
+ for (auto& barrierEntry : barriers.imageBarriers)
|
|
|
|
|
+ barrierEntry.oldLayout = barrierEntry.newLayout;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Issue second part of transition pipeline barriers (on this queue)
|
|
|
|
|
+ for (auto& entry : mTransitionInfoTemp)
|
|
|
|
|
+ {
|
|
|
|
|
+ VkCommandBuffer cmdBuffer; // TODO - Get the command buffer on queueFamily AND this exact queue
|
|
|
|
|
+ // - Probably best to just append it to current submitInfo as it is executed in order
|
|
|
|
|
+
|
|
|
|
|
+ TransitionInfo& barriers = entry.second;
|
|
|
|
|
+ UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
|
|
|
|
|
+ UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
|
|
|
|
|
+
|
|
|
|
|
+ vkCmdPipelineBarrier(cmdBuffer,
|
|
|
|
|
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
|
|
|
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
|
|
|
+ 0, 0, nullptr,
|
|
|
|
|
+ numBufferBarriers, barriers.bufferBarriers.data(),
|
|
|
|
|
+ numImgBarriers, barriers.imageBarriers.data());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
VulkanCommandBufferManager& cmdBufManager = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
|
|
VulkanCommandBufferManager& cmdBufManager = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
|
|
|
cmdBufManager.getSyncSemaphores(mDeviceIdx, syncMask, mSemaphoresTemp, submitInfo.waitSemaphoreCount);
|
|
cmdBufManager.getSyncSemaphores(mDeviceIdx, syncMask, mSemaphoresTemp, submitInfo.waitSemaphoreCount);
|
|
|
|
|
|
|
@@ -325,5 +383,13 @@ namespace BansheeEngine
|
|
|
|
|
|
|
|
mBuffer->mState = VulkanCmdBuffer::State::Submitted;
|
|
mBuffer->mState = VulkanCmdBuffer::State::Submitted;
|
|
|
acquireNewBuffer();
|
|
acquireNewBuffer();
|
|
|
|
|
+
|
|
|
|
|
+ // Clear vectors but don't clear the actual map, as we want to re-use the memory since we expect queue family
|
|
|
|
|
+ // indices to be the same
|
|
|
|
|
+ for(auto& entry : mTransitionInfoTemp)
|
|
|
|
|
+ {
|
|
|
|
|
+ entry.second.imageBarriers.clear();
|
|
|
|
|
+ entry.second.bufferBarriers.clear();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|