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