Commit ed5f7e4d by Jiacheng Lu Committed by Commit Bot

Vulkan: Use a persistent CommandPool

Previously transient CommandPool is used for CommandBuffer allocation, it is created and destroyed per frame. However, profiling found that CommandPool destroy is very inefficient. So this commit removed the previous logic and use two preallocated resetable CommandPools (One for Primary and One for Secondary) Bug: angleproject:3508 Change-Id: I8b36f2738b082811c3177935c61b10e01acb6947 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1648667 Commit-Queue: Tobin Ehlis <tobine@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 44e690ca
...@@ -184,6 +184,16 @@ struct FeaturesVk : FeatureSetBase ...@@ -184,6 +184,16 @@ struct FeaturesVk : FeatureSetBase
"On platform with Intel or AMD gpu, vulkan swapchain is not returning VK_ERROR_OUT_OF_DATE" "On platform with Intel or AMD gpu, vulkan swapchain is not returning VK_ERROR_OUT_OF_DATE"
"when window resizing", "when window resizing",
&members, "http://anglebug.com/3623, http://anglebug.com/3624, http://anglebug.com/3625"}; &members, "http://anglebug.com/3623, http://anglebug.com/3624, http://anglebug.com/3625"};
// On Pixel1XL and Pixel2, reset a vkCommandBuffer seems to have side effects on binding
// descriptor sets to it afterwards, Work-around by keep using transient vkCommandBuffer on
// those devices.
// http://b/135763283
Feature transientCommandBuffer = {
"transient_command_buffer", FeatureCategory::VulkanWorkarounds,
"On Pixel2, keep using transient vkCommandBuffer to work around driver issue in reseting"
"vkCommandBuffer",
&members, "http://b/135763283"};
}; };
inline FeaturesVk::FeaturesVk() = default; inline FeaturesVk::FeaturesVk() = default;
......
...@@ -44,9 +44,10 @@ angle::Result InitAndBeginCommandBuffer(vk::Context *context, ...@@ -44,9 +44,10 @@ angle::Result InitAndBeginCommandBuffer(vk::Context *context,
const VkCommandBufferInheritanceInfo &inheritanceInfo, const VkCommandBufferInheritanceInfo &inheritanceInfo,
VkCommandBufferUsageFlags flags, VkCommandBufferUsageFlags flags,
angle::PoolAllocator *poolAllocator, angle::PoolAllocator *poolAllocator,
PrimaryCommandBuffer *commandBuffer) priv::CommandBuffer *commandBuffer)
{ {
ASSERT(!commandBuffer->valid()); ASSERT(!commandBuffer->valid());
ASSERT(commandPool.valid());
VkCommandBufferAllocateInfo createInfo = {}; VkCommandBufferAllocateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
createInfo.commandPool = commandPool.getHandle(); createInfo.commandPool = commandPool.getHandle();
...@@ -844,8 +845,7 @@ void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier) ...@@ -844,8 +845,7 @@ void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
angle::Result CommandGraph::submitCommands(ContextVk *context, angle::Result CommandGraph::submitCommands(ContextVk *context,
Serial serial, Serial serial,
RenderPassCache *renderPassCache, RenderPassCache *renderPassCache,
CommandPool *commandPool, PrimaryCommandBuffer *primaryCommandBuffer)
PrimaryCommandBuffer *primaryCommandBufferOut)
{ {
// There is no point in submitting an empty command buffer, so make sure not to call this // There is no point in submitting an empty command buffer, so make sure not to call this
// function if there's nothing to do. // function if there's nothing to do.
...@@ -862,14 +862,6 @@ angle::Result CommandGraph::submitCommands(ContextVk *context, ...@@ -862,14 +862,6 @@ angle::Result CommandGraph::submitCommands(ContextVk *context,
previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount); previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
} }
VkCommandBufferAllocateInfo primaryInfo = {};
primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
primaryInfo.commandPool = commandPool->getHandle();
primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
primaryInfo.commandBufferCount = 1;
ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
if (mEnableGraphDiagnostics) if (mEnableGraphDiagnostics)
{ {
dumpGraphDotFile(std::cout); dumpGraphDotFile(std::cout);
...@@ -882,9 +874,9 @@ angle::Result CommandGraph::submitCommands(ContextVk *context, ...@@ -882,9 +874,9 @@ angle::Result CommandGraph::submitCommands(ContextVk *context,
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr; beginInfo.pInheritanceInfo = nullptr;
ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo)); ANGLE_VK_TRY(context, primaryCommandBuffer->begin(beginInfo));
ANGLE_TRY(context->traceGpuEvent(primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, ANGLE_TRY(context->traceGpuEvent(primaryCommandBuffer, TRACE_EVENT_PHASE_BEGIN,
"Primary Command Buffer")); "Primary Command Buffer"));
for (CommandGraphNode *topLevelNode : mNodes) for (CommandGraphNode *topLevelNode : mNodes)
...@@ -907,7 +899,7 @@ angle::Result CommandGraph::submitCommands(ContextVk *context, ...@@ -907,7 +899,7 @@ angle::Result CommandGraph::submitCommands(ContextVk *context,
break; break;
case VisitedState::Ready: case VisitedState::Ready:
ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache, ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
primaryCommandBufferOut)); primaryCommandBuffer));
nodeStack.pop_back(); nodeStack.pop_back();
break; break;
case VisitedState::Visited: case VisitedState::Visited:
...@@ -920,10 +912,10 @@ angle::Result CommandGraph::submitCommands(ContextVk *context, ...@@ -920,10 +912,10 @@ angle::Result CommandGraph::submitCommands(ContextVk *context,
} }
} }
ANGLE_TRY(context->traceGpuEvent(primaryCommandBufferOut, TRACE_EVENT_PHASE_END, ANGLE_TRY(context->traceGpuEvent(primaryCommandBuffer, TRACE_EVENT_PHASE_END,
"Primary Command Buffer")); "Primary Command Buffer"));
ANGLE_VK_TRY(context, primaryCommandBufferOut->end()); ANGLE_VK_TRY(context, primaryCommandBuffer->end());
clear(); clear();
......
...@@ -482,8 +482,7 @@ class CommandGraph final : angle::NonCopyable ...@@ -482,8 +482,7 @@ class CommandGraph final : angle::NonCopyable
angle::Result submitCommands(ContextVk *context, angle::Result submitCommands(ContextVk *context,
Serial serial, Serial serial,
RenderPassCache *renderPassCache, RenderPassCache *renderPassCache,
CommandPool *commandPool, PrimaryCommandBuffer *primaryCommandBuffer);
PrimaryCommandBuffer *primaryCommandBufferOut);
bool empty() const; bool empty() const;
void clear(); void clear();
......
...@@ -205,6 +205,7 @@ ContextVk::CommandBatch::CommandBatch(CommandBatch &&other) ...@@ -205,6 +205,7 @@ ContextVk::CommandBatch::CommandBatch(CommandBatch &&other)
ContextVk::CommandBatch &ContextVk::CommandBatch::operator=(CommandBatch &&other) ContextVk::CommandBatch &ContextVk::CommandBatch::operator=(CommandBatch &&other)
{ {
std::swap(primaryCommands, other.primaryCommands);
std::swap(commandPool, other.commandPool); std::swap(commandPool, other.commandPool);
std::swap(fence, other.fence); std::swap(fence, other.fence);
std::swap(serial, other.serial); std::swap(serial, other.serial);
...@@ -213,6 +214,7 @@ ContextVk::CommandBatch &ContextVk::CommandBatch::operator=(CommandBatch &&other ...@@ -213,6 +214,7 @@ ContextVk::CommandBatch &ContextVk::CommandBatch::operator=(CommandBatch &&other
void ContextVk::CommandBatch::destroy(VkDevice device) void ContextVk::CommandBatch::destroy(VkDevice device)
{ {
primaryCommands.destroy(device);
commandPool.destroy(device); commandPool.destroy(device);
fence.reset(device); fence.reset(device);
} }
...@@ -338,6 +340,11 @@ void ContextVk::onDestroy(const gl::Context *context) ...@@ -338,6 +340,11 @@ void ContextVk::onDestroy(const gl::Context *context)
mGpuEventQueryPool.destroy(device); mGpuEventQueryPool.destroy(device);
mCommandPool.destroy(device); mCommandPool.destroy(device);
if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
{
mPrimaryCommandPool.destroy(this);
}
for (vk::CommandPool &pool : mCommandPoolFreeList) for (vk::CommandPool &pool : mCommandPoolFreeList)
{ {
pool.destroy(device); pool.destroy(device);
...@@ -394,13 +401,23 @@ angle::Result ContextVk::initialize() ...@@ -394,13 +401,23 @@ angle::Result ContextVk::initialize()
} }
// Initialize the command pool now that we know the queue family index. // Initialize the command pool now that we know the queue family index.
VkCommandPoolCreateInfo commandPoolInfo = {}; uint32_t queueFamilyIndex = getRenderer()->getQueueFamilyIndex();
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; {
commandPoolInfo.queueFamilyIndex = getRenderer()->getQueueFamilyIndex(); ANGLE_TRY(mPrimaryCommandPool.init(this, queueFamilyIndex));
}
else
{
// Once the transientCommandBuffer issue being resolved, the commandPool will only
// used for secondaryBuffer allocation, so we can guard this block of code use macro
// ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
VkCommandPoolCreateInfo commandPoolInfo = {};
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
commandPoolInfo.queueFamilyIndex = queueFamilyIndex;
VkDevice device = getDevice(); ANGLE_VK_TRY(this, mCommandPool.init(getDevice(), commandPoolInfo));
ANGLE_VK_TRY(this, mCommandPool.init(device, commandPoolInfo)); }
#if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
angle::PlatformMethods *platform = ANGLEPlatformCurrent(); angle::PlatformMethods *platform = ANGLEPlatformCurrent();
...@@ -804,6 +821,43 @@ angle::Result ContextVk::handleDirtyComputeDescriptorSets(const gl::Context *con ...@@ -804,6 +821,43 @@ angle::Result ContextVk::handleDirtyComputeDescriptorSets(const gl::Context *con
mDriverUniforms[PipelineType::Compute]); mDriverUniforms[PipelineType::Compute]);
} }
angle::Result ContextVk::releaseToCommandBatch(vk::PrimaryCommandBuffer &&commandBuffer,
CommandBatch *batch)
{
batch->primaryCommands = std::move(commandBuffer);
if (mCommandPool.valid())
{
batch->commandPool = std::move(mCommandPool);
// Recreate CommandPool
VkCommandPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
poolInfo.queueFamilyIndex = getRenderer()->getQueueFamilyIndex();
ANGLE_VK_TRY(this, mCommandPool.init(getDevice(), poolInfo));
}
return angle::Result::Continue;
}
angle::Result ContextVk::recycleCommandBatch(CommandBatch *batch)
{
batch->commandPool.destroy(getDevice());
if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
{
ASSERT(mPrimaryCommandPool.valid());
ANGLE_TRY(mPrimaryCommandPool.collect(this, std::move(batch->primaryCommands)));
}
else
{
batch->primaryCommands.destroy(getDevice());
}
return angle::Result::Continue;
}
angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo, angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
vk::PrimaryCommandBuffer &&commandBuffer) vk::PrimaryCommandBuffer &&commandBuffer)
{ {
...@@ -829,9 +883,10 @@ angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo, ...@@ -829,9 +883,10 @@ angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
onRenderPassFinished(); onRenderPassFinished();
mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits; mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
// Store this command buffer in the in-flight list. // Store the primary CommandBuffer and command pool used for secondary CommandBuffers
batch.commandPool = std::move(mCommandPool); // in the in-flight list.
batch.serial = mCurrentQueueSerial; ANGLE_TRY(releaseToCommandBatch(std::move(commandBuffer), &batch));
batch.serial = mCurrentQueueSerial;
mInFlightCommands.emplace_back(scopedBatch.release()); mInFlightCommands.emplace_back(scopedBatch.release());
...@@ -854,58 +909,9 @@ angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo, ...@@ -854,58 +909,9 @@ angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
ANGLE_TRY(checkCompletedGpuEvents()); ANGLE_TRY(checkCompletedGpuEvents());
} }
// Simply null out the command buffer here - it was allocated using the command pool.
commandBuffer.releaseHandle();
// Reallocate the command pool for next frame.
VkCommandPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
poolInfo.queueFamilyIndex = getRenderer()->getQueueFamilyIndex();
if (mCommandPoolFreeList.empty())
{
ANGLE_VK_TRY(this, mCommandPool.init(device, poolInfo));
}
else
{
mCommandPool = std::move(mCommandPoolFreeList.back());
mCommandPoolFreeList.pop_back();
}
return angle::Result::Continue; return angle::Result::Continue;
} }
void ContextVk::freeAllInFlightResources()
{
VkDevice device = getDevice();
for (CommandBatch &batch : mInFlightCommands)
{
// On device loss we need to wait for fence to be signaled before destroying it
if (getRenderer()->isDeviceLost())
{
VkResult status = batch.fence.get().wait(device, kMaxFenceWaitTimeNs);
// If wait times out, it is probably not possible to recover from lost device
ASSERT(status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST);
}
batch.commandPool.reset(device, 0);
mCommandPoolFreeList.emplace_back(std::move(batch.commandPool));
batch.fence.reset(device);
}
mInFlightCommands.clear();
for (auto &garbage : mGarbage)
{
garbage.destroy(device);
}
mGarbage.clear();
mLastCompletedQueueSerial = mLastSubmittedQueueSerial;
}
angle::Result ContextVk::flushCommandGraph(vk::PrimaryCommandBuffer *commandBatch) angle::Result ContextVk::flushCommandGraph(vk::PrimaryCommandBuffer *commandBatch)
{ {
if (mIsAnyHostVisibleBufferWritten) if (mIsAnyHostVisibleBufferWritten)
...@@ -914,8 +920,7 @@ angle::Result ContextVk::flushCommandGraph(vk::PrimaryCommandBuffer *commandBatc ...@@ -914,8 +920,7 @@ angle::Result ContextVk::flushCommandGraph(vk::PrimaryCommandBuffer *commandBatc
} }
mIsAnyHostVisibleBufferWritten = false; mIsAnyHostVisibleBufferWritten = false;
return mCommandGraph.submitCommands(this, mCurrentQueueSerial, &mRenderPassCache, &mCommandPool, return mCommandGraph.submitCommands(this, mCurrentQueueSerial, &mRenderPassCache, commandBatch);
commandBatch);
} }
angle::Result ContextVk::synchronizeCpuGpuTime() angle::Result ContextVk::synchronizeCpuGpuTime()
...@@ -1027,13 +1032,20 @@ angle::Result ContextVk::synchronizeCpuGpuTime() ...@@ -1027,13 +1032,20 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(device); vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(device);
vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get(); vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
VkCommandBufferAllocateInfo commandBufferInfo = {}; if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; {
commandBufferInfo.commandPool = mCommandPool.getHandle(); ANGLE_TRY(mPrimaryCommandPool.alloc(this, &commandBuffer));
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; }
commandBufferInfo.commandBufferCount = 1; else
{
VkCommandBufferAllocateInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferInfo.commandPool = mCommandPool.getHandle();
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferInfo.commandBufferCount = 1;
ANGLE_VK_TRY(this, commandBuffer.init(device, commandBufferInfo)); ANGLE_VK_TRY(this, commandBuffer.init(device, commandBufferInfo));
}
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
...@@ -1062,7 +1074,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime() ...@@ -1062,7 +1074,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
InitializeSubmitInfo(&submitInfo, commandBatch.get(), {}, &mWaitSemaphoreStageMasks, InitializeSubmitInfo(&submitInfo, commandBatch.get(), {}, &mWaitSemaphoreStageMasks,
nullptr); nullptr);
ANGLE_TRY(submitFrame(submitInfo, std::move(commandBuffer))); ANGLE_TRY(submitFrame(submitInfo, commandBatch.release()));
// Wait for GPU to be ready. This is a short busy wait. // Wait for GPU to be ready. This is a short busy wait.
VkResult result = VK_EVENT_RESET; VkResult result = VK_EVENT_RESET;
...@@ -1260,7 +1272,31 @@ void ContextVk::handleDeviceLost() ...@@ -1260,7 +1272,31 @@ void ContextVk::handleDeviceLost()
{ {
mCommandGraph.clear(); mCommandGraph.clear();
// TODO: generate a new serial neccessary here? // TODO: generate a new serial neccessary here?
freeAllInFlightResources(); VkDevice device = getDevice();
for (CommandBatch &batch : mInFlightCommands)
{
// On device loss we need to wait for fence to be signaled before destroying it
VkResult status = batch.fence.get().wait(device, kMaxFenceWaitTimeNs);
// If the wait times out, it is probably not possible to recover from lost device
ASSERT(status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST);
// On device lost, here simply destroy the CommandBuffer, it will fully cleared later
// by CommandPool::destroy
batch.primaryCommands.destroy(device);
batch.commandPool.destroy(device);
batch.fence.reset(device);
}
mInFlightCommands.clear();
for (vk::GarbageObject &garbage : mGarbage)
{
garbage.destroy(device);
}
mGarbage.clear();
mLastCompletedQueueSerial = mLastSubmittedQueueSerial;
mRenderer->notifyDeviceLost(); mRenderer->notifyDeviceLost();
} }
...@@ -2463,6 +2499,21 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore) ...@@ -2463,6 +2499,21 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flush"); ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flush");
vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(getDevice()); vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(getDevice());
if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
{
ANGLE_TRY(mPrimaryCommandPool.alloc(this, &commandBatch.get()));
}
else
{
VkCommandBufferAllocateInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferInfo.commandPool = mCommandPool.getHandle();
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferInfo.commandBufferCount = 1;
ANGLE_VK_TRY(this, commandBatch.get().init(getDevice(), commandBufferInfo));
}
if (!mCommandGraph.empty()) if (!mCommandGraph.empty())
{ {
ANGLE_TRY(flushCommandGraph(&commandBatch.get())); ANGLE_TRY(flushCommandGraph(&commandBatch.get()));
...@@ -2488,7 +2539,13 @@ angle::Result ContextVk::finishImpl() ...@@ -2488,7 +2539,13 @@ angle::Result ContextVk::finishImpl()
ANGLE_TRY(flushImpl(nullptr)); ANGLE_TRY(flushImpl(nullptr));
ANGLE_TRY(finishToSerial(mLastSubmittedQueueSerial)); ANGLE_TRY(finishToSerial(mLastSubmittedQueueSerial));
freeAllInFlightResources(); ASSERT(mInFlightCommands.empty());
for (vk::GarbageObject &garbage : mGarbage)
{
garbage.destroy(getDevice());
}
mGarbage.clear();
if (mGpuEventsEnabled) if (mGpuEventsEnabled)
{ {
...@@ -2543,8 +2600,8 @@ angle::Result ContextVk::checkCompletedCommands() ...@@ -2543,8 +2600,8 @@ angle::Result ContextVk::checkCompletedCommands()
mLastCompletedQueueSerial = batch.serial; mLastCompletedQueueSerial = batch.serial;
mRenderer->resetSharedFence(&batch.fence); mRenderer->resetSharedFence(&batch.fence);
ANGLE_TRACE_EVENT0("gpu.angle", "commandPool.destroy"); ANGLE_TRACE_EVENT0("gpu.angle", "command batch recycling");
batch.commandPool.destroy(device); ANGLE_TRY(recycleCommandBatch(&batch));
++finishedCount; ++finishedCount;
} }
...@@ -2693,13 +2750,20 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut) ...@@ -2693,13 +2750,20 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(device); vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(device);
vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get(); vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
VkCommandBufferAllocateInfo commandBufferInfo = {}; if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; {
commandBufferInfo.commandPool = mCommandPool.getHandle(); ANGLE_TRY(mPrimaryCommandPool.alloc(this, &commandBuffer));
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; }
commandBufferInfo.commandBufferCount = 1; else
{
VkCommandBufferAllocateInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferInfo.commandPool = mCommandPool.getHandle();
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferInfo.commandBufferCount = 1;
ANGLE_VK_TRY(this, commandBuffer.init(device, commandBufferInfo)); ANGLE_VK_TRY(this, commandBuffer.init(device, commandBufferInfo));
}
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
...@@ -2755,6 +2819,15 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut) ...@@ -2755,6 +2819,15 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
*timestampOut * *timestampOut *
static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod)); static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod));
if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
{
ANGLE_TRY(mPrimaryCommandPool.collect(this, commandBatch.release()));
}
else
{
commandBatch.get().destroy(getDevice());
}
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "common/PackedEnums.h" #include "common/PackedEnums.h"
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/vulkan/PersistentCommandPool.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
...@@ -456,7 +457,6 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -456,7 +457,6 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
angle::Result submitFrame(const VkSubmitInfo &submitInfo, angle::Result submitFrame(const VkSubmitInfo &submitInfo,
vk::PrimaryCommandBuffer &&commandBuffer); vk::PrimaryCommandBuffer &&commandBuffer);
void freeAllInFlightResources();
angle::Result flushCommandGraph(vk::PrimaryCommandBuffer *commandBatch); angle::Result flushCommandGraph(vk::PrimaryCommandBuffer *commandBatch);
angle::Result synchronizeCpuGpuTime(); angle::Result synchronizeCpuGpuTime();
...@@ -561,6 +561,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -561,6 +561,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
vk::CommandPool mCommandPool; vk::CommandPool mCommandPool;
std::vector<vk::CommandPool> mCommandPoolFreeList; std::vector<vk::CommandPool> mCommandPoolFreeList;
// We use a Persistent CommandPool with pre-allocated buffers for primary CommandBuffer
vk::PersistentCommandPool mPrimaryCommandPool;
Serial mLastCompletedQueueSerial; Serial mLastCompletedQueueSerial;
Serial mLastSubmittedQueueSerial; Serial mLastSubmittedQueueSerial;
Serial mCurrentQueueSerial; Serial mCurrentQueueSerial;
...@@ -574,11 +577,17 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -574,11 +577,17 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void destroy(VkDevice device); void destroy(VkDevice device);
vk::PrimaryCommandBuffer primaryCommands;
// commandPool is for secondary CommandBuffer allocation
vk::CommandPool commandPool; vk::CommandPool commandPool;
vk::Shared<vk::Fence> fence; vk::Shared<vk::Fence> fence;
Serial serial; Serial serial;
}; };
angle::Result releaseToCommandBatch(vk::PrimaryCommandBuffer &&commandBuffer,
CommandBatch *batch);
angle::Result recycleCommandBatch(CommandBatch *batch);
std::vector<CommandBatch> mInFlightCommands; std::vector<CommandBatch> mInFlightCommands;
std::vector<vk::GarbageObject> mGarbage; std::vector<vk::GarbageObject> mGarbage;
......
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// PersistentCommandPool.cpp:
// Implements the class methods for PersistentCommandPool
//
#include "libANGLE/renderer/vulkan/PersistentCommandPool.h"
namespace rx
{
namespace vk
{
PersistentCommandPool::PersistentCommandPool() {}
PersistentCommandPool::~PersistentCommandPool()
{
ASSERT(!mCommandPool.valid() && mFreeBuffers.empty());
}
angle::Result PersistentCommandPool::init(vk::Context *context, uint32_t queueFamilyIndex)
{
ASSERT(!mCommandPool.valid());
// Initialize the command pool now that we know the queue family index.
VkCommandPoolCreateInfo commandPoolInfo = {};
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
commandPoolInfo.queueFamilyIndex = queueFamilyIndex;
ANGLE_VK_TRY(context, mCommandPool.init(context->getDevice(), commandPoolInfo));
for (uint32_t i = 0; i < kInitBufferNum; i++)
{
ANGLE_TRY(allocateCommandBuffer(context));
}
return angle::Result::Continue;
}
void PersistentCommandPool::destroy(const vk::Context *context)
{
ASSERT(mCommandPool.valid());
VkDevice device = context->getDevice();
for (vk::PrimaryCommandBuffer &cmdBuf : mFreeBuffers)
{
cmdBuf.destroy(device, mCommandPool);
}
mFreeBuffers.clear();
mCommandPool.destroy(device);
}
angle::Result PersistentCommandPool::alloc(vk::Context *context,
vk::PrimaryCommandBuffer *bufferOutput)
{
if (mFreeBuffers.empty())
{
ANGLE_TRY(allocateCommandBuffer(context));
ASSERT(!mFreeBuffers.empty());
}
*bufferOutput = std::move(mFreeBuffers.back());
mFreeBuffers.pop_back();
return angle::Result::Continue;
}
angle::Result PersistentCommandPool::collect(vk::Context *context,
vk::PrimaryCommandBuffer &&buffer)
{
// VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT NOT set, The CommandBuffer
// can still hold the memory resource
ANGLE_VK_TRY(context, vkResetCommandBuffer(buffer.getHandle(), 0));
mFreeBuffers.emplace_back(std::move(buffer));
return angle::Result::Continue;
}
angle::Result PersistentCommandPool::allocateCommandBuffer(vk::Context *context)
{
vk::PrimaryCommandBuffer commandBuffer;
{
// Only used for primary CommandBuffer allocation
VkCommandBufferAllocateInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferInfo.commandPool = mCommandPool.getHandle();
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferInfo.commandBufferCount = 1;
ANGLE_VK_TRY(context, commandBuffer.init(context->getDevice(), commandBufferInfo));
}
mFreeBuffers.emplace_back(std::move(commandBuffer));
return angle::Result::Continue;
}
} // namespace vk
} // namespace rx
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// PersistentCommandPool.h:
// Defines the class interface for PersistentCommandBuffer
//
#ifndef LIBANGLE_RENDERER_VULKAN_PERSISTENTCOMMANDPOOL_H_
#define LIBANGLE_RENDERER_VULKAN_PERSISTENTCOMMANDPOOL_H_
#include <vector>
#include "libANGLE/renderer/vulkan/vk_utils.h"
#include "libANGLE/renderer/vulkan/vk_wrapper.h"
namespace rx
{
namespace vk
{
class PersistentCommandPool final
{
public:
PersistentCommandPool();
~PersistentCommandPool();
void destroy(const vk::Context *context);
angle::Result init(vk::Context *context, uint32_t queueFamilyIndex);
angle::Result alloc(vk::Context *context, vk::PrimaryCommandBuffer *bufferOutput);
angle::Result collect(vk::Context *context, vk::PrimaryCommandBuffer &&buffer);
bool valid() const { return mCommandPool.valid(); }
private:
angle::Result allocateCommandBuffer(vk::Context *context);
std::vector<vk::PrimaryCommandBuffer> mFreeBuffers;
vk::CommandPool mCommandPool;
static const int kInitBufferNum = 2;
};
} // namespace vk
} // namespace rx
#endif
...@@ -1273,6 +1273,12 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames) ...@@ -1273,6 +1273,12 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
{ {
mFeatures.disableFlippingBlitWithCommand.enabled = true; mFeatures.disableFlippingBlitWithCommand.enabled = true;
} }
if (IsPixel2(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID) ||
IsPixel1XL(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID))
{
mFeatures.transientCommandBuffer.enabled = true;
}
} }
void RendererVk::initPipelineCacheVkKey() void RendererVk::initPipelineCacheVkKey()
......
...@@ -862,6 +862,8 @@ libangle_vulkan_sources = [ ...@@ -862,6 +862,8 @@ libangle_vulkan_sources = [
"src/libANGLE/renderer/vulkan/ImageVk.h", "src/libANGLE/renderer/vulkan/ImageVk.h",
"src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp", "src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp",
"src/libANGLE/renderer/vulkan/MemoryObjectVk.h", "src/libANGLE/renderer/vulkan/MemoryObjectVk.h",
"src/libANGLE/renderer/vulkan/PersistentCommandPool.cpp",
"src/libANGLE/renderer/vulkan/PersistentCommandPool.h",
"src/libANGLE/renderer/vulkan/ProgramVk.cpp", "src/libANGLE/renderer/vulkan/ProgramVk.cpp",
"src/libANGLE/renderer/vulkan/ProgramVk.h", "src/libANGLE/renderer/vulkan/ProgramVk.h",
"src/libANGLE/renderer/vulkan/ProgramPipelineVk.cpp", "src/libANGLE/renderer/vulkan/ProgramPipelineVk.cpp",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment