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