Hash :
e339f91c
Author :
Date :
2025-03-21T10:22:59
Vulkan: Split asyncCommandBufferResetAndGarbageCleanup into two Right now this one feature flag controls garbage clean up and command buffer reset. If this is enabled, we are seeing command buffer reset some times runs on small core and some times gets blocked by mutex lock inside vulkan driver. This could take quite long while main rendering thread is blocked by ANGLE's CommandPoolAccess lock. This CL splits this feature flag into two separate feature flag: asyncGarbageCleanup controls garbage clean up in the async thread or not. asyncCommandBufferReset controls commandBuffer.reset in the async thread or not. This CL also disables commandBuffer.reset in async thread only on ARM given there is no data shows other GPUs suffer form the same problem. Bug: angleproject:378718508 Change-Id: Ice87b5b91568a0a95e0064da2b70243516ff6753 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6381893 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: Roman Lavrov <romanl@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
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 127 128 129 130 131 132 133 134 135 136 137 138 139
//
// 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() && mFreeBuffersNeedReset.empty());
}
angle::Result PersistentCommandPool::init(ErrorContext *context,
ProtectionType protectionType,
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;
// TODO (https://issuetracker.google.com/issues/166793850) We currently reset individual
// command buffers from this pool. Alternatively we could reset the entire command pool.
commandPoolInfo.flags =
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
ASSERT(protectionType == ProtectionType::Unprotected ||
protectionType == ProtectionType::Protected);
if (protectionType == ProtectionType::Protected)
{
commandPoolInfo.flags |= VK_COMMAND_POOL_CREATE_PROTECTED_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(VkDevice device)
{
if (!valid())
return;
ASSERT(mCommandPool.valid());
while (!mFreeBuffers.empty())
{
mFreeBuffers.back().destroy(device, mCommandPool);
mFreeBuffers.pop_back();
}
while (!mFreeBuffersNeedReset.empty())
{
mFreeBuffersNeedReset.back().destroy(device, mCommandPool);
mFreeBuffersNeedReset.pop_back();
}
mCommandPool.destroy(device);
}
angle::Result PersistentCommandPool::allocate(ErrorContext *context,
PrimaryCommandBuffer *commandBufferOut)
{
while (!mFreeBuffersNeedReset.empty())
{
mFreeBuffersNeedReset.front().reset();
mFreeBuffers.emplace_back(std::move(mFreeBuffersNeedReset.front()));
mFreeBuffersNeedReset.pop_front();
}
if (mFreeBuffers.empty())
{
ANGLE_TRY(allocateCommandBuffer(context));
ASSERT(!mFreeBuffers.empty());
}
*commandBufferOut = std::move(mFreeBuffers.back());
mFreeBuffers.pop_back();
return angle::Result::Continue;
}
angle::Result PersistentCommandPool::collect(ErrorContext *context,
PrimaryCommandBuffer &&buffer,
WhenToResetCommandBuffer whenToReset)
{
if (whenToReset == WhenToResetCommandBuffer::Now)
{
// VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT NOT set, The CommandBuffer
// can still hold the memory resource
ANGLE_VK_TRY(context, buffer.reset());
mFreeBuffers.emplace_back(std::move(buffer));
}
else
{
mFreeBuffersNeedReset.emplace_back(std::move(buffer));
}
return angle::Result::Continue;
}
angle::Result PersistentCommandPool::allocateCommandBuffer(ErrorContext *context)
{
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