• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(ErrorContext * context,uint32_t queueFamilyIndex,ProtectionType protectionType)29 angle::Result SecondaryCommandPool::init(ErrorContext *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(ErrorContext * context,VulkanSecondaryCommandBuffer * buffer)59 angle::Result SecondaryCommandPool::allocate(ErrorContext *context,
60                                              VulkanSecondaryCommandBuffer *buffer)
61 {
62     ASSERT(valid());
63     ASSERT(!buffer->valid());
64 
65     VkDevice device = context->getDevice();
66 
67     freeCollectedBuffers(device);
68 
69     VkCommandBufferAllocateInfo allocInfo = {};
70     allocInfo.sType                       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
71     allocInfo.level                       = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
72     allocInfo.commandBufferCount          = 1;
73     allocInfo.commandPool                 = mCommandPool.getHandle();
74 
75     ANGLE_VK_TRY(context, buffer->init(device, allocInfo));
76 
77     return angle::Result::Continue;
78 }
79 
collect(VulkanSecondaryCommandBuffer * buffer)80 void SecondaryCommandPool::collect(VulkanSecondaryCommandBuffer *buffer)
81 {
82     ASSERT(valid());
83     ASSERT(buffer->valid());
84 
85     VkCommandBuffer bufferHandle = buffer->releaseHandle();
86 
87     if (!mCollectedBuffers.full())
88     {
89         mCollectedBuffers.push(bufferHandle);
90     }
91     else
92     {
93         std::lock_guard<angle::SimpleMutex> lock(mOverflowMutex);
94         mCollectedBuffersOverflow.emplace_back(bufferHandle);
95         mHasOverflow.store(true, std::memory_order_relaxed);
96     }
97 }
98 
freeCollectedBuffers(VkDevice device)99 void SecondaryCommandPool::freeCollectedBuffers(VkDevice device)
100 {
101     // Free Command Buffer for now. May later add recycling or reset/free pool at once.
102     ANGLE_TRACE_EVENT0("gpu.angle", "SecondaryCommandPool::freeCollectedBuffers");
103 
104     while (!mCollectedBuffers.empty())
105     {
106         VkCommandBuffer bufferHandle = mCollectedBuffers.front();
107         mCommandPool.freeCommandBuffers(device, 1, &bufferHandle);
108         mCollectedBuffers.pop();
109     }
110 
111     if (ANGLE_UNLIKELY(mHasOverflow.load(std::memory_order_relaxed)))
112     {
113         std::vector<VkCommandBuffer> buffers;
114         {
115             std::lock_guard<angle::SimpleMutex> lock(mOverflowMutex);
116             buffers = std::move(mCollectedBuffersOverflow);
117             mHasOverflow.store(false, std::memory_order_relaxed);
118         }
119         for (VkCommandBuffer bufferHandle : buffers)
120         {
121             mCommandPool.freeCommandBuffers(device, 1, &bufferHandle);
122         }
123     }
124 }
125 
126 }  // namespace vk
127 }  // namespace rx
128