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

Commit ee248599 authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

Refactor DisplayList path caching.

This removes dependence on SkPath ptrs that HWUI does not control
the lifecycle of. This clears up some errors where the paths are
not generated from Java, but rather the Skia test suites.

Cherry-pick of a change that originally landed in master-skia and is
dependent on a skia merge (ag/655422).

Change-Id: I41b9797a2b0af5d6b4ea51891565469d4f1d832d
parent 247dc6e1
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
#include "SkPath.h"
#include "SkPathOps.h"

#include <ResourceCache.h>
#include <Caches.h>
#include <vector>
#include <map>

@@ -38,11 +38,11 @@ public:

    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
        if (android::uirenderer::ResourceCache::hasInstance()) {
            android::uirenderer::ResourceCache::getInstance().destructor(obj);
        } else {
            delete obj;
        // Purge entries from the HWUI path cache if this path's data is unique
        if (obj->unique() && android::uirenderer::Caches::hasInstance()) {
            android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj);
        }
        delete obj;
    }

    static jlong init1(JNIEnv* env, jobject clazz) {
+9 −6
Original line number Diff line number Diff line
@@ -49,18 +49,21 @@ void DisplayListData::cleanupResources() {
        resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
    }

    for (size_t i = 0; i < sourcePaths.size(); i++) {
        resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
    }

    resourceCache.unlock();

    for (size_t i = 0; i < pathResources.size(); i++) {
        const SkPath* path = pathResources.itemAt(i);
        if (path->unique() && Caches::hasInstance()) {
            Caches::getInstance().pathCache.removeDeferred(path);
        }
        delete path;
    }

    bitmapResources.clear();
    patchResources.clear();
    sourcePaths.clear();
    pathResources.clear();
    paints.clear();
    regions.clear();
    paths.clear();
}

size_t DisplayListData::addChild(DrawRenderNodeOp* op) {
+1 −2
Original line number Diff line number Diff line
@@ -134,12 +134,11 @@ public:
    int projectionReceiveIndex;

    Vector<const SkBitmap*> bitmapResources;
    Vector<const SkPath*> pathResources;
    Vector<const Res_png_9patch*> patchResources;

    std::vector<std::unique_ptr<const SkPaint>> paints;
    std::vector<std::unique_ptr<const SkRegion>> regions;
    std::vector<std::unique_ptr<const SkPath>> paths;
    SortedVector<const SkPath*> sourcePaths;
    Vector<Functor*> functors;

    const Vector<Chunk>& getChunks() const {
+4 −15
Original line number Diff line number Diff line
@@ -282,21 +282,10 @@ private:
    inline const SkPath* refPath(const SkPath* path) {
        if (!path) return nullptr;

        const SkPath* cachedPath = mPathMap.valueFor(path);
        if (cachedPath == nullptr || cachedPath->getGenerationID() != path->getGenerationID()) {
            SkPath* newPathCopy = new SkPath(*path);
            newPathCopy->setSourcePath(path);
            cachedPath = newPathCopy;
            std::unique_ptr<const SkPath> copy(newPathCopy);
            mDisplayListData->paths.push_back(std::move(copy));

            // replaceValueFor() performs an add if the entry doesn't exist
            mPathMap.replaceValueFor(path, cachedPath);
        }
        if (mDisplayListData->sourcePaths.indexOf(path) < 0) {
            mResourceCache.incrementRefcount(path);
            mDisplayListData->sourcePaths.add(path);
        }
        // The points/verbs within the path are refcounted so this copy operation
        // is inexpensive and maintains the generationID of the original path.
        const SkPath* cachedPath = new SkPath(*path);
        mDisplayListData->pathResources.add(cachedPath);
        return cachedPath;
    }

+13 −48
Original line number Diff line number Diff line
@@ -362,22 +362,9 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
// Paths
///////////////////////////////////////////////////////////////////////////////

void PathCache::remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair) {
    LruCache<PathDescription, PathTexture*>::Iterator i(mCache);

    while (i.next()) {
        const PathDescription& key = i.key();
        if (key.type == kShapePath &&
                (key.shape.path.mPath == pair.getFirst() ||
                        key.shape.path.mPath == pair.getSecond())) {
            pathsToRemove.push(key);
        }
    }
}

void PathCache::removeDeferred(SkPath* path) {
void PathCache::removeDeferred(const SkPath* path) {
    Mutex::Autolock l(mLock);
    mGarbage.push(path_pair_t(path, const_cast<SkPath*>(path->getSourcePath())));
    mGarbage.push(path->getGenerationID());
}

void PathCache::clearGarbage() {
@@ -387,9 +374,15 @@ void PathCache::clearGarbage() {
        Mutex::Autolock l(mLock);
        size_t count = mGarbage.size();
        for (size_t i = 0; i < count; i++) {
            const path_pair_t& pair = mGarbage.itemAt(i);
            remove(pathsToRemove, pair);
            delete pair.getFirst();
            const uint32_t generationID = mGarbage.itemAt(i);

            LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
            while (iter.next()) {
                const PathDescription& key = iter.key();
                if (key.type == kShapePath && key.shape.path.mGenerationID == generationID) {
                    pathsToRemove.push(key);
                }
            }
        }
        mGarbage.clear();
    }
@@ -399,27 +392,9 @@ void PathCache::clearGarbage() {
    }
}

/**
 * To properly handle path mutations at draw time we always make a copy
 * of paths objects when recording display lists. The source path points
 * to the path we originally copied the path from. This ensures we use
 * the original path as a cache key the first time a path is inserted
 * in the cache. The source path is also used to reclaim garbage when a
 * Dalvik Path object is collected.
 */
static const SkPath* getSourcePath(const SkPath* path) {
    const SkPath* sourcePath = path->getSourcePath();
    if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) {
        return const_cast<SkPath*>(sourcePath);
    }
    return path;
}

PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
    path = getSourcePath(path);

    PathDescription entry(kShapePath, paint);
    entry.shape.path.mPath = path;
    entry.shape.path.mGenerationID = path->getGenerationID();

    PathTexture* texture = mCache.get(entry);

@@ -442,11 +417,6 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
                texture = nullptr;
                mCache.remove(entry);
            }
        } else if (path->getGenerationID() != texture->generation) {
            // The size of the path might have changed so we first
            // remove the entry from the cache
            mCache.remove(entry);
            texture = addTexture(entry, path, paint);
        }
    }

@@ -458,19 +428,14 @@ void PathCache::precache(const SkPath* path, const SkPaint* paint) {
        return;
    }

    path = getSourcePath(path);

    PathDescription entry(kShapePath, paint);
    entry.shape.path.mPath = path;
    entry.shape.path.mGenerationID = path->getGenerationID();

    PathTexture* texture = mCache.get(entry);

    bool generate = false;
    if (!texture) {
        generate = true;
    } else if (path->getGenerationID() != texture->generation) {
        mCache.remove(entry);
        generate = true;
    }

    if (generate) {
Loading