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 <brianosman@google.com>
Commit-Queue: Stan Iliev <stani@google.com>
This commit is contained in:
Stan Iliev 2017-06-28 13:24:41 -04:00 committed by Skia Commit-Bot
parent c2d207603e
commit dbba55de70
2 changed files with 57 additions and 31 deletions

View File

@ -17,9 +17,11 @@
#include "GrBackendSurface.h" #include "GrBackendSurface.h"
#include "GrContext.h" #include "GrContext.h"
#include "GrContextPriv.h" #include "GrContextPriv.h"
#include "GrResourceCache.h"
#include "GrResourceProvider.h" #include "GrResourceProvider.h"
#include "GrTexture.h" #include "GrTexture.h"
#include "GrTextureProxy.h" #include "GrTextureProxy.h"
#include "SkMessageBus.h"
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
@ -72,11 +74,22 @@ GrAHardwareBufferImageGenerator::GrAHardwareBufferImageGenerator(const SkImageIn
GrAHardwareBufferImageGenerator::~GrAHardwareBufferImageGenerator() { GrAHardwareBufferImageGenerator::~GrAHardwareBufferImageGenerator() {
AHardwareBuffer_release(fGraphicBuffer); 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<GrGpuResourceFreedMessage>::Post(msg);
fOriginalTexture = nullptr;
}
} }
void GrAHardwareBufferImageGenerator::deleteImageTexture(void* context) { void GrAHardwareBufferImageGenerator::deleteImageTexture(void* context) {
BufferCleanupHelper* cleanupHelper = static_cast<BufferCleanupHelper*>(context); BufferCleanupHelper* cleanupHelper = static_cast<BufferCleanupHelper*>(context);
delete cleanupHelper; delete cleanupHelper;
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
@ -86,14 +99,36 @@ void GrAHardwareBufferImageGenerator::deleteImageTexture(void* context) {
sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture( sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
GrContext* context, const SkImageInfo& info, const SkIPoint& origin) { GrContext* context, const SkImageInfo& info, const SkIPoint& origin) {
// TODO: return a cached GrTextureProxy if invoked with the same context auto proxy = this->makeProxy(context);
// TODO: if we cache GrTextureProxy, then deleteImageTexture may be invoked on the wrong thread 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<GrTextureProxy> GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) {
if (!context->getGpu() || kOpenGL_GrBackend != context->contextPriv().getBackend()) { if (!context->getGpu() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
// Check if GrContext is not abandoned and the backend is GL. // Check if GrContext is not abandoned and the backend is GL.
return nullptr; 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 while (GL_NO_ERROR != glGetError()) {} //clear GL errors
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(fGraphicBuffer); EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(fGraphicBuffer);
@ -168,36 +203,23 @@ sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
return nullptr; return nullptr;
} }
tex->setRelease(deleteImageTexture, new BufferCleanupHelper(image, display)); tex->setRelease(deleteImageTexture, new BufferCleanupHelper(image, display));
sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(tex)));
if (0 == origin.fX && 0 == origin.fY && // We fail this assert, if the context has changed. This will be fully handled after
info.width() == backendTex.width() && info.height() == backendTex.height()) { // skbug.com/6812 is ready.
// If the caller wants the entire texture, we're done SkASSERT(!fOriginalTexture);
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();
sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeDeferredSurfaceContext( this->clear();
desc, SkBackingFit::kExact, SkBudgeted::kYes)); fOriginalTexture = tex.get();
if (!sContext) { fOwningContextID = context->uniqueID();
return nullptr; // 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
SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height()); // makeProxy when it is invoked with a different context.
if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) { //TODO: GrResourceCache should delete GrTexture, when GrContext is deleted. Currently
return nullptr; //TODO: SkMessageBus ignores messages for deleted contexts and GrTexture will leak.
} context->getResourceCache()->insertCrossContextGpuResource(fOriginalTexture);
return GrSurfaceProxy::MakeWrapped(std::move(tex));
return sContext->asTextureProxyRef();
}
} }
#endif
bool GrAHardwareBufferImageGenerator::onIsValid(GrContext* context) const { bool GrAHardwareBufferImageGenerator::onIsValid(GrContext* context) const {
if (nullptr == context) { if (nullptr == context) {

View File

@ -41,10 +41,14 @@ protected:
private: private:
GrAHardwareBufferImageGenerator(const SkImageInfo&, AHardwareBuffer*, SkAlphaType); GrAHardwareBufferImageGenerator(const SkImageInfo&, AHardwareBuffer*, SkAlphaType);
sk_sp<GrTextureProxy> makeProxy(GrContext* context);
void clear();
static void deleteImageTexture(void* ctx); static void deleteImageTexture(void* ctx);
AHardwareBuffer* fGraphicBuffer; AHardwareBuffer* fGraphicBuffer;
GrTexture* fOriginalTexture = nullptr;
uint32_t fOwningContextID;
typedef SkImageGenerator INHERITED; typedef SkImageGenerator INHERITED;
}; };