Hash :
cb31b886
Author :
Date :
2024-11-22T13:15:57
Vulkan: pruneDefaultBufferPools when there is excessive garbage What commonly happens with game (and traces) is that we upload a lot of textures before first frame is drawn. These texture uploads uses a lot of buffer memory and creates peak memory usage moment if not clean up quickly. This CL adds back the check if there is excessive suballocation memory gets destroyed, don't wait until frame boundary to prune empty buffer blocks. Do the prune immediately so that these memory could be reused for other purpose for the first frame rendering. Bug: angleproject:372268711 Change-Id: Ie548245b5ce108be0e2c19b296a28025bface395 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6043405 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Yuxin Hu <yuxinhu@google.com>
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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
//
// Copyright 2023 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.
//
// ShareGroupVk.h:
// Defines the class interface for ShareGroupVk, implementing ShareGroupImpl.
//
#ifndef LIBANGLE_RENDERER_VULKAN_SHAREGROUPVK_H_
#define LIBANGLE_RENDERER_VULKAN_SHAREGROUPVK_H_
#include "libANGLE/renderer/ShareGroupImpl.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
#include "libANGLE/renderer/vulkan/vk_resource.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
constexpr VkDeviceSize kMaxTotalEmptyBufferBytes = 16 * 1024 * 1024;
class TextureUpload
{
public:
TextureUpload() { mPrevUploadedMutableTexture = nullptr; }
~TextureUpload() { resetPrevTexture(); }
angle::Result onMutableTextureUpload(ContextVk *contextVk, TextureVk *newTexture);
void onTextureRelease(TextureVk *textureVk);
void resetPrevTexture() { mPrevUploadedMutableTexture = nullptr; }
private:
// Keep track of the previously stored texture. Used to flush mutable textures.
TextureVk *mPrevUploadedMutableTexture;
};
class ShareGroupVk : public ShareGroupImpl
{
public:
ShareGroupVk(const egl::ShareGroupState &state, vk::Renderer *renderer);
void onDestroy(const egl::Display *display) override;
void onContextAdd() override;
FramebufferCache &getFramebufferCache() { return mFramebufferCache; }
bool hasAnyContextWithRobustness() const { return mState.hasAnyContextWithRobustness(); }
// PipelineLayoutCache and DescriptorSetLayoutCache can be shared between multiple threads
// accessing them via shared contexts. The ShareGroup locks around gl entrypoints ensuring
// synchronous update to the caches.
PipelineLayoutCache &getPipelineLayoutCache() { return mPipelineLayoutCache; }
DescriptorSetLayoutCache &getDescriptorSetLayoutCache() { return mDescriptorSetLayoutCache; }
const egl::ContextMap &getContexts() const { return mState.getContexts(); }
vk::DescriptorSetArray<vk::MetaDescriptorPool> &getMetaDescriptorPools()
{
return mMetaDescriptorPools;
}
// Used to flush the mutable textures more often.
angle::Result onMutableTextureUpload(ContextVk *contextVk, TextureVk *newTexture);
vk::BufferPool *getDefaultBufferPool(VkDeviceSize size,
uint32_t memoryTypeIndex,
BufferUsageType usageType);
void pruneDefaultBufferPools();
void calculateTotalBufferCount(size_t *bufferCount, VkDeviceSize *totalSize) const;
void logBufferPools() const;
// Temporary workaround until VkSemaphore(s) will be used between different priorities.
angle::Result unifyContextsPriority(ContextVk *newContextVk);
// Temporary workaround until VkSemaphore(s) will be used between different priorities.
angle::Result lockDefaultContextsPriority(ContextVk *contextVk);
UpdateDescriptorSetsBuilder *getUpdateDescriptorSetsBuilder()
{
return &mUpdateDescriptorSetsBuilder;
}
void onTextureRelease(TextureVk *textureVk);
VertexInputGraphicsPipelineCache *getVertexInputGraphicsPipelineCache()
{
return &mVertexInputGraphicsPipelineCache;
}
FragmentOutputGraphicsPipelineCache *getFragmentOutputGraphicsPipelineCache()
{
return &mFragmentOutputGraphicsPipelineCache;
}
angle::Result scheduleMonolithicPipelineCreationTask(
ContextVk *contextVk,
vk::WaitableMonolithicPipelineCreationTask *taskOut);
void waitForCurrentMonolithicPipelineCreationTask();
vk::RefCountedEventsGarbageRecycler *getRefCountedEventsGarbageRecycler()
{
return &mRefCountedEventsGarbageRecycler;
}
void cleanupRefCountedEventGarbage() { mRefCountedEventsGarbageRecycler.cleanup(mRenderer); }
void cleanupExcessiveRefCountedEventGarbage()
{
// TODO: b/336844257 needs tune.
constexpr size_t kExcessiveGarbageCountThreshold = 256;
if (mRefCountedEventsGarbageRecycler.getGarbageCount() > kExcessiveGarbageCountThreshold)
{
mRefCountedEventsGarbageRecycler.cleanup(mRenderer);
}
}
void onFramebufferBoundary();
uint32_t getCurrentFrameCount() const { return mCurrentFrameCount; }
private:
angle::Result updateContextsPriority(ContextVk *contextVk, egl::ContextPriority newPriority);
bool isDueForBufferPoolPrune();
vk::Renderer *mRenderer;
// Tracks the total number of frames rendered.
uint32_t mCurrentFrameCount;
// VkFramebuffer caches
FramebufferCache mFramebufferCache;
void resetPrevTexture() { mTextureUpload.resetPrevTexture(); }
// ANGLE uses a PipelineLayout cache to store compatible pipeline layouts.
PipelineLayoutCache mPipelineLayoutCache;
// DescriptorSetLayouts are also managed in a cache.
DescriptorSetLayoutCache mDescriptorSetLayoutCache;
// Descriptor set caches
vk::DescriptorSetArray<vk::MetaDescriptorPool> mMetaDescriptorPools;
// Priority of all Contexts in the context set
egl::ContextPriority mContextsPriority;
bool mIsContextsPriorityLocked;
// Storage for vkUpdateDescriptorSets
UpdateDescriptorSetsBuilder mUpdateDescriptorSetsBuilder;
// The per shared group buffer pools that all buffers should sub-allocate from.
vk::BufferPoolPointerArray mDefaultBufferPools;
// The system time when last pruneEmptyBuffer gets called.
double mLastPruneTime;
// Used when VK_EXT_graphics_pipeline_library is available, the vertex input and fragment output
// partial pipelines are created in the following caches. These caches are in the share group
// because linked pipelines using these pipeline libraries are referenced from
// ProgramExecutableVk, and as such must stay alive as long as the program may be alive.
VertexInputGraphicsPipelineCache mVertexInputGraphicsPipelineCache;
FragmentOutputGraphicsPipelineCache mFragmentOutputGraphicsPipelineCache;
// The system time when the last monolithic pipeline creation job was launched. This is
// rate-limited to avoid hogging all cores and interfering with the application threads. A
// single pipeline creation job is currently supported.
double mLastMonolithicPipelineJobTime;
std::shared_ptr<angle::WaitableEvent> mMonolithicPipelineCreationEvent;
// Texture update manager used to flush uploaded mutable textures.
TextureUpload mTextureUpload;
// Holds RefCountedEvent that are free and ready to reuse
vk::RefCountedEventsGarbageRecycler mRefCountedEventsGarbageRecycler;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_SHAREGROUPVK_H_