Release VectorDrawable cache surface on render thread

Release VectorDrawable cache surface on render thread.
This is fixing an assert in skia GrSingleOwner.h:33.

Test: Ran gmail before and after the change.
Bug: 64842607
Change-Id: I46e0c2557ac5b2fc3be2cc2d35abf96f6d6c9399
This commit is contained in:
Stan Iliev
2017-08-23 12:41:41 -04:00
parent b18835d453
commit 6b894d7746
6 changed files with 64 additions and 1 deletions

View File

@@ -21,6 +21,7 @@
#include <cmath>
#include "utils/TraceUtils.h"
#include "renderthread/RenderProxy.h"
#include "renderthread/RenderThread.h"
namespace android {
namespace uirenderer {
@@ -228,6 +229,15 @@ AtlasEntry VectorDrawableAtlas::getEntry(AtlasKey atlasKey) {
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
@@ -245,6 +255,14 @@ void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) {
}
}
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) {
#ifndef ANDROID_ENABLE_LINEAR_BLENDING
sk_sp<SkColorSpace> colorSpace = nullptr;

View File

@@ -20,6 +20,7 @@
#include <SkSurface.h>
#include <utils/FatVector.h>
#include <utils/RefBase.h>
#include <utils/Thread.h>
#include <list>
class GrRectanizer;
@@ -103,12 +104,19 @@ public:
/**
* "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey"
* is causing an undefined behaviour.
* 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,
@@ -182,6 +190,17 @@ private:
*/
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) {

View File

@@ -732,6 +732,18 @@ void RenderProxy::repackVectorDrawableAtlas() {
thread.queue(task);
}
CREATE_BRIDGE1(releaseVDAtlasEntries, RenderThread* thread) {
args->thread->cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries();
return nullptr;
}
void RenderProxy::releaseVDAtlasEntries() {
RenderThread& thread = RenderThread::getInstance();
SETUP_TASK(releaseVDAtlasEntries);
args->thread = &thread;
thread.queue(task);
}
void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
void* retval;
task->setReturnPtr(&retval);

View File

@@ -143,6 +143,8 @@ public:
static void repackVectorDrawableAtlas();
static void releaseVDAtlasEntries();
private:
RenderThread& mRenderThread;
CanvasContext* mContext;

View File

@@ -499,6 +499,10 @@ sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
return nullptr;
}
bool RenderThread::isCurrent() {
return gettid() == getInstance().getTid();
}
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */

View File

@@ -111,6 +111,14 @@ public:
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
void dumpGraphicsMemory(int fd);
/**
* isCurrent provides a way to query, if the caller is running on
* the render thread.
*
* @return true only if isCurrent is invoked from the render thread.
*/
static bool isCurrent();
protected:
virtual bool threadLoop() override;