From dbba55de7026c0ffbf1eff057d7bf87c19ec80d1 Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Wed, 28 Jun 2017 13:24:41 -0400 Subject: [PATCH] Cache GrTexture in GrAHardwareBufferImageGenerator Cache last GrTexture needed by onGenerateTexture. Make sure GrTexture is destroyed by the thread that owns its GrContext. This CL avoids frequent eglDestroyImageKHR calls, which can take more than 7ms. Bug: skia: Change-Id: Ic8472e7e4c55c0f559d96e16845054dc54ec8efa Reviewed-on: https://skia-review.googlesource.com/20989 Reviewed-by: Brian Osman Commit-Queue: Stan Iliev --- src/gpu/GrAHardwareBufferImageGenerator.cpp | 84 +++++++++++++-------- src/gpu/GrAHardwareBufferImageGenerator.h | 4 + 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/gpu/GrAHardwareBufferImageGenerator.cpp b/src/gpu/GrAHardwareBufferImageGenerator.cpp index 8f6cb886e9..b05605c4a0 100644 --- a/src/gpu/GrAHardwareBufferImageGenerator.cpp +++ b/src/gpu/GrAHardwareBufferImageGenerator.cpp @@ -17,9 +17,11 @@ #include "GrBackendSurface.h" #include "GrContext.h" #include "GrContextPriv.h" +#include "GrResourceCache.h" #include "GrResourceProvider.h" #include "GrTexture.h" #include "GrTextureProxy.h" +#include "SkMessageBus.h" #include #include @@ -72,11 +74,22 @@ GrAHardwareBufferImageGenerator::GrAHardwareBufferImageGenerator(const SkImageIn GrAHardwareBufferImageGenerator::~GrAHardwareBufferImageGenerator() { AHardwareBuffer_release(fGraphicBuffer); + this->clear(); +} + +void GrAHardwareBufferImageGenerator::clear() { + if (fOriginalTexture) { + // Notify the original cache that it can free the last ref, so it happens on the correct + // thread. + GrGpuResourceFreedMessage msg { fOriginalTexture, fOwningContextID }; + SkMessageBus::Post(msg); + fOriginalTexture = nullptr; + } } void GrAHardwareBufferImageGenerator::deleteImageTexture(void* context) { - BufferCleanupHelper* cleanupHelper = static_cast(context); - delete cleanupHelper; + BufferCleanupHelper* cleanupHelper = static_cast(context); + delete cleanupHelper; } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -86,14 +99,36 @@ void GrAHardwareBufferImageGenerator::deleteImageTexture(void* context) { sk_sp GrAHardwareBufferImageGenerator::onGenerateTexture( GrContext* context, const SkImageInfo& info, const SkIPoint& origin) { - // TODO: return a cached GrTextureProxy if invoked with the same context - // TODO: if we cache GrTextureProxy, then deleteImageTexture may be invoked on the wrong thread + auto proxy = this->makeProxy(context); + if (!proxy) { + return nullptr; + } + if (0 == origin.fX && 0 == origin.fY && + info.width() == getInfo().width() && info.height() == getInfo().height()) { + // If the caller wants the entire texture, we're done + return proxy; + } else { + // Otherwise, make a copy of the requested subset. + return GrSurfaceProxy::Copy(context, proxy.get(), + SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), + info.height()), + SkBudgeted::kYes); + } +} +#endif + +sk_sp GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) { if (!context->getGpu() || kOpenGL_GrBackend != context->contextPriv().getBackend()) { // Check if GrContext is not abandoned and the backend is GL. return nullptr; } + // return a cached GrTexture if invoked with the same context + if (fOriginalTexture && fOwningContextID == context->uniqueID()) { + return GrSurfaceProxy::MakeWrapped(sk_ref_sp(fOriginalTexture)); + } + while (GL_NO_ERROR != glGetError()) {} //clear GL errors EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(fGraphicBuffer); @@ -168,36 +203,23 @@ sk_sp GrAHardwareBufferImageGenerator::onGenerateTexture( return nullptr; } tex->setRelease(deleteImageTexture, new BufferCleanupHelper(image, display)); - sk_sp proxy(GrSurfaceProxy::MakeWrapped(std::move(tex))); - if (0 == origin.fX && 0 == origin.fY && - info.width() == backendTex.width() && info.height() == backendTex.height()) { - // If the caller wants the entire texture, we're done - return proxy; - } else { - // Otherwise, make a copy of the requested subset. - GrSurfaceDesc desc; - desc.fConfig = proxy->config(); - desc.fWidth = info.width(); - desc.fHeight = info.height(); - desc.fOrigin = proxy->origin(); - desc.fIsMipMapped = proxy->isMipMapped(); + // We fail this assert, if the context has changed. This will be fully handled after + // skbug.com/6812 is ready. + SkASSERT(!fOriginalTexture); - sk_sp sContext(context->contextPriv().makeDeferredSurfaceContext( - desc, SkBackingFit::kExact, SkBudgeted::kYes)); - if (!sContext) { - return nullptr; - } - - SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height()); - if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) { - return nullptr; - } - - return sContext->asTextureProxyRef(); - } + this->clear(); + fOriginalTexture = tex.get(); + fOwningContextID = context->uniqueID(); + // Attach our texture to this context's resource cache. This ensures that deletion will happen + // in the correct thread/context. This adds the only ref to the texture that will persist from + // this point. To trigger GrTexture deletion a message is sent by generator dtor or by + // makeProxy when it is invoked with a different context. + //TODO: GrResourceCache should delete GrTexture, when GrContext is deleted. Currently + //TODO: SkMessageBus ignores messages for deleted contexts and GrTexture will leak. + context->getResourceCache()->insertCrossContextGpuResource(fOriginalTexture); + return GrSurfaceProxy::MakeWrapped(std::move(tex)); } -#endif bool GrAHardwareBufferImageGenerator::onIsValid(GrContext* context) const { if (nullptr == context) { diff --git a/src/gpu/GrAHardwareBufferImageGenerator.h b/src/gpu/GrAHardwareBufferImageGenerator.h index e758138507..f23738b9c5 100644 --- a/src/gpu/GrAHardwareBufferImageGenerator.h +++ b/src/gpu/GrAHardwareBufferImageGenerator.h @@ -41,10 +41,14 @@ protected: private: GrAHardwareBufferImageGenerator(const SkImageInfo&, AHardwareBuffer*, SkAlphaType); + sk_sp makeProxy(GrContext* context); + void clear(); static void deleteImageTexture(void* ctx); AHardwareBuffer* fGraphicBuffer; + GrTexture* fOriginalTexture = nullptr; + uint32_t fOwningContextID; typedef SkImageGenerator INHERITED; };