Hash :
6f794eab
Author :
Date :
2023-10-05T11:23:30
Change angle::FixedQueue's storage from std::array to std::vector Right now angle::FixedQueue uses std::array as the storage. In the case when queue is full, the only choice is to wait for dequeue thread to run until there is more room to enqueue. This CL try to add extra flexibility. In this CL< it switches storage to std::vector so that we could reallocate to double the storage when it is full. The trick is that before doing that, you must ensure no one is accessing the queue other than check the size. In a lot of usage cases that is easy to do by just grabbing the necessary locks. Bug: b/302739073 Change-Id: Ibefe0fd0e3e89c17dd6ee2cac6adc3368122adb9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4915811 Reviewed-by: Hailin Zhang <hailinzhang@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Charlie Lao <cclao@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
//
// Copyright 2023 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.
//
// SecondaryCommandPool:
// A class for allocating Command Buffers for VulkanSecondaryCommandBuffer.
//
#include "libANGLE/renderer/vulkan/SecondaryCommandPool.h"
#include "common/debug.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
namespace vk
{
SecondaryCommandPool::SecondaryCommandPool() : mCollectedBuffers(kFixedQueueLimit) {}
SecondaryCommandPool::~SecondaryCommandPool()
{
ASSERT(mCollectedBuffers.empty());
ASSERT(mCollectedBuffersOverflow.empty());
}
angle::Result SecondaryCommandPool::init(Context *context,
uint32_t queueFamilyIndex,
ProtectionType protectionType)
{
VkCommandPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
poolInfo.queueFamilyIndex = queueFamilyIndex;
if (context->getRenderer()->getFeatures().useResetCommandBufferBitForSecondaryPools.enabled)
{
poolInfo.flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
}
ASSERT(protectionType == ProtectionType::Unprotected ||
protectionType == ProtectionType::Protected);
if (protectionType == ProtectionType::Protected)
{
poolInfo.flags |= VK_COMMAND_POOL_CREATE_PROTECTED_BIT;
}
ANGLE_VK_TRY(context, mCommandPool.init(context->getDevice(), poolInfo));
return angle::Result::Continue;
}
void SecondaryCommandPool::destroy(VkDevice device)
{
// Command buffers will be destroyed with the Pool. Avoid possible slowdown during cleanup.
mCollectedBuffers.clear();
mCollectedBuffersOverflow.clear();
mCommandPool.destroy(device);
}
angle::Result SecondaryCommandPool::allocate(Context *context, VulkanSecondaryCommandBuffer *buffer)
{
ASSERT(valid());
ASSERT(!buffer->valid());
VkDevice device = context->getDevice();
freeCollectedBuffers(device);
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
allocInfo.commandBufferCount = 1;
allocInfo.commandPool = mCommandPool.getHandle();
ANGLE_VK_TRY(context, buffer->init(device, allocInfo));
return angle::Result::Continue;
}
void SecondaryCommandPool::collect(VulkanSecondaryCommandBuffer *buffer)
{
ASSERT(valid());
ASSERT(buffer->valid());
VkCommandBuffer bufferHandle = buffer->releaseHandle();
if (!mCollectedBuffers.full())
{
mCollectedBuffers.push(bufferHandle);
}
else
{
std::lock_guard<std::mutex> lock(mOverflowMutex);
mCollectedBuffersOverflow.emplace_back(bufferHandle);
mHasOverflow.store(true, std::memory_order_relaxed);
}
}
void SecondaryCommandPool::freeCollectedBuffers(VkDevice device)
{
// Free Command Buffer for now. May later add recycling or reset/free pool at once.
ANGLE_TRACE_EVENT0("gpu.angle", "SecondaryCommandPool::freeCollectedBuffers");
while (!mCollectedBuffers.empty())
{
VkCommandBuffer bufferHandle = mCollectedBuffers.front();
mCommandPool.freeCommandBuffers(device, 1, &bufferHandle);
mCollectedBuffers.pop();
}
if (ANGLE_UNLIKELY(mHasOverflow.load(std::memory_order_relaxed)))
{
std::vector<VkCommandBuffer> buffers;
{
std::lock_guard<std::mutex> lock(mOverflowMutex);
buffers = std::move(mCollectedBuffersOverflow);
mHasOverflow.store(false, std::memory_order_relaxed);
}
for (VkCommandBuffer bufferHandle : buffers)
{
mCommandPool.freeCommandBuffers(device, 1, &bufferHandle);
}
}
}
} // namespace vk
} // namespace rx