1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #include "CacheManager.h"
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include <SkExecutor.h>
20*d57664e9SAndroid Build Coastguard Worker #include <SkGraphics.h>
21*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrContextOptions.h>
22*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrTypes.h>
23*d57664e9SAndroid Build Coastguard Worker #include <math.h>
24*d57664e9SAndroid Build Coastguard Worker #include <utils/Trace.h>
25*d57664e9SAndroid Build Coastguard Worker
26*d57664e9SAndroid Build Coastguard Worker #include <set>
27*d57664e9SAndroid Build Coastguard Worker
28*d57664e9SAndroid Build Coastguard Worker #include "CanvasContext.h"
29*d57664e9SAndroid Build Coastguard Worker #include "DeviceInfo.h"
30*d57664e9SAndroid Build Coastguard Worker #include "Layer.h"
31*d57664e9SAndroid Build Coastguard Worker #include "Properties.h"
32*d57664e9SAndroid Build Coastguard Worker #include "RenderThread.h"
33*d57664e9SAndroid Build Coastguard Worker #include "VulkanManager.h"
34*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/ATraceMemoryDump.h"
35*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/ShaderCache.h"
36*d57664e9SAndroid Build Coastguard Worker #include "pipeline/skia/SkiaMemoryTracer.h"
37*d57664e9SAndroid Build Coastguard Worker #include "renderstate/RenderState.h"
38*d57664e9SAndroid Build Coastguard Worker #include "thread/CommonPool.h"
39*d57664e9SAndroid Build Coastguard Worker
40*d57664e9SAndroid Build Coastguard Worker namespace android {
41*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
42*d57664e9SAndroid Build Coastguard Worker namespace renderthread {
43*d57664e9SAndroid Build Coastguard Worker
CacheManager(RenderThread & thread)44*d57664e9SAndroid Build Coastguard Worker CacheManager::CacheManager(RenderThread& thread)
45*d57664e9SAndroid Build Coastguard Worker : mRenderThread(thread), mMemoryPolicy(loadMemoryPolicy()) {
46*d57664e9SAndroid Build Coastguard Worker mMaxSurfaceArea = static_cast<size_t>((DeviceInfo::getWidth() * DeviceInfo::getHeight()) *
47*d57664e9SAndroid Build Coastguard Worker mMemoryPolicy.initialMaxSurfaceAreaScale);
48*d57664e9SAndroid Build Coastguard Worker setupCacheLimits();
49*d57664e9SAndroid Build Coastguard Worker }
50*d57664e9SAndroid Build Coastguard Worker
countLeadingZeros(uint32_t mask)51*d57664e9SAndroid Build Coastguard Worker static inline int countLeadingZeros(uint32_t mask) {
52*d57664e9SAndroid Build Coastguard Worker // __builtin_clz(0) is undefined, so we have to detect that case.
53*d57664e9SAndroid Build Coastguard Worker return mask ? __builtin_clz(mask) : 32;
54*d57664e9SAndroid Build Coastguard Worker }
55*d57664e9SAndroid Build Coastguard Worker
56*d57664e9SAndroid Build Coastguard Worker // Return the smallest power-of-2 >= n.
nextPowerOfTwo(uint32_t n)57*d57664e9SAndroid Build Coastguard Worker static inline uint32_t nextPowerOfTwo(uint32_t n) {
58*d57664e9SAndroid Build Coastguard Worker return n ? (1 << (32 - countLeadingZeros(n - 1))) : 1;
59*d57664e9SAndroid Build Coastguard Worker }
60*d57664e9SAndroid Build Coastguard Worker
setupCacheLimits()61*d57664e9SAndroid Build Coastguard Worker void CacheManager::setupCacheLimits() {
62*d57664e9SAndroid Build Coastguard Worker mMaxResourceBytes = mMaxSurfaceArea * mMemoryPolicy.surfaceSizeMultiplier;
63*d57664e9SAndroid Build Coastguard Worker mBackgroundResourceBytes = mMaxResourceBytes * mMemoryPolicy.backgroundRetentionPercent;
64*d57664e9SAndroid Build Coastguard Worker // This sets the maximum size for a single texture atlas in the GPU font cache. If
65*d57664e9SAndroid Build Coastguard Worker // necessary, the cache can allocate additional textures that are counted against the
66*d57664e9SAndroid Build Coastguard Worker // total cache limits provided to Skia.
67*d57664e9SAndroid Build Coastguard Worker mMaxGpuFontAtlasBytes = nextPowerOfTwo(mMaxSurfaceArea);
68*d57664e9SAndroid Build Coastguard Worker // This sets the maximum size of the CPU font cache to be at least the same size as the
69*d57664e9SAndroid Build Coastguard Worker // total number of GPU font caches (i.e. 4 separate GPU atlases).
70*d57664e9SAndroid Build Coastguard Worker mMaxCpuFontCacheBytes = std::max(mMaxGpuFontAtlasBytes * 4, SkGraphics::GetFontCacheLimit());
71*d57664e9SAndroid Build Coastguard Worker mBackgroundCpuFontCacheBytes = mMaxCpuFontCacheBytes * mMemoryPolicy.backgroundRetentionPercent;
72*d57664e9SAndroid Build Coastguard Worker
73*d57664e9SAndroid Build Coastguard Worker SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
74*d57664e9SAndroid Build Coastguard Worker if (mGrContext) {
75*d57664e9SAndroid Build Coastguard Worker mGrContext->setResourceCacheLimit(mMaxResourceBytes);
76*d57664e9SAndroid Build Coastguard Worker }
77*d57664e9SAndroid Build Coastguard Worker }
78*d57664e9SAndroid Build Coastguard Worker
reset(sk_sp<GrDirectContext> context)79*d57664e9SAndroid Build Coastguard Worker void CacheManager::reset(sk_sp<GrDirectContext> context) {
80*d57664e9SAndroid Build Coastguard Worker if (context != mGrContext) {
81*d57664e9SAndroid Build Coastguard Worker destroy();
82*d57664e9SAndroid Build Coastguard Worker }
83*d57664e9SAndroid Build Coastguard Worker
84*d57664e9SAndroid Build Coastguard Worker if (context) {
85*d57664e9SAndroid Build Coastguard Worker mGrContext = std::move(context);
86*d57664e9SAndroid Build Coastguard Worker mGrContext->setResourceCacheLimit(mMaxResourceBytes);
87*d57664e9SAndroid Build Coastguard Worker mLastDeferredCleanup = systemTime(CLOCK_MONOTONIC);
88*d57664e9SAndroid Build Coastguard Worker }
89*d57664e9SAndroid Build Coastguard Worker }
90*d57664e9SAndroid Build Coastguard Worker
destroy()91*d57664e9SAndroid Build Coastguard Worker void CacheManager::destroy() {
92*d57664e9SAndroid Build Coastguard Worker // cleanup any caches here as the GrContext is about to go away...
93*d57664e9SAndroid Build Coastguard Worker mGrContext.reset(nullptr);
94*d57664e9SAndroid Build Coastguard Worker }
95*d57664e9SAndroid Build Coastguard Worker
96*d57664e9SAndroid Build Coastguard Worker class CommonPoolExecutor : public SkExecutor {
97*d57664e9SAndroid Build Coastguard Worker public:
add(std::function<void (void)> func)98*d57664e9SAndroid Build Coastguard Worker virtual void add(std::function<void(void)> func) override { CommonPool::post(std::move(func)); }
99*d57664e9SAndroid Build Coastguard Worker };
100*d57664e9SAndroid Build Coastguard Worker
101*d57664e9SAndroid Build Coastguard Worker static CommonPoolExecutor sDefaultExecutor;
102*d57664e9SAndroid Build Coastguard Worker
configureContext(GrContextOptions * contextOptions,const void * identity,ssize_t size)103*d57664e9SAndroid Build Coastguard Worker void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity,
104*d57664e9SAndroid Build Coastguard Worker ssize_t size) {
105*d57664e9SAndroid Build Coastguard Worker contextOptions->fAllowPathMaskCaching = true;
106*d57664e9SAndroid Build Coastguard Worker contextOptions->fGlyphCacheTextureMaximumBytes = mMaxGpuFontAtlasBytes;
107*d57664e9SAndroid Build Coastguard Worker contextOptions->fExecutor = &sDefaultExecutor;
108*d57664e9SAndroid Build Coastguard Worker
109*d57664e9SAndroid Build Coastguard Worker auto& cache = skiapipeline::ShaderCache::get();
110*d57664e9SAndroid Build Coastguard Worker cache.initShaderDiskCache(identity, size);
111*d57664e9SAndroid Build Coastguard Worker contextOptions->fPersistentCache = &cache;
112*d57664e9SAndroid Build Coastguard Worker }
113*d57664e9SAndroid Build Coastguard Worker
toSkiaEnum(bool scratchOnly)114*d57664e9SAndroid Build Coastguard Worker static GrPurgeResourceOptions toSkiaEnum(bool scratchOnly) {
115*d57664e9SAndroid Build Coastguard Worker return scratchOnly ? GrPurgeResourceOptions::kScratchResourcesOnly :
116*d57664e9SAndroid Build Coastguard Worker GrPurgeResourceOptions::kAllResources;
117*d57664e9SAndroid Build Coastguard Worker }
118*d57664e9SAndroid Build Coastguard Worker
trimMemory(TrimLevel mode)119*d57664e9SAndroid Build Coastguard Worker void CacheManager::trimMemory(TrimLevel mode) {
120*d57664e9SAndroid Build Coastguard Worker if (!mGrContext) {
121*d57664e9SAndroid Build Coastguard Worker return;
122*d57664e9SAndroid Build Coastguard Worker }
123*d57664e9SAndroid Build Coastguard Worker
124*d57664e9SAndroid Build Coastguard Worker // flush and submit all work to the gpu and wait for it to finish
125*d57664e9SAndroid Build Coastguard Worker mGrContext->flushAndSubmit(GrSyncCpu::kYes);
126*d57664e9SAndroid Build Coastguard Worker
127*d57664e9SAndroid Build Coastguard Worker if (mode >= TrimLevel::BACKGROUND) {
128*d57664e9SAndroid Build Coastguard Worker mGrContext->freeGpuResources();
129*d57664e9SAndroid Build Coastguard Worker SkGraphics::PurgeAllCaches();
130*d57664e9SAndroid Build Coastguard Worker mRenderThread.destroyRenderingContext();
131*d57664e9SAndroid Build Coastguard Worker } else if (mode == TrimLevel::UI_HIDDEN) {
132*d57664e9SAndroid Build Coastguard Worker // Here we purge all the unlocked scratch resources and then toggle the resources cache
133*d57664e9SAndroid Build Coastguard Worker // limits between the background and max amounts. This causes the unlocked resources
134*d57664e9SAndroid Build Coastguard Worker // that have persistent data to be purged in LRU order.
135*d57664e9SAndroid Build Coastguard Worker mGrContext->setResourceCacheLimit(mBackgroundResourceBytes);
136*d57664e9SAndroid Build Coastguard Worker SkGraphics::SetFontCacheLimit(mBackgroundCpuFontCacheBytes);
137*d57664e9SAndroid Build Coastguard Worker mGrContext->purgeUnlockedResources(toSkiaEnum(mMemoryPolicy.purgeScratchOnly));
138*d57664e9SAndroid Build Coastguard Worker mGrContext->setResourceCacheLimit(mMaxResourceBytes);
139*d57664e9SAndroid Build Coastguard Worker SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
140*d57664e9SAndroid Build Coastguard Worker }
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker
trimCaches(CacheTrimLevel mode)143*d57664e9SAndroid Build Coastguard Worker void CacheManager::trimCaches(CacheTrimLevel mode) {
144*d57664e9SAndroid Build Coastguard Worker switch (mode) {
145*d57664e9SAndroid Build Coastguard Worker case CacheTrimLevel::FONT_CACHE:
146*d57664e9SAndroid Build Coastguard Worker SkGraphics::PurgeFontCache();
147*d57664e9SAndroid Build Coastguard Worker break;
148*d57664e9SAndroid Build Coastguard Worker case CacheTrimLevel::RESOURCE_CACHE:
149*d57664e9SAndroid Build Coastguard Worker SkGraphics::PurgeResourceCache();
150*d57664e9SAndroid Build Coastguard Worker break;
151*d57664e9SAndroid Build Coastguard Worker case CacheTrimLevel::ALL_CACHES:
152*d57664e9SAndroid Build Coastguard Worker SkGraphics::PurgeAllCaches();
153*d57664e9SAndroid Build Coastguard Worker if (mGrContext) {
154*d57664e9SAndroid Build Coastguard Worker mGrContext->purgeUnlockedResources(GrPurgeResourceOptions::kAllResources);
155*d57664e9SAndroid Build Coastguard Worker }
156*d57664e9SAndroid Build Coastguard Worker break;
157*d57664e9SAndroid Build Coastguard Worker default:
158*d57664e9SAndroid Build Coastguard Worker break;
159*d57664e9SAndroid Build Coastguard Worker }
160*d57664e9SAndroid Build Coastguard Worker }
161*d57664e9SAndroid Build Coastguard Worker
trimStaleResources()162*d57664e9SAndroid Build Coastguard Worker void CacheManager::trimStaleResources() {
163*d57664e9SAndroid Build Coastguard Worker if (!mGrContext) {
164*d57664e9SAndroid Build Coastguard Worker return;
165*d57664e9SAndroid Build Coastguard Worker }
166*d57664e9SAndroid Build Coastguard Worker mGrContext->flushAndSubmit();
167*d57664e9SAndroid Build Coastguard Worker mGrContext->performDeferredCleanup(std::chrono::seconds(30),
168*d57664e9SAndroid Build Coastguard Worker GrPurgeResourceOptions::kAllResources);
169*d57664e9SAndroid Build Coastguard Worker }
170*d57664e9SAndroid Build Coastguard Worker
getMemoryUsage(size_t * cpuUsage,size_t * gpuUsage)171*d57664e9SAndroid Build Coastguard Worker void CacheManager::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
172*d57664e9SAndroid Build Coastguard Worker *cpuUsage = 0;
173*d57664e9SAndroid Build Coastguard Worker *gpuUsage = 0;
174*d57664e9SAndroid Build Coastguard Worker if (!mGrContext) {
175*d57664e9SAndroid Build Coastguard Worker return;
176*d57664e9SAndroid Build Coastguard Worker }
177*d57664e9SAndroid Build Coastguard Worker
178*d57664e9SAndroid Build Coastguard Worker skiapipeline::SkiaMemoryTracer cpuTracer("category", true);
179*d57664e9SAndroid Build Coastguard Worker SkGraphics::DumpMemoryStatistics(&cpuTracer);
180*d57664e9SAndroid Build Coastguard Worker *cpuUsage += cpuTracer.total();
181*d57664e9SAndroid Build Coastguard Worker
182*d57664e9SAndroid Build Coastguard Worker skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
183*d57664e9SAndroid Build Coastguard Worker mGrContext->dumpMemoryStatistics(&gpuTracer);
184*d57664e9SAndroid Build Coastguard Worker *gpuUsage += gpuTracer.total();
185*d57664e9SAndroid Build Coastguard Worker }
186*d57664e9SAndroid Build Coastguard Worker
dumpMemoryUsage(String8 & log,const RenderState * renderState)187*d57664e9SAndroid Build Coastguard Worker void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) {
188*d57664e9SAndroid Build Coastguard Worker log.appendFormat(R"(Memory policy:
189*d57664e9SAndroid Build Coastguard Worker Max surface area: %zu
190*d57664e9SAndroid Build Coastguard Worker Max resource usage: %.2fMB (x%.0f)
191*d57664e9SAndroid Build Coastguard Worker Background retention: %.0f%% (altUiHidden = %s)
192*d57664e9SAndroid Build Coastguard Worker )",
193*d57664e9SAndroid Build Coastguard Worker mMaxSurfaceArea, mMaxResourceBytes / 1000000.f,
194*d57664e9SAndroid Build Coastguard Worker mMemoryPolicy.surfaceSizeMultiplier,
195*d57664e9SAndroid Build Coastguard Worker mMemoryPolicy.backgroundRetentionPercent * 100.0f,
196*d57664e9SAndroid Build Coastguard Worker mMemoryPolicy.useAlternativeUiHidden ? "true" : "false");
197*d57664e9SAndroid Build Coastguard Worker if (Properties::isSystemOrPersistent) {
198*d57664e9SAndroid Build Coastguard Worker log.appendFormat(" IsSystemOrPersistent\n");
199*d57664e9SAndroid Build Coastguard Worker }
200*d57664e9SAndroid Build Coastguard Worker log.appendFormat(" GPU Context timeout: %" PRIu64 "\n", ns2s(mMemoryPolicy.contextTimeout));
201*d57664e9SAndroid Build Coastguard Worker size_t stoppedContexts = 0;
202*d57664e9SAndroid Build Coastguard Worker for (auto context : mCanvasContexts) {
203*d57664e9SAndroid Build Coastguard Worker if (context->isStopped()) stoppedContexts++;
204*d57664e9SAndroid Build Coastguard Worker }
205*d57664e9SAndroid Build Coastguard Worker log.appendFormat("Contexts: %zu (stopped = %zu)\n", mCanvasContexts.size(), stoppedContexts);
206*d57664e9SAndroid Build Coastguard Worker
207*d57664e9SAndroid Build Coastguard Worker auto vkInstance = VulkanManager::peekInstance();
208*d57664e9SAndroid Build Coastguard Worker if (!mGrContext) {
209*d57664e9SAndroid Build Coastguard Worker if (!vkInstance) {
210*d57664e9SAndroid Build Coastguard Worker log.appendFormat("No GPU context.\n");
211*d57664e9SAndroid Build Coastguard Worker } else {
212*d57664e9SAndroid Build Coastguard Worker log.appendFormat("No GrContext; however %d remaining Vulkan refs",
213*d57664e9SAndroid Build Coastguard Worker vkInstance->getStrongCount() - 1);
214*d57664e9SAndroid Build Coastguard Worker }
215*d57664e9SAndroid Build Coastguard Worker return;
216*d57664e9SAndroid Build Coastguard Worker }
217*d57664e9SAndroid Build Coastguard Worker std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
218*d57664e9SAndroid Build Coastguard Worker {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
219*d57664e9SAndroid Build Coastguard Worker {"skia/sk_resource_cache/rrect-blur_", "Masks"},
220*d57664e9SAndroid Build Coastguard Worker {"skia/sk_resource_cache/rects-blur_", "Masks"},
221*d57664e9SAndroid Build Coastguard Worker {"skia/sk_resource_cache/tessellated", "Shadows"},
222*d57664e9SAndroid Build Coastguard Worker {"skia/sk_glyph_cache", "Glyph Cache"},
223*d57664e9SAndroid Build Coastguard Worker };
224*d57664e9SAndroid Build Coastguard Worker skiapipeline::SkiaMemoryTracer cpuTracer(cpuResourceMap, false);
225*d57664e9SAndroid Build Coastguard Worker SkGraphics::DumpMemoryStatistics(&cpuTracer);
226*d57664e9SAndroid Build Coastguard Worker if (cpuTracer.hasOutput()) {
227*d57664e9SAndroid Build Coastguard Worker log.appendFormat("CPU Caches:\n");
228*d57664e9SAndroid Build Coastguard Worker cpuTracer.logOutput(log);
229*d57664e9SAndroid Build Coastguard Worker log.appendFormat(" Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
230*d57664e9SAndroid Build Coastguard Worker log.appendFormat("Total CPU memory usage:\n");
231*d57664e9SAndroid Build Coastguard Worker cpuTracer.logTotals(log);
232*d57664e9SAndroid Build Coastguard Worker }
233*d57664e9SAndroid Build Coastguard Worker
234*d57664e9SAndroid Build Coastguard Worker skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
235*d57664e9SAndroid Build Coastguard Worker mGrContext->dumpMemoryStatistics(&gpuTracer);
236*d57664e9SAndroid Build Coastguard Worker if (gpuTracer.hasOutput()) {
237*d57664e9SAndroid Build Coastguard Worker log.appendFormat("GPU Caches:\n");
238*d57664e9SAndroid Build Coastguard Worker gpuTracer.logOutput(log);
239*d57664e9SAndroid Build Coastguard Worker }
240*d57664e9SAndroid Build Coastguard Worker
241*d57664e9SAndroid Build Coastguard Worker if (renderState && renderState->mActiveLayers.size() > 0) {
242*d57664e9SAndroid Build Coastguard Worker log.appendFormat("Layer Info:\n");
243*d57664e9SAndroid Build Coastguard Worker
244*d57664e9SAndroid Build Coastguard Worker const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL
245*d57664e9SAndroid Build Coastguard Worker ? "GlLayer"
246*d57664e9SAndroid Build Coastguard Worker : "VkLayer";
247*d57664e9SAndroid Build Coastguard Worker size_t layerMemoryTotal = 0;
248*d57664e9SAndroid Build Coastguard Worker for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
249*d57664e9SAndroid Build Coastguard Worker it != renderState->mActiveLayers.end(); it++) {
250*d57664e9SAndroid Build Coastguard Worker const Layer* layer = *it;
251*d57664e9SAndroid Build Coastguard Worker log.appendFormat(" %s size %dx%d\n", layerType, layer->getWidth(),
252*d57664e9SAndroid Build Coastguard Worker layer->getHeight());
253*d57664e9SAndroid Build Coastguard Worker layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
254*d57664e9SAndroid Build Coastguard Worker }
255*d57664e9SAndroid Build Coastguard Worker log.appendFormat(" Layers Total %6.2f KB (numLayers = %zu)\n",
256*d57664e9SAndroid Build Coastguard Worker layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
257*d57664e9SAndroid Build Coastguard Worker }
258*d57664e9SAndroid Build Coastguard Worker
259*d57664e9SAndroid Build Coastguard Worker log.appendFormat("Total GPU memory usage:\n");
260*d57664e9SAndroid Build Coastguard Worker gpuTracer.logTotals(log);
261*d57664e9SAndroid Build Coastguard Worker }
262*d57664e9SAndroid Build Coastguard Worker
onFrameCompleted()263*d57664e9SAndroid Build Coastguard Worker void CacheManager::onFrameCompleted() {
264*d57664e9SAndroid Build Coastguard Worker cancelDestroyContext();
265*d57664e9SAndroid Build Coastguard Worker mFrameCompletions.next() = systemTime(CLOCK_MONOTONIC);
266*d57664e9SAndroid Build Coastguard Worker if (ATRACE_ENABLED()) {
267*d57664e9SAndroid Build Coastguard Worker ATRACE_NAME("dumpingMemoryStatistics");
268*d57664e9SAndroid Build Coastguard Worker static skiapipeline::ATraceMemoryDump tracer;
269*d57664e9SAndroid Build Coastguard Worker tracer.startFrame();
270*d57664e9SAndroid Build Coastguard Worker SkGraphics::DumpMemoryStatistics(&tracer);
271*d57664e9SAndroid Build Coastguard Worker if (mGrContext && Properties::debugTraceGpuResourceCategories) {
272*d57664e9SAndroid Build Coastguard Worker mGrContext->dumpMemoryStatistics(&tracer);
273*d57664e9SAndroid Build Coastguard Worker }
274*d57664e9SAndroid Build Coastguard Worker tracer.logTraces(Properties::debugTraceGpuResourceCategories, mGrContext.get());
275*d57664e9SAndroid Build Coastguard Worker }
276*d57664e9SAndroid Build Coastguard Worker }
277*d57664e9SAndroid Build Coastguard Worker
onThreadIdle()278*d57664e9SAndroid Build Coastguard Worker void CacheManager::onThreadIdle() {
279*d57664e9SAndroid Build Coastguard Worker if (!mGrContext || mFrameCompletions.size() == 0) return;
280*d57664e9SAndroid Build Coastguard Worker
281*d57664e9SAndroid Build Coastguard Worker const nsecs_t now = systemTime(CLOCK_MONOTONIC);
282*d57664e9SAndroid Build Coastguard Worker // Rate limiting
283*d57664e9SAndroid Build Coastguard Worker if ((now - mLastDeferredCleanup) > 25_ms) {
284*d57664e9SAndroid Build Coastguard Worker mLastDeferredCleanup = now;
285*d57664e9SAndroid Build Coastguard Worker const nsecs_t frameCompleteNanos = mFrameCompletions[0];
286*d57664e9SAndroid Build Coastguard Worker const nsecs_t frameDiffNanos = now - frameCompleteNanos;
287*d57664e9SAndroid Build Coastguard Worker const nsecs_t cleanupMillis =
288*d57664e9SAndroid Build Coastguard Worker ns2ms(std::clamp(frameDiffNanos, mMemoryPolicy.minimumResourceRetention,
289*d57664e9SAndroid Build Coastguard Worker mMemoryPolicy.maximumResourceRetention));
290*d57664e9SAndroid Build Coastguard Worker mGrContext->performDeferredCleanup(std::chrono::milliseconds(cleanupMillis),
291*d57664e9SAndroid Build Coastguard Worker toSkiaEnum(mMemoryPolicy.purgeScratchOnly));
292*d57664e9SAndroid Build Coastguard Worker }
293*d57664e9SAndroid Build Coastguard Worker }
294*d57664e9SAndroid Build Coastguard Worker
scheduleDestroyContext()295*d57664e9SAndroid Build Coastguard Worker void CacheManager::scheduleDestroyContext() {
296*d57664e9SAndroid Build Coastguard Worker if (mMemoryPolicy.contextTimeout > 0) {
297*d57664e9SAndroid Build Coastguard Worker mRenderThread.queue().postDelayed(mMemoryPolicy.contextTimeout,
298*d57664e9SAndroid Build Coastguard Worker [this, genId = mGenerationId] {
299*d57664e9SAndroid Build Coastguard Worker if (mGenerationId != genId) return;
300*d57664e9SAndroid Build Coastguard Worker // GenID should have already stopped this, but just in
301*d57664e9SAndroid Build Coastguard Worker // case
302*d57664e9SAndroid Build Coastguard Worker if (!areAllContextsStopped()) return;
303*d57664e9SAndroid Build Coastguard Worker mRenderThread.destroyRenderingContext();
304*d57664e9SAndroid Build Coastguard Worker });
305*d57664e9SAndroid Build Coastguard Worker }
306*d57664e9SAndroid Build Coastguard Worker }
307*d57664e9SAndroid Build Coastguard Worker
cancelDestroyContext()308*d57664e9SAndroid Build Coastguard Worker void CacheManager::cancelDestroyContext() {
309*d57664e9SAndroid Build Coastguard Worker if (mIsDestructionPending) {
310*d57664e9SAndroid Build Coastguard Worker mIsDestructionPending = false;
311*d57664e9SAndroid Build Coastguard Worker mGenerationId++;
312*d57664e9SAndroid Build Coastguard Worker }
313*d57664e9SAndroid Build Coastguard Worker }
314*d57664e9SAndroid Build Coastguard Worker
areAllContextsStopped()315*d57664e9SAndroid Build Coastguard Worker bool CacheManager::areAllContextsStopped() {
316*d57664e9SAndroid Build Coastguard Worker for (auto context : mCanvasContexts) {
317*d57664e9SAndroid Build Coastguard Worker if (!context->isStopped()) return false;
318*d57664e9SAndroid Build Coastguard Worker }
319*d57664e9SAndroid Build Coastguard Worker return true;
320*d57664e9SAndroid Build Coastguard Worker }
321*d57664e9SAndroid Build Coastguard Worker
checkUiHidden()322*d57664e9SAndroid Build Coastguard Worker void CacheManager::checkUiHidden() {
323*d57664e9SAndroid Build Coastguard Worker if (!mGrContext) return;
324*d57664e9SAndroid Build Coastguard Worker
325*d57664e9SAndroid Build Coastguard Worker if (mMemoryPolicy.useAlternativeUiHidden && areAllContextsStopped()) {
326*d57664e9SAndroid Build Coastguard Worker trimMemory(TrimLevel::UI_HIDDEN);
327*d57664e9SAndroid Build Coastguard Worker }
328*d57664e9SAndroid Build Coastguard Worker }
329*d57664e9SAndroid Build Coastguard Worker
registerCanvasContext(CanvasContext * context)330*d57664e9SAndroid Build Coastguard Worker void CacheManager::registerCanvasContext(CanvasContext* context) {
331*d57664e9SAndroid Build Coastguard Worker mCanvasContexts.push_back(context);
332*d57664e9SAndroid Build Coastguard Worker cancelDestroyContext();
333*d57664e9SAndroid Build Coastguard Worker }
334*d57664e9SAndroid Build Coastguard Worker
unregisterCanvasContext(CanvasContext * context)335*d57664e9SAndroid Build Coastguard Worker void CacheManager::unregisterCanvasContext(CanvasContext* context) {
336*d57664e9SAndroid Build Coastguard Worker std::erase(mCanvasContexts, context);
337*d57664e9SAndroid Build Coastguard Worker checkUiHidden();
338*d57664e9SAndroid Build Coastguard Worker if (mCanvasContexts.empty()) {
339*d57664e9SAndroid Build Coastguard Worker scheduleDestroyContext();
340*d57664e9SAndroid Build Coastguard Worker }
341*d57664e9SAndroid Build Coastguard Worker }
342*d57664e9SAndroid Build Coastguard Worker
onContextStopped(CanvasContext * context)343*d57664e9SAndroid Build Coastguard Worker void CacheManager::onContextStopped(CanvasContext* context) {
344*d57664e9SAndroid Build Coastguard Worker checkUiHidden();
345*d57664e9SAndroid Build Coastguard Worker if (mMemoryPolicy.releaseContextOnStoppedOnly && areAllContextsStopped()) {
346*d57664e9SAndroid Build Coastguard Worker scheduleDestroyContext();
347*d57664e9SAndroid Build Coastguard Worker }
348*d57664e9SAndroid Build Coastguard Worker }
349*d57664e9SAndroid Build Coastguard Worker
notifyNextFrameSize(int width,int height)350*d57664e9SAndroid Build Coastguard Worker void CacheManager::notifyNextFrameSize(int width, int height) {
351*d57664e9SAndroid Build Coastguard Worker int frameArea = width * height;
352*d57664e9SAndroid Build Coastguard Worker if (frameArea > mMaxSurfaceArea) {
353*d57664e9SAndroid Build Coastguard Worker mMaxSurfaceArea = frameArea;
354*d57664e9SAndroid Build Coastguard Worker setupCacheLimits();
355*d57664e9SAndroid Build Coastguard Worker }
356*d57664e9SAndroid Build Coastguard Worker }
357*d57664e9SAndroid Build Coastguard Worker
358*d57664e9SAndroid Build Coastguard Worker } /* namespace renderthread */
359*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
360*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
361