Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12741cec authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implement CacheManager for the Skia pipelines."

parents ae645595 f9e45d1d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -141,6 +141,7 @@ cc_defaults {
        "renderstate/Scissor.cpp",
        "renderstate/Stencil.cpp",
        "renderstate/TextureState.cpp",
        "renderthread/CacheManager.cpp",
        "renderthread/CanvasContext.cpp",
        "renderthread/OpenGLPipeline.cpp",
        "renderthread/DrawFrameTask.cpp",
@@ -300,6 +301,7 @@ cc_test {
        "tests/unit/BakedOpRendererTests.cpp",
        "tests/unit/BakedOpStateTests.cpp",
        "tests/unit/BitmapTests.cpp",
        "tests/unit/CacheManagerTests.cpp",
        "tests/unit/CanvasContextTests.cpp",
        "tests/unit/CanvasStateTests.cpp",
        "tests/unit/ClipAreaTests.cpp",
+1 −2
Original line number Diff line number Diff line
@@ -50,8 +50,7 @@ TaskManager* SkiaPipeline::getTaskManager() {
}

void SkiaPipeline::onDestroyHardwareResources() {
    // No need to flush the caches here. There is a timer
    // which will flush temporary resources over time.
    mRenderThread.cacheManager().trimStaleResources();
}

bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ class Layer;
class DeferredLayerUpdater;

namespace renderthread {
class CacheManager;
class CanvasContext;
class RenderThread;
}
@@ -55,6 +56,7 @@ class RenderState {
    PREVENT_COPY_AND_ASSIGN(RenderState);
    friend class renderthread::RenderThread;
    friend class Caches;
    friend class renderthread::CacheManager;
public:
    void onGLContextCreated();
    void onGLContextDestroyed();
+187 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CacheManager.h"

#include "Layer.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"

#include <gui/Surface.h>
#include <GrContextOptions.h>
#include <math.h>
#include <set>

namespace android {
namespace uirenderer {
namespace renderthread {

// This multiplier was selected based on historical review of cache sizes relative
// to the screen resolution. This is meant to be a conservative default based on
// that analysis. The 4.0f is used because the default pixel format is assumed to
// be ARGB_8888.
#define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f)
#define BACKGROUND_RETENTION_PERCENTAGE (0.5f)

// for super large fonts we will draw them as paths so no need to keep linearly
// increasing the font cache size.
#define FONT_CACHE_MIN_MB (0.5f)
#define FONT_CACHE_MAX_MB (4.0f)

CacheManager::CacheManager(const DisplayInfo& display)
        : mMaxSurfaceArea(display.w * display.h) {
    mVectorDrawableAtlas.reset(new VectorDrawableAtlas);
}

void CacheManager::reset(GrContext* context) {
    if (context != mGrContext.get()) {
        destroy();
    }

    if (context) {
        mGrContext = sk_ref_sp(context);
        mGrContext->getResourceCacheLimits(&mMaxResources, nullptr);
        updateContextCacheSizes();
    }
}

void CacheManager::destroy() {
    // cleanup any caches here as the GrContext is about to go away...
    mGrContext.reset(nullptr);
    mVectorDrawableAtlas.reset(new VectorDrawableAtlas);
}

void CacheManager::updateContextCacheSizes() {
    mMaxResourceBytes = mMaxSurfaceArea * SURFACE_SIZE_MULTIPLIER;
    mBackgroundResourceBytes = mMaxResourceBytes * BACKGROUND_RETENTION_PERCENTAGE;

    mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
}

void CacheManager::configureContext(GrContextOptions* contextOptions) {
    contextOptions->fAllowPathMaskCaching = true;

    float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f;
    float fontCacheMB = 0;
    float decimalVal = std::modf(screenMP, &fontCacheMB);

    // This is a basic heuristic to size the cache to a multiple of 512 KB
    if (decimalVal > 0.8f) {
        fontCacheMB += 1.0f;
    } else if (decimalVal > 0.5f) {
        fontCacheMB += 0.5f;
    }

    // set limits on min/max size of the cache
    fontCacheMB = std::max(FONT_CACHE_MIN_MB, std::min(FONT_CACHE_MAX_MB, fontCacheMB));

    // We must currently set the size of the text cache based on the size of the
    // display even though we like to  be dynamicallysizing it to the size of the window.
    // Skia's implementation doesn't provide a mechanism to resize the font cache due to
    // the potential cost of recreating the glyphs.
    contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024;
}

void CacheManager::trimMemory(TrimMemoryMode mode) {
    if (!mGrContext) {
        return;
    }

    mGrContext->flush();

    switch (mode) {
        case TrimMemoryMode::Complete:
            mVectorDrawableAtlas.reset(new VectorDrawableAtlas);
            mGrContext->freeGpuResources();
            break;
        case TrimMemoryMode::UiHidden:
            mGrContext->purgeUnlockedResources(mMaxResourceBytes - mBackgroundResourceBytes, true);
            break;
    }
}

void CacheManager::trimStaleResources() {
    if (!mGrContext) {
        return;
    }
    mGrContext->flush();
    mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
}

VectorDrawableAtlas* CacheManager::acquireVectorDrawableAtlas() {
    LOG_ALWAYS_FATAL_IF(mVectorDrawableAtlas.get() == nullptr);
    LOG_ALWAYS_FATAL_IF(mGrContext == nullptr);

    /**
     * TODO LIST:
     *    1) compute the atlas based on the surfaceArea surface
     *    2) identify a way to reuse cache entries
     *    3) add ability to repack the cache?
     *    4) define memory conditions where we clear the cache (e.g. surface->reset())
     */

    return mVectorDrawableAtlas.release();
}
void CacheManager::releaseVectorDrawableAtlas(VectorDrawableAtlas* atlas) {
    LOG_ALWAYS_FATAL_IF(mVectorDrawableAtlas.get() != nullptr);
    mVectorDrawableAtlas.reset(atlas);
    mVectorDrawableAtlas->isNewAtlas = false;
}

void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) {
    if (!mGrContext) {
        log.appendFormat("No valid cache instance.\n");
        return;
    }

    size_t bytesCached;
    mGrContext->getResourceCacheUsage(nullptr, &bytesCached);

    log.appendFormat("Caches:\n");
    log.appendFormat("                         Current / Maximum\n");
    log.appendFormat("  VectorDrawableAtlas  %6.2f kB / %6.2f kB (entries = %zu)\n",
            0.0f, 0.0f, (size_t)0);

    if (renderState) {
        if (renderState->mActiveLayers.size() > 0) {
            log.appendFormat("  Layer Info:\n");
        }

        size_t layerMemoryTotal = 0;
        for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
                it != renderState->mActiveLayers.end(); it++) {
            const Layer* layer = *it;
            const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer";
            log.appendFormat("    %s size %dx%d\n", layerType,
                    layer->getWidth(), layer->getHeight());
            layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
        }
        log.appendFormat("  Layers Total         %6.2f kB (numLayers = %zu)\n",
                         layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
    }


    log.appendFormat("Total memory usage:\n");
    log.appendFormat("  %zu bytes, %.2f MB (%.2f MB is purgeable)\n",
                     bytesCached, bytesCached / 1024.0f / 1024.0f,
                     mGrContext->getResourceCachePurgeableBytes() / 1024.0f / 1024.0f);


}

} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef CACHEMANAGER_H
#define CACHEMANAGER_H

#include <GrContext.h>
#include <SkSurface.h>
#include <ui/DisplayInfo.h>
#include <utils/String8.h>
#include <vector>

namespace android {

class Surface;

namespace uirenderer {

class RenderState;

namespace renderthread {

class IRenderPipeline;
class RenderThread;

struct VectorDrawableAtlas {
    sk_sp<SkSurface> surface;
    bool isNewAtlas = true;
};

class CacheManager {
public:
    enum class TrimMemoryMode {
        Complete,
        UiHidden
    };

    void configureContext(GrContextOptions* context);
    void trimMemory(TrimMemoryMode mode);
    void trimStaleResources();
    void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);

    VectorDrawableAtlas* acquireVectorDrawableAtlas();
    void releaseVectorDrawableAtlas(VectorDrawableAtlas*);

    size_t getCacheSize() const { return mMaxResourceBytes; }
    size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }

private:
    friend class RenderThread;

    CacheManager(const DisplayInfo& display);


    void reset(GrContext* grContext);
    void destroy();
    void updateContextCacheSizes();

    const size_t mMaxSurfaceArea;
    sk_sp<GrContext> mGrContext;

    int mMaxResources = 0;
    size_t mMaxResourceBytes = 0;
    size_t mBackgroundResourceBytes = 0;

    struct PipelineProps {
        const void* pipelineKey = nullptr;
        size_t surfaceArea = 0;
    };

    std::unique_ptr<VectorDrawableAtlas> mVectorDrawableAtlas;
};

} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */

#endif /* CACHEMANAGER_H */
Loading