Have GrAHardwareBufferImageGenerator use lazy proxies.
Bug: skia: Change-Id: I0c98157ec36f056c3c1b217f3b6561e371b4f057 Reviewed-on: https://skia-review.googlesource.com/148987 Reviewed-by: Brian Osman <brianosman@google.com> Reviewed-by: Stan Iliev <stani@google.com> Commit-Queue: Stan Iliev <stani@google.com>
This commit is contained in:
parent
21fc5ce7f8
commit
f125111ca7
@ -23,6 +23,8 @@
|
||||
#include "GrTexture.h"
|
||||
#include "GrTextureProxy.h"
|
||||
#include "SkMessageBus.h"
|
||||
#include "gl/GrGLDefines.h"
|
||||
#include "gl/GrGLTypes.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
@ -54,33 +56,39 @@ std::unique_ptr<SkImageGenerator> GrAHardwareBufferImageGenerator::Make(
|
||||
}
|
||||
|
||||
GrAHardwareBufferImageGenerator::GrAHardwareBufferImageGenerator(const SkImageInfo& info,
|
||||
AHardwareBuffer* graphicBuffer, SkAlphaType alphaType)
|
||||
AHardwareBuffer* hardwareBuffer, SkAlphaType alphaType)
|
||||
: INHERITED(info)
|
||||
, fGraphicBuffer(graphicBuffer) {
|
||||
AHardwareBuffer_acquire(fGraphicBuffer);
|
||||
, fHardwareBuffer(hardwareBuffer) {
|
||||
AHardwareBuffer_acquire(fHardwareBuffer);
|
||||
}
|
||||
|
||||
void GrAHardwareBufferImageGenerator::releaseTextureRef() {
|
||||
// We must release our ref on the proxy before we send the free message to the actual texture so
|
||||
// that we make sure the last ref (if it is owned by this class) is released on the owning
|
||||
// context.
|
||||
fCachedProxy.reset();
|
||||
if (fOwnedTexture) {
|
||||
SkASSERT(fOwningContextID != SK_InvalidGenID);
|
||||
// Notify the original cache that it can free the last ref, so it happens on the correct
|
||||
// thread.
|
||||
GrGpuResourceFreedMessage msg { fOwnedTexture, fOwningContextID };
|
||||
SkMessageBus<GrGpuResourceFreedMessage>::Post(msg);
|
||||
fOwnedTexture = nullptr;
|
||||
fOwningContextID = SK_InvalidGenID;
|
||||
}
|
||||
}
|
||||
|
||||
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<GrGpuResourceFreedMessage>::Post(msg);
|
||||
fOriginalTexture = nullptr;
|
||||
}
|
||||
this->releaseTextureRef();
|
||||
AHardwareBuffer_release(fHardwareBuffer);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
|
||||
GrContext* context, const SkImageInfo& info, const SkIPoint& origin, bool willNeedMipMaps) {
|
||||
auto proxy = this->makeProxy(context);
|
||||
if (!proxy) {
|
||||
this->makeProxy(context);
|
||||
if (!fCachedProxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -88,9 +96,9 @@ sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
|
||||
if (0 == origin.fX && 0 == origin.fY &&
|
||||
info.width() == this->getInfo().width() && info.height() == this->getInfo().height()) {
|
||||
makingASubset = false;
|
||||
if (!willNeedMipMaps || GrMipMapped::kYes == proxy->mipMapped()) {
|
||||
if (!willNeedMipMaps || GrMipMapped::kYes == fCachedProxy->mipMapped()) {
|
||||
// If the caller wants the full texture and we have the correct mip support, we're done
|
||||
return proxy;
|
||||
return fCachedProxy;
|
||||
}
|
||||
}
|
||||
// Otherwise, make a copy for the requested subset or for mip maps.
|
||||
@ -98,7 +106,7 @@ sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
|
||||
|
||||
GrMipMapped mipMapped = willNeedMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
|
||||
|
||||
sk_sp<GrTextureProxy> texProxy = GrSurfaceProxy::Copy(context, proxy.get(), mipMapped,
|
||||
sk_sp<GrTextureProxy> texProxy = GrSurfaceProxy::Copy(context, fCachedProxy.get(), mipMapped,
|
||||
subset, SkBudgeted::kYes);
|
||||
if (!makingASubset && texProxy) {
|
||||
// We are in this case if we wanted the full texture, but we will be mip mapping the
|
||||
@ -112,14 +120,11 @@ sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
|
||||
// should match.
|
||||
SkASSERT(context->uniqueID() == fOwningContextID);
|
||||
|
||||
// Clear out the old cached texture.
|
||||
this->clear();
|
||||
// Since we no longer will be caching the and reusing the texture that actually wraps the
|
||||
// hardware buffer, we can release our refs on it.
|
||||
this->releaseTextureRef();
|
||||
|
||||
// We need to get the actual GrTexture so force instantiation of the GrTextureProxy
|
||||
texProxy->instantiate(context->contextPriv().resourceProvider());
|
||||
GrTexture* texture = texProxy->peekTexture();
|
||||
SkASSERT(texture);
|
||||
fOriginalTexture = texture;
|
||||
fCachedProxy = texProxy;
|
||||
}
|
||||
return texProxy;
|
||||
}
|
||||
@ -130,6 +135,7 @@ public:
|
||||
: fImage(image)
|
||||
, fDisplay(display) { }
|
||||
~BufferCleanupHelper() {
|
||||
// eglDestroyImageKHR will remove a ref from the AHardwareBuffer
|
||||
eglDestroyImageKHR(fDisplay, fImage);
|
||||
}
|
||||
private:
|
||||
@ -145,7 +151,7 @@ void GrAHardwareBufferImageGenerator::DeleteEGLImage(void* context) {
|
||||
|
||||
static GrBackendTexture make_gl_backend_texture(
|
||||
GrContext* context, AHardwareBuffer* hardwareBuffer,
|
||||
int width, int height,
|
||||
int width, int height, GrPixelConfig config,
|
||||
GrAHardwareBufferImageGenerator::DeleteImageProc* deleteProc,
|
||||
GrAHardwareBufferImageGenerator::DeleteImageCtx* deleteCtx) {
|
||||
while (GL_NO_ERROR != glGetError()) {} //clear GL errors
|
||||
@ -154,6 +160,7 @@ static GrBackendTexture make_gl_backend_texture(
|
||||
EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
|
||||
EGL_NONE };
|
||||
EGLDisplay display = eglGetCurrentDisplay();
|
||||
// eglCreateImageKHR will add a ref to the AHardwareBuffer
|
||||
EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
|
||||
clientBuffer, attribs);
|
||||
if (EGL_NO_IMAGE_KHR == image) {
|
||||
@ -187,6 +194,19 @@ static GrBackendTexture make_gl_backend_texture(
|
||||
GrGLTextureInfo textureInfo;
|
||||
textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
|
||||
textureInfo.fID = texID;
|
||||
switch (config) {
|
||||
case kRGBA_8888_GrPixelConfig:
|
||||
textureInfo.fFormat = GR_GL_RGBA8;
|
||||
break;
|
||||
case kRGBA_half_GrPixelConfig:
|
||||
textureInfo.fFormat = GR_GL_RGBA16F;
|
||||
break;
|
||||
case kRGB_565_GrPixelConfig:
|
||||
textureInfo.fFormat = GR_GL_RGB565;
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
}
|
||||
|
||||
*deleteProc = GrAHardwareBufferImageGenerator::DeleteEGLImage;
|
||||
*deleteCtx = new BufferCleanupHelper(image, display);
|
||||
@ -196,14 +216,15 @@ static GrBackendTexture make_gl_backend_texture(
|
||||
|
||||
static GrBackendTexture make_backend_texture(
|
||||
GrContext* context, AHardwareBuffer* hardwareBuffer,
|
||||
int width, int height,
|
||||
int width, int height, GrPixelConfig config,
|
||||
GrAHardwareBufferImageGenerator::DeleteImageProc* deleteProc,
|
||||
GrAHardwareBufferImageGenerator::DeleteImageCtx* deleteCtx) {
|
||||
if (context->abandoned() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
|
||||
// Check if GrContext is not abandoned and the backend is GL.
|
||||
return GrBackendTexture();
|
||||
}
|
||||
return make_gl_backend_texture(context, hardwareBuffer, width, height, deleteProc, deleteCtx);
|
||||
return make_gl_backend_texture(context, hardwareBuffer, width, height, config, deleteProc,
|
||||
deleteCtx);
|
||||
}
|
||||
|
||||
static void free_backend_texture(GrBackendTexture* backendTexture) {
|
||||
@ -222,19 +243,23 @@ static void free_backend_texture(GrBackendTexture* backendTexture) {
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) {
|
||||
void GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) {
|
||||
if (context->abandoned() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
|
||||
// Check if GrContext is not abandoned and the backend is GL.
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto proxyProvider = context->contextPriv().proxyProvider();
|
||||
|
||||
// return a cached GrTexture if invoked with the same context
|
||||
if (fOriginalTexture && fOwningContextID == context->uniqueID()) {
|
||||
return proxyProvider->createWrapped(sk_ref_sp(fOriginalTexture),
|
||||
kTopLeft_GrSurfaceOrigin);
|
||||
if (SK_InvalidGenID != fOwningContextID) {
|
||||
SkASSERT(fCachedProxy);
|
||||
if (context->uniqueID() != fOwningContextID) {
|
||||
this->releaseTextureRef();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SkASSERT(!fCachedProxy);
|
||||
|
||||
fOwningContextID = context->uniqueID();
|
||||
|
||||
GrPixelConfig pixelConfig;
|
||||
switch (this->getInfo().colorType()) {
|
||||
@ -248,48 +273,82 @@ sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::makeProxy(GrContext* cont
|
||||
pixelConfig = kRGB_565_GrPixelConfig;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteImageProc deleteImageProc = nullptr;
|
||||
DeleteImageCtx deleteImageCtx = nullptr;
|
||||
int width = this->getInfo().width();
|
||||
int height = this->getInfo().height();
|
||||
|
||||
GrBackendTexture backendTex = make_backend_texture(context, fGraphicBuffer,
|
||||
this->getInfo().width(),
|
||||
this->getInfo().height(),
|
||||
&deleteImageProc,
|
||||
&deleteImageCtx);
|
||||
GrSurfaceDesc desc;
|
||||
desc.fWidth = width;
|
||||
desc.fHeight = height;
|
||||
desc.fConfig = pixelConfig;
|
||||
|
||||
if (!backendTex.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
SkASSERT(deleteImageProc && deleteImageCtx);
|
||||
backendTex.fConfig = pixelConfig;
|
||||
sk_sp<GrTexture> tex = context->contextPriv().resourceProvider()->wrapBackendTexture(
|
||||
backendTex, kAdopt_GrWrapOwnership);
|
||||
if (!tex) {
|
||||
free_backend_texture(&backendTex);
|
||||
deleteImageProc(deleteImageCtx);
|
||||
return nullptr;
|
||||
GrTextureType textureType = GrTextureType::k2D;
|
||||
if (context->contextPriv().getBackend() == kOpenGL_GrBackend) {
|
||||
textureType = GrTextureType::kExternal;
|
||||
}
|
||||
|
||||
sk_sp<GrReleaseProcHelper> releaseProcHelper(
|
||||
auto proxyProvider = context->contextPriv().proxyProvider();
|
||||
|
||||
AHardwareBuffer* hardwareBuffer = fHardwareBuffer;
|
||||
AHardwareBuffer_acquire(hardwareBuffer);
|
||||
|
||||
GrTexture** ownedTexturePtr = &fOwnedTexture;
|
||||
|
||||
fCachedProxy = proxyProvider->createLazyProxy(
|
||||
[context, hardwareBuffer, width, height, pixelConfig, ownedTexturePtr]
|
||||
(GrResourceProvider* resourceProvider) {
|
||||
if (!resourceProvider) {
|
||||
AHardwareBuffer_release(hardwareBuffer);
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
|
||||
SkASSERT(!*ownedTexturePtr);
|
||||
|
||||
DeleteImageProc deleteImageProc = nullptr;
|
||||
DeleteImageCtx deleteImageCtx = nullptr;
|
||||
|
||||
GrBackendTexture backendTex = make_backend_texture(context, hardwareBuffer,
|
||||
width, height, pixelConfig,
|
||||
&deleteImageProc,
|
||||
&deleteImageCtx);
|
||||
if (!backendTex.isValid()) {
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
SkASSERT(deleteImageProc && deleteImageCtx);
|
||||
|
||||
backendTex.fConfig = pixelConfig;
|
||||
sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(
|
||||
backendTex, kAdopt_GrWrapOwnership);
|
||||
if (!tex) {
|
||||
free_backend_texture(&backendTex);
|
||||
deleteImageProc(deleteImageCtx);
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
|
||||
sk_sp<GrReleaseProcHelper> releaseProcHelper(
|
||||
new GrReleaseProcHelper(deleteImageProc, deleteImageCtx));
|
||||
tex->setRelease(std::move(releaseProcHelper));
|
||||
tex->setRelease(releaseProcHelper);
|
||||
|
||||
// We fail this assert, if the context has changed. This will be fully handled after
|
||||
// skbug.com/6812 is ready.
|
||||
SkASSERT(!fOriginalTexture);
|
||||
*ownedTexturePtr = tex.get();
|
||||
|
||||
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.
|
||||
context->contextPriv().getResourceCache()->insertCrossContextGpuResource(fOriginalTexture);
|
||||
return proxyProvider->createWrapped(std::move(tex), kTopLeft_GrSurfaceOrigin);
|
||||
// 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.
|
||||
context->contextPriv().getResourceCache()->insertCrossContextGpuResource(tex.get());
|
||||
return tex;
|
||||
},
|
||||
desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, textureType, SkBackingFit::kExact,
|
||||
SkBudgeted::kNo);
|
||||
|
||||
|
||||
if (!fCachedProxy) {
|
||||
AHardwareBuffer_release(hardwareBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool GrAHardwareBufferImageGenerator::onIsValid(GrContext* context) const {
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include "SkImageGenerator.h"
|
||||
|
||||
#include "GrTypesPriv.h"
|
||||
|
||||
extern "C" {
|
||||
typedef struct AHardwareBuffer AHardwareBuffer;
|
||||
}
|
||||
@ -46,12 +48,21 @@ protected:
|
||||
|
||||
private:
|
||||
GrAHardwareBufferImageGenerator(const SkImageInfo&, AHardwareBuffer*, SkAlphaType);
|
||||
sk_sp<GrTextureProxy> makeProxy(GrContext* context);
|
||||
void clear();
|
||||
void makeProxy(GrContext* context);
|
||||
|
||||
AHardwareBuffer* fGraphicBuffer;
|
||||
GrTexture* fOriginalTexture = nullptr;
|
||||
uint32_t fOwningContextID;
|
||||
void releaseTextureRef();
|
||||
|
||||
static void ReleaseRefHelper_TextureReleaseProc(void* ctx);
|
||||
|
||||
AHardwareBuffer* fHardwareBuffer;
|
||||
|
||||
// There is never a ref associated with this pointer. We rely on our atomic bookkeeping
|
||||
// with the context ID to know when this pointer is valid and safe to use. This lets us
|
||||
// avoid releasing a ref from another thread, or get into races during context shutdown.
|
||||
GrTexture* fOwnedTexture = nullptr;
|
||||
uint32_t fOwningContextID = SK_InvalidGenID;
|
||||
|
||||
sk_sp<GrTextureProxy> fCachedProxy;
|
||||
|
||||
typedef SkImageGenerator INHERITED;
|
||||
};
|
||||
|
@ -139,8 +139,8 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
|
||||
textureType = GrGLTexture::TextureTypeFromTarget(glInfo.fTarget);
|
||||
}
|
||||
sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
|
||||
[refHelper, releaseProcHelper, semaphore,
|
||||
backendTexture](GrResourceProvider* resourceProvider) {
|
||||
[refHelper, releaseProcHelper, semaphore, backendTexture]
|
||||
(GrResourceProvider* resourceProvider) {
|
||||
if (!resourceProvider) {
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user