Home | History | Annotate | Download | only in renderthread
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "CacheManager.h"
     18 
     19 #include "Layer.h"
     20 #include "Properties.h"
     21 #include "RenderThread.h"
     22 #include "pipeline/skia/ShaderCache.h"
     23 #include "pipeline/skia/SkiaMemoryTracer.h"
     24 #include "renderstate/RenderState.h"
     25 #include "thread/CommonPool.h"
     26 
     27 #include <GrContextOptions.h>
     28 #include <SkExecutor.h>
     29 #include <SkGraphics.h>
     30 #include <SkMathPriv.h>
     31 #include <gui/Surface.h>
     32 #include <math.h>
     33 #include <set>
     34 
     35 namespace android {
     36 namespace uirenderer {
     37 namespace renderthread {
     38 
     39 // This multiplier was selected based on historical review of cache sizes relative
     40 // to the screen resolution. This is meant to be a conservative default based on
     41 // that analysis. The 4.0f is used because the default pixel format is assumed to
     42 // be ARGB_8888.
     43 #define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f)
     44 #define BACKGROUND_RETENTION_PERCENTAGE (0.5f)
     45 
     46 CacheManager::CacheManager(const DisplayInfo& display)
     47         : mMaxSurfaceArea(display.w * display.h)
     48         , mMaxResourceBytes(mMaxSurfaceArea * SURFACE_SIZE_MULTIPLIER)
     49         , mBackgroundResourceBytes(mMaxResourceBytes * BACKGROUND_RETENTION_PERCENTAGE)
     50         // This sets the maximum size for a single texture atlas in the GPU font cache. If
     51         // necessary, the cache can allocate additional textures that are counted against the
     52         // total cache limits provided to Skia.
     53         , mMaxGpuFontAtlasBytes(GrNextSizePow2(mMaxSurfaceArea))
     54         // This sets the maximum size of the CPU font cache to be at least the same size as the
     55         // total number of GPU font caches (i.e. 4 separate GPU atlases).
     56         , mMaxCpuFontCacheBytes(std::max(mMaxGpuFontAtlasBytes*4, SkGraphics::GetFontCacheLimit()))
     57         , mBackgroundCpuFontCacheBytes(mMaxCpuFontCacheBytes * BACKGROUND_RETENTION_PERCENTAGE) {
     58 
     59     SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
     60 
     61     mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
     62             mMaxSurfaceArea / 2,
     63             skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
     64 }
     65 
     66 void CacheManager::reset(sk_sp<GrContext> context) {
     67     if (context != mGrContext) {
     68         destroy();
     69     }
     70 
     71     if (context) {
     72         mGrContext = std::move(context);
     73         mGrContext->getResourceCacheLimits(&mMaxResources, nullptr);
     74         mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
     75     }
     76 }
     77 
     78 void CacheManager::destroy() {
     79     // cleanup any caches here as the GrContext is about to go away...
     80     mGrContext.reset(nullptr);
     81     mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
     82             mMaxSurfaceArea / 2,
     83             skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
     84 }
     85 
     86 class CommonPoolExecutor : public SkExecutor {
     87 public:
     88     virtual void add(std::function<void(void)> func) override { CommonPool::post(std::move(func)); }
     89 };
     90 
     91 static CommonPoolExecutor sDefaultExecutor;
     92 
     93 void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity,
     94                                     ssize_t size) {
     95     contextOptions->fAllowPathMaskCaching = true;
     96     contextOptions->fGlyphCacheTextureMaximumBytes = mMaxGpuFontAtlasBytes;
     97     contextOptions->fExecutor = &sDefaultExecutor;
     98 
     99     auto& cache = skiapipeline::ShaderCache::get();
    100     cache.initShaderDiskCache(identity, size);
    101     contextOptions->fPersistentCache = &cache;
    102     contextOptions->fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
    103 }
    104 
    105 void CacheManager::trimMemory(TrimMemoryMode mode) {
    106     if (!mGrContext) {
    107         return;
    108     }
    109 
    110     mGrContext->flush();
    111 
    112     switch (mode) {
    113         case TrimMemoryMode::Complete:
    114             mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea / 2);
    115             mGrContext->freeGpuResources();
    116             SkGraphics::PurgeAllCaches();
    117             break;
    118         case TrimMemoryMode::UiHidden:
    119             // Here we purge all the unlocked scratch resources and then toggle the resources cache
    120             // limits between the background and max amounts. This causes the unlocked resources
    121             // that have persistent data to be purged in LRU order.
    122             mGrContext->purgeUnlockedResources(true);
    123             mGrContext->setResourceCacheLimits(mMaxResources, mBackgroundResourceBytes);
    124             mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
    125             SkGraphics::SetFontCacheLimit(mBackgroundCpuFontCacheBytes);
    126             SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
    127             break;
    128     }
    129 
    130     // We must sync the cpu to make sure deletions of resources still queued up on the GPU actually
    131     // happen.
    132     mGrContext->flush(kSyncCpu_GrFlushFlag, 0, nullptr);
    133 }
    134 
    135 void CacheManager::trimStaleResources() {
    136     if (!mGrContext) {
    137         return;
    138     }
    139     mGrContext->flush();
    140     mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
    141 }
    142 
    143 sp<skiapipeline::VectorDrawableAtlas> CacheManager::acquireVectorDrawableAtlas() {
    144     LOG_ALWAYS_FATAL_IF(mVectorDrawableAtlas.get() == nullptr);
    145     LOG_ALWAYS_FATAL_IF(mGrContext == nullptr);
    146 
    147     /**
    148      * TODO: define memory conditions where we clear the cache (e.g. surface->reset())
    149      */
    150     return mVectorDrawableAtlas;
    151 }
    152 
    153 void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) {
    154     if (!mGrContext) {
    155         log.appendFormat("No valid cache instance.\n");
    156         return;
    157     }
    158 
    159     log.appendFormat("Font Cache (CPU):\n");
    160     log.appendFormat("  Size: %.2f kB \n", SkGraphics::GetFontCacheUsed() / 1024.0f);
    161     log.appendFormat("  Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
    162 
    163     log.appendFormat("CPU Caches:\n");
    164     std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
    165             {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
    166             {"skia/sk_resource_cache/rrect-blur_", "Masks"},
    167             {"skia/sk_resource_cache/rects-blur_", "Masks"},
    168             {"skia/sk_resource_cache/tessellated", "Shadows"},
    169     };
    170     skiapipeline::SkiaMemoryTracer cpuTracer(cpuResourceMap, false);
    171     SkGraphics::DumpMemoryStatistics(&cpuTracer);
    172     cpuTracer.logOutput(log);
    173 
    174     log.appendFormat("GPU Caches:\n");
    175     skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
    176     mGrContext->dumpMemoryStatistics(&gpuTracer);
    177     gpuTracer.logOutput(log);
    178 
    179     log.appendFormat("Other Caches:\n");
    180     log.appendFormat("                         Current / Maximum\n");
    181     log.appendFormat("  VectorDrawableAtlas  %6.2f kB / %6.2f KB (entries = %zu)\n", 0.0f, 0.0f,
    182                      (size_t)0);
    183 
    184     if (renderState) {
    185         if (renderState->mActiveLayers.size() > 0) {
    186             log.appendFormat("  Layer Info:\n");
    187         }
    188 
    189         const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL
    190                                         ? "GlLayer"
    191                                         : "VkLayer";
    192         size_t layerMemoryTotal = 0;
    193         for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
    194              it != renderState->mActiveLayers.end(); it++) {
    195             const Layer* layer = *it;
    196             log.appendFormat("    %s size %dx%d\n", layerType, layer->getWidth(),
    197                              layer->getHeight());
    198             layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
    199         }
    200         log.appendFormat("  Layers Total         %6.2f KB (numLayers = %zu)\n",
    201                          layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
    202     }
    203 
    204     log.appendFormat("Total GPU memory usage:\n");
    205     gpuTracer.logTotals(log);
    206 }
    207 
    208 } /* namespace renderthread */
    209 } /* namespace uirenderer */
    210 } /* namespace android */
    211