diff options
author | John Reck <jreck@google.com> | 2019-10-04 14:48:27 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2019-10-04 14:49:20 -0700 |
commit | 83161dcd6aa15c7da161b4ae561b06d20edd2510 (patch) | |
tree | d564507b70019ef9b3905fbd3256f7c2d51948cd /libs/hwui/pipeline | |
parent | 781630e4b4d67e0371c133ae64923ede1b989250 (diff) |
Delete VectorDrawableAtlas
Poking around in a few apps it doesn't appear that
the VectorDrawableAtlas is achieving sufficient
utilization to justify its existence. The potential for
draw call merging doesn't seem warranted for the
RAM cost of the atlas.
Bug: 137853925
Test: builds
Change-Id: Id2419bc6dccb6316636d50c568f8fac75a2d563f
Diffstat (limited to 'libs/hwui/pipeline')
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 5 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.cpp | 23 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.h | 13 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp | 283 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/VectorDrawableAtlas.h | 212 |
5 files changed, 0 insertions, 536 deletions
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index d7076d4cf424..158c3493a90c 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -150,12 +150,7 @@ bool SkiaDisplayList::prepareListAndChildren( const SkRect& bounds = vectorDrawable->properties().getBounds(); if (intersects(info.screenSize, totalMatrix, bounds)) { isDirty = true; -#ifdef __ANDROID__ // Layoutlib does not support CanvasContext - static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) - ->getVectorDrawables() - ->push_back(vectorDrawable); vectorDrawable->setPropertyChangeWillBeConsumed(true); -#endif } } } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 3010206cdc5b..87ef7fc9a6e1 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -43,7 +43,6 @@ namespace uirenderer { namespace skiapipeline { SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { - mVectorDrawables.reserve(30); } SkiaPipeline::~SkiaPipeline() { @@ -73,18 +72,11 @@ void SkiaPipeline::unpinImages() { mPinnedImages.clear(); } -void SkiaPipeline::onPrepareTree() { - // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without - // a renderFrame in the middle. - mVectorDrawables.clear(); -} - void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, const LightInfo& lightInfo) { LightingInfo::updateLighting(lightGeometry, lightInfo); ATRACE_NAME("draw layers"); - renderVectorDrawableCache(); renderLayersImpl(*layerUpdateQueue, opaque); layerUpdateQueue->clear(); } @@ -213,19 +205,6 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { } } -void SkiaPipeline::renderVectorDrawableCache() { - if (!mVectorDrawables.empty()) { - sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas(); - auto grContext = mRenderThread.getGrContext(); - atlas->prepareForDraw(grContext); - ATRACE_NAME("Update VectorDrawables"); - for (auto vd : mVectorDrawables) { - vd->updateCache(atlas, grContext); - } - mVectorDrawables.clear(); - } -} - static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) { CommonPool::post([data, filename] { if (0 == access(filename.c_str(), F_OK)) { @@ -380,8 +359,6 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli Properties::skpCaptureEnabled = true; } - renderVectorDrawableCache(); - // draw all layers up front renderLayersImpl(layers, opaque); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 37b559f92f05..215ff36ebb2b 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -41,7 +41,6 @@ public: bool pinImages(std::vector<SkImage*>& mutableImages) override; bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; } void unpinImages() override; - void onPrepareTree() override; void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, const LightInfo& lightInfo) override; @@ -57,8 +56,6 @@ public: const Rect& contentDrawBounds, sk_sp<SkSurface> surface, const SkMatrix& preTransform); - std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; } - static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap); void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque); @@ -93,11 +90,6 @@ private: const std::vector<sp<RenderNode>>& nodes, const Rect& contentDrawBounds, sk_sp<SkSurface> surface, const SkMatrix& preTransform); - /** - * Render mVectorDrawables into offscreen buffers. - */ - void renderVectorDrawableCache(); - // Called every frame. Normally returns early with screen canvas. // But when capture is enabled, returns an nwaycanvas where commands are also recorded. SkCanvas* tryCapture(SkSurface* surface); @@ -113,11 +105,6 @@ private: std::vector<sk_sp<SkImage>> mPinnedImages; - /** - * populated by prepareTree with dirty VDs - */ - std::vector<VectorDrawableRoot*> mVectorDrawables; - // Block of properties used only for debugging to record a SkPicture and save it in a file. // There are three possible ways of recording drawing commands. enum class CaptureMode { diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp deleted file mode 100644 index e783f389feb8..000000000000 --- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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 "VectorDrawableAtlas.h" - -#include <GrRectanizer_pow2.h> -#include <SkCanvas.h> -#include <cmath> -#include "renderthread/RenderProxy.h" -#include "renderthread/RenderThread.h" -#include "utils/TraceUtils.h" - -namespace android { -namespace uirenderer { -namespace skiapipeline { - -VectorDrawableAtlas::VectorDrawableAtlas(size_t surfaceArea, StorageMode storageMode) - : mWidth((int)std::sqrt(surfaceArea)) - , mHeight((int)std::sqrt(surfaceArea)) - , mStorageMode(storageMode) {} - -void VectorDrawableAtlas::prepareForDraw(GrContext* context) { - if (StorageMode::allowSharedSurface == mStorageMode) { - if (!mSurface) { - mSurface = createSurface(mWidth, mHeight, context); - mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight); - mPixelUsedByVDs = 0; - mPixelAllocated = 0; - mConsecutiveFailures = 0; - mFreeRects.clear(); - } else { - if (isFragmented()) { - // Invoke repack outside renderFrame to avoid jank. - renderthread::RenderProxy::repackVectorDrawableAtlas(); - } - } - } -} - -#define MAX_CONSECUTIVE_FAILURES 5 -#define MAX_UNUSED_RATIO 2.0f - -bool VectorDrawableAtlas::isFragmented() { - return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES && - mPixelUsedByVDs * MAX_UNUSED_RATIO < mPixelAllocated; -} - -void VectorDrawableAtlas::repackIfNeeded(GrContext* context) { - // We repackage when atlas failed to allocate space MAX_CONSECUTIVE_FAILURES consecutive - // times and the atlas allocated pixels are at least MAX_UNUSED_RATIO times higher than pixels - // used by atlas VDs. - if (isFragmented() && mSurface) { - repack(context); - } -} - -// compare to CacheEntry objects based on VD area. -bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second) { - return first.VDrect.width() * first.VDrect.height() < - second.VDrect.width() * second.VDrect.height(); -} - -void VectorDrawableAtlas::repack(GrContext* context) { - ATRACE_CALL(); - sk_sp<SkSurface> newSurface; - SkCanvas* canvas = nullptr; - if (StorageMode::allowSharedSurface == mStorageMode) { - newSurface = createSurface(mWidth, mHeight, context); - if (!newSurface) { - return; - } - canvas = newSurface->getCanvas(); - canvas->clear(SK_ColorTRANSPARENT); - mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight); - } else { - if (!mSurface) { - return; // nothing to repack - } - mRectanizer.reset(); - } - mFreeRects.clear(); - SkImage* sourceImageAtlas = nullptr; - if (mSurface) { - sourceImageAtlas = mSurface->makeImageSnapshot().get(); - } - - // Sort the list by VD size, which allows for the smallest VDs to get first in the atlas. - // Sorting is safe, because it does not affect iterator validity. - if (mRects.size() <= 100) { - mRects.sort(compareCacheEntry); - } - - for (CacheEntry& entry : mRects) { - SkRect currentVDRect = entry.VDrect; - SkImage* sourceImage; // copy either from the atlas or from a standalone surface - if (entry.surface) { - if (!fitInAtlas(currentVDRect.width(), currentVDRect.height())) { - continue; // don't even try to repack huge VD - } - sourceImage = entry.surface->makeImageSnapshot().get(); - } else { - sourceImage = sourceImageAtlas; - } - size_t VDRectArea = currentVDRect.width() * currentVDRect.height(); - SkIPoint16 pos; - if (canvas && mRectanizer->addRect(currentVDRect.width(), currentVDRect.height(), &pos)) { - SkRect newRect = - SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(), currentVDRect.height()); - canvas->drawImageRect(sourceImage, currentVDRect, newRect, nullptr); - entry.VDrect = newRect; - entry.rect = newRect; - if (entry.surface) { - // A rectangle moved from a standalone surface to the atlas. - entry.surface = nullptr; - mPixelUsedByVDs += VDRectArea; - } - } else { - // Repack failed for this item. If it is not already, store it in a standalone - // surface. - if (!entry.surface) { - // A rectangle moved from an atlas to a standalone surface. - mPixelUsedByVDs -= VDRectArea; - SkRect newRect = SkRect::MakeWH(currentVDRect.width(), currentVDRect.height()); - entry.surface = createSurface(newRect.width(), newRect.height(), context); - auto tempCanvas = entry.surface->getCanvas(); - tempCanvas->clear(SK_ColorTRANSPARENT); - tempCanvas->drawImageRect(sourceImageAtlas, currentVDRect, newRect, nullptr); - entry.VDrect = newRect; - entry.rect = newRect; - } - } - } - mPixelAllocated = mPixelUsedByVDs; - context->flush(); - mSurface = newSurface; - mConsecutiveFailures = 0; -} - -AtlasEntry VectorDrawableAtlas::requestNewEntry(int width, int height, GrContext* context) { - AtlasEntry result; - if (width <= 0 || height <= 0) { - return result; - } - - if (mSurface) { - const size_t area = width * height; - - // Use a rectanizer to allocate unused space from the atlas surface. - bool notTooBig = fitInAtlas(width, height); - SkIPoint16 pos; - if (notTooBig && mRectanizer->addRect(width, height, &pos)) { - mPixelUsedByVDs += area; - mPixelAllocated += area; - result.rect = SkRect::MakeXYWH(pos.fX, pos.fY, width, height); - result.surface = mSurface; - auto eraseIt = mRects.emplace(mRects.end(), result.rect, result.rect, nullptr); - CacheEntry* entry = &(*eraseIt); - entry->eraseIt = eraseIt; - result.key = reinterpret_cast<AtlasKey>(entry); - mConsecutiveFailures = 0; - return result; - } - - // Try to reuse atlas memory from rectangles freed by "releaseEntry". - auto freeRectIt = mFreeRects.lower_bound(area); - while (freeRectIt != mFreeRects.end()) { - SkRect& freeRect = freeRectIt->second; - if (freeRect.width() >= width && freeRect.height() >= height) { - result.rect = SkRect::MakeXYWH(freeRect.fLeft, freeRect.fTop, width, height); - result.surface = mSurface; - auto eraseIt = mRects.emplace(mRects.end(), result.rect, freeRect, nullptr); - CacheEntry* entry = &(*eraseIt); - entry->eraseIt = eraseIt; - result.key = reinterpret_cast<AtlasKey>(entry); - mPixelUsedByVDs += area; - mFreeRects.erase(freeRectIt); - mConsecutiveFailures = 0; - return result; - } - freeRectIt++; - } - - if (notTooBig && mConsecutiveFailures <= MAX_CONSECUTIVE_FAILURES) { - mConsecutiveFailures++; - } - } - - // Allocate a surface for a rectangle that is too big or if atlas is full. - if (nullptr != context) { - result.rect = SkRect::MakeWH(width, height); - result.surface = createSurface(width, height, context); - auto eraseIt = mRects.emplace(mRects.end(), result.rect, result.rect, result.surface); - CacheEntry* entry = &(*eraseIt); - entry->eraseIt = eraseIt; - result.key = reinterpret_cast<AtlasKey>(entry); - } - - return result; -} - -AtlasEntry VectorDrawableAtlas::getEntry(AtlasKey atlasKey) { - AtlasEntry result; - if (INVALID_ATLAS_KEY != atlasKey) { - CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey); - result.rect = entry->VDrect; - result.surface = entry->surface; - if (!result.surface) { - result.surface = mSurface; - } - result.key = atlasKey; - } - return result; -} - -void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) { - if (INVALID_ATLAS_KEY != atlasKey) { - if (!renderthread::RenderThread::isCurrent()) { - { - AutoMutex _lock(mReleaseKeyLock); - mKeysForRelease.push_back(atlasKey); - } - // invoke releaseEntry on the renderthread - renderthread::RenderProxy::releaseVDAtlasEntries(); - return; - } - CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey); - if (!entry->surface) { - // Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas - // is full. - SkRect& removedRect = entry->rect; - size_t rectArea = removedRect.width() * removedRect.height(); - mFreeRects.emplace(rectArea, removedRect); - SkRect& removedVDRect = entry->VDrect; - size_t VDRectArea = removedVDRect.width() * removedVDRect.height(); - mPixelUsedByVDs -= VDRectArea; - mConsecutiveFailures = 0; - } - auto eraseIt = entry->eraseIt; - mRects.erase(eraseIt); - } -} - -void VectorDrawableAtlas::delayedReleaseEntries() { - AutoMutex _lock(mReleaseKeyLock); - for (auto key : mKeysForRelease) { - releaseEntry(key); - } - mKeysForRelease.clear(); -} - -sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrContext* context) { - SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType); - // This must have a top-left origin so that calls to surface->canvas->writePixels - // performs a basic texture upload instead of a more complex drawing operation - return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, kTopLeft_GrSurfaceOrigin, - nullptr); -} - -void VectorDrawableAtlas::setStorageMode(StorageMode mode) { - mStorageMode = mode; - if (StorageMode::disallowSharedSurface == mStorageMode && mSurface) { - mSurface.reset(); - mRectanizer.reset(); - mFreeRects.clear(); - } -} - -} /* namespace skiapipeline */ -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h deleted file mode 100644 index 5e892aa7e92c..000000000000 --- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include <SkSurface.h> -#include <utils/FatVector.h> -#include <utils/RefBase.h> -#include <utils/Thread.h> -#include <list> -#include <map> - -class GrRectanizer; - -namespace android { -namespace uirenderer { -namespace skiapipeline { - -typedef uintptr_t AtlasKey; - -#define INVALID_ATLAS_KEY 0 - -struct AtlasEntry { - sk_sp<SkSurface> surface; - SkRect rect; - AtlasKey key = INVALID_ATLAS_KEY; -}; - -/** - * VectorDrawableAtlas provides offscreen buffers used to draw VD and AnimatedVD. - * VectorDrawableAtlas can allocate a standalone surface or provide a subrect from a shared surface. - * VectorDrawableAtlas is owned by the CacheManager and weak pointers are kept by each - * VectorDrawable that is using it. VectorDrawableAtlas and its surface can be deleted at any time, - * except during a renderFrame call. VectorDrawable does not contain a pointer to atlas SkSurface - * nor any coordinates into the atlas, but instead holds a rectangle "id", which is resolved only - * when drawing. This design makes VectorDrawableAtlas free to move the data internally. - * At draw time a VectorDrawable may find, that its atlas has been deleted, which will make it - * draw in a standalone cache surface not part of an atlas. In this case VD won't use - * VectorDrawableAtlas until the next frame. - * VectorDrawableAtlas tries to fit VDs in the atlas SkSurface. If there is not enough space in - * the atlas, VectorDrawableAtlas creates a standalone surface for each VD. - * When a VectorDrawable is deleted, it invokes VectorDrawableAtlas::releaseEntry, which is keeping - * track of free spaces and allow to reuse the surface for another VD. - */ -// TODO: Check if not using atlas for AnimatedVD is more efficient. -// TODO: For low memory situations, when there are no paint effects in VD, we may render without an -// TODO: offscreen surface. -class VectorDrawableAtlas : public virtual RefBase { -public: - enum class StorageMode { allowSharedSurface, disallowSharedSurface }; - - explicit VectorDrawableAtlas(size_t surfaceArea, - StorageMode storageMode = StorageMode::allowSharedSurface); - - /** - * "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the - * atlas at a later time. - */ - void prepareForDraw(GrContext* context); - - /** - * Repack the atlas if needed, by moving used rectangles into a new atlas surface. - * The goal of repacking is to fix a fragmented atlas. - */ - void repackIfNeeded(GrContext* context); - - /** - * Returns true if atlas is fragmented and repack is needed. - */ - bool isFragmented(); - - /** - * "requestNewEntry" is called by VectorDrawable to allocate a new rectangle area from the atlas - * or create a standalone surface if atlas is full. - * On success it returns a non-negative unique id, which can be used later with "getEntry" and - * "releaseEntry". - */ - AtlasEntry requestNewEntry(int width, int height, GrContext* context); - - /** - * "getEntry" extracts coordinates and surface of a previously created rectangle. - * "atlasKey" is an unique id created by "requestNewEntry". Passing a non-existing "atlasKey" is - * causing an undefined behaviour. - * On success it returns a rectangle Id -> may be same or different from "atlasKey" if - * implementation decides to move the record internally. - */ - AtlasEntry getEntry(AtlasKey atlasKey); - - /** - * "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey" - * is causing an undefined behaviour. This is the only function in the class that can be - * invoked from any thread. It will marshal internally to render thread if needed. - */ - void releaseEntry(AtlasKey atlasKey); - - void setStorageMode(StorageMode mode); - - /** - * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is - * invoked from a non render thread. - */ - void delayedReleaseEntries(); - -private: - struct CacheEntry { - CacheEntry(const SkRect& newVDrect, const SkRect& newRect, - const sk_sp<SkSurface>& newSurface) - : VDrect(newVDrect), rect(newRect), surface(newSurface) {} - - /** - * size and position of VectorDrawable into the atlas or in "this.surface" - */ - SkRect VDrect; - - /** - * rect allocated in atlas surface or "this.surface". It may be bigger than "VDrect" - */ - SkRect rect; - - /** - * this surface is used if atlas is full or VD is too big - */ - sk_sp<SkSurface> surface; - - /** - * iterator is used to delete self with a constant complexity (without traversing the list) - */ - std::list<CacheEntry>::iterator eraseIt; - }; - - /** - * atlas surface shared by all VDs - */ - sk_sp<SkSurface> mSurface; - - std::unique_ptr<GrRectanizer> mRectanizer; - const int mWidth; - const int mHeight; - - /** - * "mRects" keeps records only for rectangles used by VDs. List has nice properties: constant - * complexity to insert and erase and references are not invalidated by insert/erase. - */ - std::list<CacheEntry> mRects; - - /** - * Rectangles freed by "releaseEntry" are removed from "mRects" and added to "mFreeRects". - * "mFreeRects" is using for an index the rectangle area. There could be more than one free - * rectangle with the same area, which is the reason to use "multimap" instead of "map". - */ - std::multimap<size_t, SkRect> mFreeRects; - - /** - * area in atlas used by VectorDrawables (area in standalone surface not counted) - */ - int mPixelUsedByVDs = 0; - - /** - * area allocated in mRectanizer - */ - int mPixelAllocated = 0; - - /** - * Consecutive times we had to allocate standalone surfaces, because atlas was full. - */ - int mConsecutiveFailures = 0; - - /** - * mStorageMode allows using a shared surface to store small vector drawables. - * Using a shared surface can boost the performance by allowing GL ops to be batched, but may - * consume more memory. - */ - StorageMode mStorageMode; - - /** - * mKeysForRelease is used by releaseEntry implementation to pass atlas keys from an arbitrary - * calling thread to the render thread. - */ - std::vector<AtlasKey> mKeysForRelease; - - /** - * A lock used to protect access to mKeysForRelease. - */ - Mutex mReleaseKeyLock; - - sk_sp<SkSurface> createSurface(int width, int height, GrContext* context); - - inline bool fitInAtlas(int width, int height) { - return 2 * width < mWidth && 2 * height < mHeight; - } - - void repack(GrContext* context); - - static bool compareCacheEntry(const CacheEntry& first, const CacheEntry& second); -}; - -} /* namespace skiapipeline */ -} /* namespace uirenderer */ -} /* namespace android */ |