Skip to content

Commit d8a95bf

Browse files
i-nazarov-ukraineAngle LUCI CQ
authored andcommitted
Vulkan: Protect OneOff commands recording with pool mutex
Bug: angleproject:384940864 Change-Id: I518c54ae4b0fc5da0e58d330f8c531bc8d65529e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6108843 Commit-Queue: Igor Nazarov <i.nazarov@samsung.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com>
1 parent 4237cca commit d8a95bf

File tree

9 files changed

+105
-49
lines changed

9 files changed

+105
-49
lines changed

src/libANGLE/renderer/vulkan/CommandQueue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,8 @@ void CommandPoolAccess::destroyPrimaryCommandBuffer(VkDevice device,
492492
PrimaryCommandBuffer *primaryCommands) const
493493
{
494494
ASSERT(primaryCommands->valid());
495-
std::lock_guard<angle::SimpleMutex> lock(mCmdPoolMutex);
496495

496+
// Does not require a pool mutex lock.
497497
primaryCommands->destroy(device);
498498
}
499499

src/libANGLE/renderer/vulkan/CommandQueue.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,43 @@ class CleanUpThread : public Context
543543
std::condition_variable mWorkAvailableCondition;
544544
std::atomic<bool> mNeedCleanUp;
545545
};
546+
547+
// Provides access to the PrimaryCommandBuffer while also locking the corresponding CommandPool
548+
class [[nodiscard]] ScopedPrimaryCommandBuffer final
549+
{
550+
public:
551+
explicit ScopedPrimaryCommandBuffer(VkDevice device) : mCommandBuffer(device) {}
552+
553+
void assign(std::unique_lock<angle::SimpleMutex> &&poolLock,
554+
PrimaryCommandBuffer &&commandBuffer)
555+
{
556+
ASSERT(poolLock.owns_lock());
557+
ASSERT(commandBuffer.valid());
558+
ASSERT(mPoolLock.mutex() == nullptr);
559+
ASSERT(!mCommandBuffer.get().valid());
560+
mPoolLock = std::move(poolLock);
561+
mCommandBuffer.get() = std::move(commandBuffer);
562+
}
563+
564+
PrimaryCommandBuffer &get()
565+
{
566+
ASSERT(mPoolLock.owns_lock());
567+
ASSERT(mCommandBuffer.get().valid());
568+
return mCommandBuffer.get();
569+
}
570+
571+
DeviceScoped<PrimaryCommandBuffer> unlockAndRelease()
572+
{
573+
ASSERT(mCommandBuffer.get().valid() && mPoolLock.owns_lock() ||
574+
!mCommandBuffer.get().valid() && mPoolLock.mutex() == nullptr);
575+
mPoolLock = {};
576+
return std::move(mCommandBuffer);
577+
}
578+
579+
private:
580+
std::unique_lock<angle::SimpleMutex> mPoolLock;
581+
DeviceScoped<PrimaryCommandBuffer> mCommandBuffer;
582+
};
546583
} // namespace vk
547584

548585
} // namespace rx

src/libANGLE/renderer/vulkan/ContextVk.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3923,10 +3923,11 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
39233923
ANGLE_VK_TRY(this, gpuDone.get().reset(device));
39243924

39253925
// Record the command buffer
3926-
vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
3927-
vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
3926+
vk::ScopedPrimaryCommandBuffer scopedCommandBuffer(device);
39283927

3929-
ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, getProtectionType(), &commandBuffer));
3928+
ANGLE_TRY(
3929+
mRenderer->getCommandBufferOneOff(this, getProtectionType(), &scopedCommandBuffer));
3930+
vk::PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
39303931

39313932
commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
39323933
commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
@@ -3941,8 +3942,9 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
39413942
QueueSerial submitSerial;
39423943
// vkEvent's are externally synchronized, therefore need work to be submitted before calling
39433944
// vkGetEventStatus
3944-
ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(commandBuffer), getProtectionType(),
3945-
mContextPriority, VK_NULL_HANDLE, 0, &submitSerial));
3945+
ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(scopedCommandBuffer),
3946+
getProtectionType(), mContextPriority,
3947+
VK_NULL_HANDLE, 0, &submitSerial));
39463948

39473949
// Track it with the submitSerial.
39483950
timestampQuery.setQueueSerial(submitSerial);
@@ -7973,17 +7975,17 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
79737975
ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, &timestampQuery, 1));
79747976

79757977
// Record the command buffer
7976-
vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
7977-
vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
7978+
vk::ScopedPrimaryCommandBuffer scopedCommandBuffer(device);
79787979

7979-
ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, getProtectionType(), &commandBuffer));
7980+
ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, getProtectionType(), &scopedCommandBuffer));
7981+
vk::PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
79807982

79817983
timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
79827984
ANGLE_VK_TRY(this, commandBuffer.end());
79837985

79847986
QueueSerial submitQueueSerial;
7985-
ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(commandBuffer), getProtectionType(),
7986-
mContextPriority, VK_NULL_HANDLE, 0,
7987+
ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(scopedCommandBuffer),
7988+
getProtectionType(), mContextPriority, VK_NULL_HANDLE, 0,
79877989
&submitQueueSerial));
79887990
// Track it with the submitSerial.
79897991
timestampQuery.setQueueSerial(submitQueueSerial);

src/libANGLE/renderer/vulkan/SurfaceVk.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,12 +2881,13 @@ VkResult WindowSurfaceVk::postProcessUnlockedAcquire(vk::Context *context)
28812881
{
28822882
ASSERT(image.image->valid() &&
28832883
image.image->getCurrentImageLayout() != vk::ImageLayout::SharedPresent);
2884-
rx::vk::Renderer *renderer = context->getRenderer();
2885-
rx::vk::PrimaryCommandBuffer primaryCommandBuffer;
2884+
vk::Renderer *renderer = context->getRenderer();
2885+
vk::ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
28862886
auto protectionType = vk::ConvertProtectionBoolToType(mState.hasProtectedContent());
2887-
if (renderer->getCommandBufferOneOff(context, protectionType, &primaryCommandBuffer) ==
2887+
if (renderer->getCommandBufferOneOff(context, protectionType, &scopedCommandBuffer) ==
28882888
angle::Result::Continue)
28892889
{
2890+
vk::PrimaryCommandBuffer &primaryCommandBuffer = scopedCommandBuffer.get();
28902891
VkSemaphore semaphore;
28912892
// Note return errors is early exit may leave new Image and Swapchain in unknown state.
28922893
image.image->recordWriteBarrierOneOff(context, vk::ImageLayout::SharedPresent,
@@ -2898,8 +2899,8 @@ VkResult WindowSurfaceVk::postProcessUnlockedAcquire(vk::Context *context)
28982899
return VK_ERROR_OUT_OF_DATE_KHR;
28992900
}
29002901
QueueSerial queueSerial;
2901-
if (renderer->queueSubmitOneOff(context, std::move(primaryCommandBuffer),
2902-
protectionType, egl::ContextPriority::Medium, semaphore,
2902+
if (renderer->queueSubmitOneOff(context, std::move(scopedCommandBuffer), protectionType,
2903+
egl::ContextPriority::Medium, semaphore,
29032904
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
29042905
&queueSerial) != angle::Result::Continue)
29052906
{

src/libANGLE/renderer/vulkan/vk_helpers.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5555,23 +5555,24 @@ angle::Result BufferHelper::initializeNonZeroMemory(Context *context,
55555555
StagingBuffer stagingBuffer;
55565556
ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
55575557

5558-
PrimaryCommandBuffer commandBuffer;
5559-
ANGLE_TRY(
5560-
renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
5561-
55625558
// Queue a DMA copy.
55635559
VkBufferCopy copyRegion = {};
55645560
copyRegion.srcOffset = 0;
55655561
copyRegion.dstOffset = getOffset();
55665562
copyRegion.size = size;
55675563

5564+
ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
5565+
ANGLE_TRY(renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected,
5566+
&scopedCommandBuffer));
5567+
PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
5568+
55685569
commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, &copyRegion);
55695570

55705571
ANGLE_VK_TRY(context, commandBuffer.end());
55715572

55725573
QueueSerial queueSerial;
55735574
ANGLE_TRY(renderer->queueSubmitOneOff(
5574-
context, std::move(commandBuffer), ProtectionType::Unprotected,
5575+
context, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
55755576
egl::ContextPriority::Medium, VK_NULL_HANDLE, 0, &queueSerial));
55765577

55775578
stagingBuffer.collectGarbage(renderer, queueSerial);
@@ -6172,9 +6173,10 @@ angle::Result ImageHelper::copyToBufferOneOff(Context *context,
61726173
VkBufferImageCopy copyRegion)
61736174
{
61746175
Renderer *renderer = context->getRenderer();
6175-
PrimaryCommandBuffer commandBuffer;
6176-
ANGLE_TRY(
6177-
renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
6176+
ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
6177+
ANGLE_TRY(renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected,
6178+
&scopedCommandBuffer));
6179+
PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
61786180

61796181
VkSemaphore acquireNextImageSemaphore;
61806182
barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst,
@@ -6185,10 +6187,10 @@ angle::Result ImageHelper::copyToBufferOneOff(Context *context,
61856187
ANGLE_VK_TRY(context, commandBuffer.end());
61866188

61876189
QueueSerial submitQueueSerial;
6188-
ANGLE_TRY(
6189-
renderer->queueSubmitOneOff(context, std::move(commandBuffer), ProtectionType::Unprotected,
6190-
egl::ContextPriority::Medium, acquireNextImageSemaphore,
6191-
kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
6190+
ANGLE_TRY(renderer->queueSubmitOneOff(
6191+
context, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
6192+
egl::ContextPriority::Medium, acquireNextImageSemaphore,
6193+
kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
61926194

61936195
return renderer->finishQueueSerial(context, submitQueueSerial);
61946196
}
@@ -6605,9 +6607,10 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context,
66056607
// setEvent.
66066608
ASSERT(!mCurrentEvent.valid());
66076609

6608-
PrimaryCommandBuffer commandBuffer;
6610+
ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
66096611
auto protectionType = ConvertProtectionBoolToType(hasProtectedContent);
6610-
ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &commandBuffer));
6612+
ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &scopedCommandBuffer));
6613+
PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
66116614

66126615
// Queue a DMA copy.
66136616
VkSemaphore acquireNextImageSemaphore;
@@ -6693,7 +6696,7 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context,
66936696
ANGLE_VK_TRY(context, commandBuffer.end());
66946697

66956698
QueueSerial queueSerial;
6696-
ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), protectionType,
6699+
ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(scopedCommandBuffer), protectionType,
66976700
egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
66986701
&queueSerial));
66996702

@@ -10856,11 +10859,12 @@ angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
1085610859

1085710860
// We may have a valid event here but we do not have a collector to collect it. Release the
1085810861
// event here to force pipelineBarrier.
10859-
mCurrentEvent.release(displayVk->getRenderer());
10862+
mCurrentEvent.release(renderer);
1086010863

10861-
PrimaryCommandBuffer primaryCommandBuffer;
10864+
ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
1086210865
ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
10863-
&primaryCommandBuffer));
10866+
&scopedCommandBuffer));
10867+
PrimaryCommandBuffer &primaryCommandBuffer = scopedCommandBuffer.get();
1086410868

1086510869
VkSemaphore acquireNextImageSemaphore;
1086610870
barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferSrc,
@@ -10873,7 +10877,7 @@ angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
1087310877

1087410878
QueueSerial submitQueueSerial;
1087510879
ANGLE_TRY(renderer->queueSubmitOneOff(
10876-
displayVk, std::move(primaryCommandBuffer), ProtectionType::Unprotected,
10880+
displayVk, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
1087710881
egl::ContextPriority::Medium, acquireNextImageSemaphore,
1087810882
kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
1087910883

@@ -10910,9 +10914,10 @@ angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
1091010914
// event here to force pipelineBarrier.
1091110915
mCurrentEvent.release(displayVk->getRenderer());
1091210916

10913-
PrimaryCommandBuffer commandBuffer;
10914-
ANGLE_TRY(
10915-
renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected, &commandBuffer));
10917+
ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
10918+
ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
10919+
&scopedCommandBuffer));
10920+
PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
1091610921

1091710922
VkSemaphore acquireNextImageSemaphore;
1091810923
barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferDst,
@@ -10925,7 +10930,7 @@ angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
1092510930

1092610931
QueueSerial submitQueueSerial;
1092710932
ANGLE_TRY(renderer->queueSubmitOneOff(
10928-
displayVk, std::move(commandBuffer), ProtectionType::Unprotected,
10933+
displayVk, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
1092910934
egl::ContextPriority::Medium, acquireNextImageSemaphore,
1093010935
kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
1093110936

src/libANGLE/renderer/vulkan/vk_renderer.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,16 +1672,18 @@ void OneOffCommandPool::destroy(VkDevice device)
16721672
}
16731673

16741674
angle::Result OneOffCommandPool::getCommandBuffer(vk::Context *context,
1675-
vk::PrimaryCommandBuffer *commandBufferOut)
1675+
vk::ScopedPrimaryCommandBuffer *commandBufferOut)
16761676
{
16771677
std::unique_lock<angle::SimpleMutex> lock(mMutex);
16781678

16791679
if (!mPendingCommands.empty() &&
16801680
context->getRenderer()->hasResourceUseFinished(mPendingCommands.front().use))
16811681
{
1682-
*commandBufferOut = std::move(mPendingCommands.front().commandBuffer);
1682+
commandBufferOut->assign(std::move(lock),
1683+
std::move(mPendingCommands.front().commandBuffer));
16831684
mPendingCommands.pop_front();
1684-
ANGLE_VK_TRY(context, commandBufferOut->reset());
1685+
// No need to explicitly call reset() on |commandBufferOut|, since the begin() call below
1686+
// will do it implicitly.
16851687
}
16861688
else
16871689
{
@@ -1707,14 +1709,16 @@ angle::Result OneOffCommandPool::getCommandBuffer(vk::Context *context,
17071709
allocInfo.commandBufferCount = 1;
17081710
allocInfo.commandPool = mCommandPool.getHandle();
17091711

1710-
ANGLE_VK_TRY(context, commandBufferOut->init(context->getDevice(), allocInfo));
1712+
PrimaryCommandBuffer newCommandBuffer;
1713+
ANGLE_VK_TRY(context, newCommandBuffer.init(context->getDevice(), allocInfo));
1714+
commandBufferOut->assign(std::move(lock), std::move(newCommandBuffer));
17111715
}
17121716

17131717
VkCommandBufferBeginInfo beginInfo = {};
17141718
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
17151719
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
17161720
beginInfo.pInheritanceInfo = nullptr;
1717-
ANGLE_VK_TRY(context, commandBufferOut->begin(beginInfo));
1721+
ANGLE_VK_TRY(context, commandBufferOut->get().begin(beginInfo));
17181722

17191723
return angle::Result::Continue;
17201724
}
@@ -6201,14 +6205,17 @@ void Renderer::outputVmaStatString()
62016205
}
62026206

62036207
angle::Result Renderer::queueSubmitOneOff(vk::Context *context,
6204-
vk::PrimaryCommandBuffer &&primary,
6208+
vk::ScopedPrimaryCommandBuffer &&scopedCommandBuffer,
62056209
vk::ProtectionType protectionType,
62066210
egl::ContextPriority priority,
62076211
VkSemaphore waitSemaphore,
62086212
VkPipelineStageFlags waitSemaphoreStageMasks,
62096213
QueueSerial *queueSerialOut)
62106214
{
62116215
ANGLE_TRACE_EVENT0("gpu.angle", "Renderer::queueSubmitOneOff");
6216+
DeviceScoped<PrimaryCommandBuffer> commandBuffer = scopedCommandBuffer.unlockAndRelease();
6217+
PrimaryCommandBuffer &primary = commandBuffer.get();
6218+
62126219
// Allocate a one off SerialIndex and generate a QueueSerial and then use it and release the
62136220
// index.
62146221
vk::ScopedQueueSerialIndex index;

src/libANGLE/renderer/vulkan/vk_renderer.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class OneOffCommandPool : angle::NonCopyable
119119
OneOffCommandPool();
120120
void init(vk::ProtectionType protectionType);
121121
angle::Result getCommandBuffer(vk::Context *context,
122-
vk::PrimaryCommandBuffer *commandBufferOut);
122+
vk::ScopedPrimaryCommandBuffer *commandBufferOut);
123123
void releaseCommandBuffer(const QueueSerial &submitQueueSerial,
124124
vk::PrimaryCommandBuffer &&primary);
125125
void destroy(VkDevice device);
@@ -307,15 +307,15 @@ class Renderer : angle::NonCopyable
307307
// This command buffer should be submitted immediately via queueSubmitOneOff.
308308
angle::Result getCommandBufferOneOff(vk::Context *context,
309309
vk::ProtectionType protectionType,
310-
vk::PrimaryCommandBuffer *commandBufferOut)
310+
vk::ScopedPrimaryCommandBuffer *commandBufferOut)
311311
{
312312
return mOneOffCommandPoolMap[protectionType].getCommandBuffer(context, commandBufferOut);
313313
}
314314

315315
// Fire off a single command buffer immediately with default priority.
316316
// Command buffer must be allocated with getCommandBufferOneOff and is reclaimed.
317317
angle::Result queueSubmitOneOff(vk::Context *context,
318-
vk::PrimaryCommandBuffer &&primary,
318+
vk::ScopedPrimaryCommandBuffer &&scopedCommandBuffer,
319319
vk::ProtectionType protectionType,
320320
egl::ContextPriority priority,
321321
VkSemaphore waitSemaphore,

src/libANGLE/renderer/vulkan/vk_utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,8 @@ template <typename T>
633633
class [[nodiscard]] DeviceScoped final : angle::NonCopyable
634634
{
635635
public:
636-
DeviceScoped(VkDevice device) : mDevice(device) {}
636+
explicit DeviceScoped(VkDevice device) : mDevice(device) {}
637+
DeviceScoped(DeviceScoped &&other) : mDevice(other.mDevice), mVar(std::move(other.mVar)) {}
637638
~DeviceScoped() { mVar.destroy(mDevice); }
638639

639640
const T &get() const { return mVar; }

src/libANGLE/renderer/vulkan/vk_wrapper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
172172
VkCommandBuffer releaseHandle();
173173

174174
// This is used for normal pool allocated command buffers. It reset the handle.
175+
// Note: this method does not require pool synchronization (locking the pool mutex).
175176
void destroy(VkDevice device);
176177

177178
// This is used in conjunction with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT.
@@ -910,6 +911,8 @@ ANGLE_INLINE void CommandBuffer::imageWaitEvent(const VkEvent &event,
910911

911912
ANGLE_INLINE void CommandBuffer::destroy(VkDevice device)
912913
{
914+
// Note: do not add code that may access the pool in any way, because this method may be called
915+
// without taking the pool mutex lock.
913916
releaseHandle();
914917
}
915918

0 commit comments

Comments
 (0)