Commit f750d86a by Tim Van Patten Committed by Commit Bot

Trigger a flush() when the command graph contains too many objects

If an App repeatedly issues GL commands like glTextImage2D without a finish/flush/draw, it's possible for ANGLE to exhaust the available Vulkan memory allocations and exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount. When this occurs, the Vulkan validation layers will trigger an error and cause dEQP tests to fail. This change will query the backend if a flush() should be performed during each of the GL delete calls, and perform it if necessary. This will cause a queue submission and a Serial increment, allowing the allocated memory to be freed, preventing the validation errors. Bug: angleproject:3818 Test: KHR-GLES3.copy_tex_image_conversions.forbidden.renderbuffer_cubemap_* Change-Id: I26d0a47aa7bca10c25bc8141f1523afbab0b3b5b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1834781 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 1f08ab28
......@@ -2909,6 +2909,11 @@ void ContextVk::insertWaitSemaphore(const vk::Semaphore *waitSemaphore)
mWaitSemaphores.push_back(waitSemaphore->getHandle());
}
bool ContextVk::shouldFlush()
{
return getRenderer()->shouldCleanupGarbage();
}
angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
{
if (mCommandGraph.empty() && !signalSemaphore && mWaitSemaphores.empty())
......
......@@ -324,6 +324,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void insertWaitSemaphore(const vk::Semaphore *waitSemaphore);
bool shouldFlush();
angle::Result flushImpl(const vk::Semaphore *semaphore);
angle::Result finishImpl();
......
......@@ -832,6 +832,10 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
ChoosePhysicalDevice(physicalDevices, mEnabledICD, &mPhysicalDevice,
&mPhysicalDeviceProperties);
mGarbageCollectionFlushThreshold =
static_cast<uint32_t>(mPhysicalDeviceProperties.limits.maxMemoryAllocationCount *
kPercentMaxMemoryAllocationCount);
vkGetPhysicalDeviceFeatures(mPhysicalDevice, &mPhysicalDeviceFeatures);
// Ensure we can find a graphics queue family.
......
......@@ -197,6 +197,11 @@ class RendererVk : angle::NonCopyable
void onCompletedSerial(Serial serial);
bool shouldCleanupGarbage()
{
return (mSharedGarbage.size() > mGarbageCollectionFlushThreshold);
}
private:
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
......@@ -280,6 +285,11 @@ class RendererVk : angle::NonCopyable
// Latest validation data for debug overlay.
std::string mLastValidationMessage;
uint32_t mValidationMessageCount;
// How close to VkPhysicalDeviceLimits::maxMemoryAllocationCount we allow ourselves to get
static constexpr double kPercentMaxMemoryAllocationCount = 0.3;
// How many objects to garbage collect before issuing a flush()
uint32_t mGarbageCollectionFlushThreshold;
};
} // namespace rx
......
......@@ -1309,6 +1309,14 @@ angle::Result BufferHelper::init(ContextVk *contextVk,
const VkBufferCreateInfo &createInfo,
VkMemoryPropertyFlags memoryPropertyFlags)
{
// TODO: Remove with anglebug.com/2162: Vulkan: Implement device memory sub-allocation
// Check if we have too many resources allocated already and need to free some before allocating
// more and (possibly) exceeding the device's limits.
if (contextVk->shouldFlush())
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
mSize = createInfo.size;
ANGLE_VK_TRY(contextVk, mBuffer.init(contextVk->getDevice(), createInfo));
return vk::AllocateBufferMemory(contextVk, memoryPropertyFlags, &mMemoryPropertyFlags, nullptr,
......
......@@ -341,8 +341,16 @@ void StagingBuffer::destroy(VkDevice device)
mSize = 0;
}
angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUsage usage)
angle::Result StagingBuffer::init(ContextVk *contextVk, VkDeviceSize size, StagingUsage usage)
{
// TODO: Remove with anglebug.com/2162: Vulkan: Implement device memory sub-allocation
// Check if we have too many resources allocated already and need to free some before allocating
// more and (possibly) exceeding the device's limits.
if (contextVk->shouldFlush())
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.flags = 0;
......@@ -355,9 +363,9 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo));
ANGLE_VK_TRY(contextVk, mBuffer.init(contextVk->getDevice(), createInfo));
VkMemoryPropertyFlags flagsOut = 0;
ANGLE_TRY(AllocateBufferMemory(context, flags, &flagsOut, nullptr, &mBuffer, &mDeviceMemory));
ANGLE_TRY(AllocateBufferMemory(contextVk, flags, &flagsOut, nullptr, &mBuffer, &mDeviceMemory));
mSize = static_cast<size_t>(size);
return angle::Result::Continue;
}
......
......@@ -292,7 +292,7 @@ class StagingBuffer final : angle::NonCopyable
void release(ContextVk *contextVk);
void destroy(VkDevice device);
angle::Result init(Context *context, VkDeviceSize size, StagingUsage usage);
angle::Result init(ContextVk *context, VkDeviceSize size, StagingUsage usage);
Buffer &getBuffer() { return mBuffer; }
const Buffer &getBuffer() const { return mBuffer; }
......
......@@ -95,13 +95,6 @@
3817 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.cubemap_posz_cubemap_posy = FAIL
3817 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.cubemap_posz_cubemap_posz = FAIL
// Failing due to Vulkan validation error re: "Number of currently valid memory objects is not less than the maximum allowed" error.
3818 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.renderbuffer_cubemap_negy = FAIL
3818 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.renderbuffer_cubemap_negz = FAIL
3818 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.renderbuffer_cubemap_posx = FAIL
3818 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.renderbuffer_cubemap_posy = FAIL
3818 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.renderbuffer_cubemap_posz = FAIL
// glCopyTexImage from 3D textures is failing and getting the following Vulkan Validation errors:
//
// ImageView must not be a 2D or 2DArray view of a 3D image. The Vulkan spec states:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment