Hash :
9b6368cc
Author :
Date :
2023-03-14T14:48:30
Vulkan: Fix freeing Secondary Command Buffers from wrong thread. Problem: - Secondary Command Buffers are freed in the "CommandQueue" class. - This may happen from any Context thread that calls "checkCompletedCommands()" or "finish<*>()" methods. - As the result, one Command Buffer may be freed from one thread, while other Command Buffer from the same "VkCommandPool" is allocated/reset/recorded in the other thread. Vulkan spec demands external "VkCommandPool" synchronization for any modifications (begin/end/reset/free/cmd) on its "VkCommandBuffer"s. Fix: - Added new "rx::vk::SecondaryCommandPool" class that replaces the "rx::vk::CommandPool" wrapper. - This class has "collect()" method for storing "VkCommandBuffer"s. Collected buffers are freed from the correct thread on the next "allocate()" call. This CL only fixes the problem, keeping Secondary Command Buffer memory management as is (allocate/free single buffer without reuse). In the future CLs this behavior may be changed (reuse buffers, reset/free entire pools). Bug: angleproject:6100 Change-Id: If938416c4df4fe55f0cfb418b6759721ac53098b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4334577 Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Igor Nazarov <i.nazarov@samsung.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// VulkanSecondaryCommandBuffer:
// Implementation of VulkanSecondaryCommandBuffer.
//
#include "libANGLE/renderer/vulkan/VulkanSecondaryCommandBuffer.h"
#include "common/debug.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
namespace vk
{
angle::Result VulkanSecondaryCommandBuffer::InitializeCommandPool(Context *context,
SecondaryCommandPool *pool,
uint32_t queueFamilyIndex,
ProtectionType protectionType)
{
ANGLE_TRY(pool->init(context, queueFamilyIndex, protectionType));
return angle::Result::Continue;
}
angle::Result VulkanSecondaryCommandBuffer::InitializeRenderPassInheritanceInfo(
ContextVk *contextVk,
const Framebuffer &framebuffer,
const RenderPassDesc &renderPassDesc,
VkCommandBufferInheritanceInfo *inheritanceInfoOut)
{
const RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(contextVk->getCompatibleRenderPass(renderPassDesc, &compatibleRenderPass));
inheritanceInfoOut->sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inheritanceInfoOut->renderPass = compatibleRenderPass->getHandle();
inheritanceInfoOut->subpass = 0;
inheritanceInfoOut->framebuffer = framebuffer.getHandle();
return angle::Result::Continue;
}
angle::Result VulkanSecondaryCommandBuffer::initialize(Context *context,
SecondaryCommandPool *pool,
bool isRenderPassCommandBuffer,
SecondaryCommandMemoryAllocator *allocator)
{
mCommandPool = pool;
mCommandTracker.reset();
mAnyCommand = false;
ANGLE_TRY(pool->allocate(context, this));
// Outside-RP command buffers are begun automatically here. RP command buffers are begun when
// the render pass itself starts, as they require inheritance info.
if (!isRenderPassCommandBuffer)
{
VkCommandBufferInheritanceInfo inheritanceInfo = {};
inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
ANGLE_TRY(begin(context, inheritanceInfo));
}
return angle::Result::Continue;
}
void VulkanSecondaryCommandBuffer::destroy()
{
if (valid())
{
ASSERT(mCommandPool != nullptr);
mCommandPool->collect(this);
}
}
angle::Result VulkanSecondaryCommandBuffer::begin(
Context *context,
const VkCommandBufferInheritanceInfo &inheritanceInfo)
{
ASSERT(!mAnyCommand);
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = &inheritanceInfo;
if (inheritanceInfo.renderPass != VK_NULL_HANDLE)
{
beginInfo.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
}
ANGLE_VK_TRY(context, CommandBuffer::begin(beginInfo));
return angle::Result::Continue;
}
angle::Result VulkanSecondaryCommandBuffer::end(Context *context)
{
ANGLE_VK_TRY(context, CommandBuffer::end());
return angle::Result::Continue;
}
VkResult VulkanSecondaryCommandBuffer::reset()
{
mCommandTracker.reset();
mAnyCommand = false;
return CommandBuffer::reset();
}
} // namespace vk
} // namespace rx