xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/SecondaryCommandPool.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SecondaryCommandPool:
7 //    A class for allocating Command Buffers for VulkanSecondaryCommandBuffer.
8 //
9 
10 #include "libANGLE/renderer/vulkan/SecondaryCommandPool.h"
11 
12 #include "common/debug.h"
13 #include "libANGLE/renderer/vulkan/vk_renderer.h"
14 #include "libANGLE/renderer/vulkan/vk_utils.h"
15 
16 namespace rx
17 {
18 namespace vk
19 {
20 
SecondaryCommandPool()21 SecondaryCommandPool::SecondaryCommandPool() : mCollectedBuffers(kFixedQueueLimit) {}
22 
~SecondaryCommandPool()23 SecondaryCommandPool::~SecondaryCommandPool()
24 {
25     ASSERT(mCollectedBuffers.empty());
26     ASSERT(mCollectedBuffersOverflow.empty());
27 }
28 
init(Context * context,uint32_t queueFamilyIndex,ProtectionType protectionType)29 angle::Result SecondaryCommandPool::init(Context *context,
30                                          uint32_t queueFamilyIndex,
31                                          ProtectionType protectionType)
32 {
33     VkCommandPoolCreateInfo poolInfo = {};
34     poolInfo.sType                   = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
35     poolInfo.flags                   = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
36     poolInfo.queueFamilyIndex        = queueFamilyIndex;
37     if (context->getFeatures().useResetCommandBufferBitForSecondaryPools.enabled)
38     {
39         poolInfo.flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
40     }
41     ASSERT(protectionType == ProtectionType::Unprotected ||
42            protectionType == ProtectionType::Protected);
43     if (protectionType == ProtectionType::Protected)
44     {
45         poolInfo.flags |= VK_COMMAND_POOL_CREATE_PROTECTED_BIT;
46     }
47     ANGLE_VK_TRY(context, mCommandPool.init(context->getDevice(), poolInfo));
48     return angle::Result::Continue;
49 }
50 
destroy(VkDevice device)51 void SecondaryCommandPool::destroy(VkDevice device)
52 {
53     // Command buffers will be destroyed with the Pool. Avoid possible slowdown during cleanup.
54     mCollectedBuffers.clear();
55     mCollectedBuffersOverflow.clear();
56     mCommandPool.destroy(device);
57 }
58 
allocate(Context * context,VulkanSecondaryCommandBuffer * buffer)59 angle::Result SecondaryCommandPool::allocate(Context *context, VulkanSecondaryCommandBuffer *buffer)
60 {
61     ASSERT(valid());
62     ASSERT(!buffer->valid());
63 
64     VkDevice device = context->getDevice();
65 
66     freeCollectedBuffers(device);
67 
68     VkCommandBufferAllocateInfo allocInfo = {};
69     allocInfo.sType                       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
70     allocInfo.level                       = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
71     allocInfo.commandBufferCount          = 1;
72     allocInfo.commandPool                 = mCommandPool.getHandle();
73 
74     ANGLE_VK_TRY(context, buffer->init(device, allocInfo));
75 
76     return angle::Result::Continue;
77 }
78 
collect(VulkanSecondaryCommandBuffer * buffer)79 void SecondaryCommandPool::collect(VulkanSecondaryCommandBuffer *buffer)
80 {
81     ASSERT(valid());
82     ASSERT(buffer->valid());
83 
84     VkCommandBuffer bufferHandle = buffer->releaseHandle();
85 
86     if (!mCollectedBuffers.full())
87     {
88         mCollectedBuffers.push(bufferHandle);
89     }
90     else
91     {
92         std::lock_guard<angle::SimpleMutex> lock(mOverflowMutex);
93         mCollectedBuffersOverflow.emplace_back(bufferHandle);
94         mHasOverflow.store(true, std::memory_order_relaxed);
95     }
96 }
97 
freeCollectedBuffers(VkDevice device)98 void SecondaryCommandPool::freeCollectedBuffers(VkDevice device)
99 {
100     // Free Command Buffer for now. May later add recycling or reset/free pool at once.
101     ANGLE_TRACE_EVENT0("gpu.angle", "SecondaryCommandPool::freeCollectedBuffers");
102 
103     while (!mCollectedBuffers.empty())
104     {
105         VkCommandBuffer bufferHandle = mCollectedBuffers.front();
106         mCommandPool.freeCommandBuffers(device, 1, &bufferHandle);
107         mCollectedBuffers.pop();
108     }
109 
110     if (ANGLE_UNLIKELY(mHasOverflow.load(std::memory_order_relaxed)))
111     {
112         std::vector<VkCommandBuffer> buffers;
113         {
114             std::lock_guard<angle::SimpleMutex> lock(mOverflowMutex);
115             buffers = std::move(mCollectedBuffersOverflow);
116             mHasOverflow.store(false, std::memory_order_relaxed);
117         }
118         for (VkCommandBuffer bufferHandle : buffers)
119         {
120             mCommandPool.freeCommandBuffers(device, 1, &bufferHandle);
121         }
122     }
123 }
124 
125 }  // namespace vk
126 }  // namespace rx
127