Add lazy proxy's for wrapping backend textures
Bug: skia: Change-Id: I3bb557cefc35312adc9515b5683d2ed747bb4eb3 Reviewed-on: https://skia-review.googlesource.com/96862 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
4e69f14814
commit
f2336e4500
@ -206,6 +206,10 @@ public:
|
||||
*
|
||||
* Will return NULL if the specified backend texture is unsupported.
|
||||
*
|
||||
* This is not supported if the GrContext was obtained from a deferred display list canvas
|
||||
* since if the SkImage never gets used and flushed to a real GrContext, we have no way to be
|
||||
* able to delete the underlying backend texture.
|
||||
*
|
||||
* DEPRECATED: This factory is deprecated and clients should use the factory below which takes
|
||||
* an SkColorType.
|
||||
*/
|
||||
@ -224,6 +228,10 @@ public:
|
||||
* interpret the backend format supplied by the GrBackendTexture. If the format in the
|
||||
* GrBackendTexture is not compitable with the SkColorType, SkAlphaType, and SkColorSpace we
|
||||
* will return nullptr.
|
||||
*
|
||||
* This is not supported if the GrContext was obtained from a deferred display list canvas
|
||||
* since if the SkImage never gets used and flushed to a real GrContext, we have no way to be
|
||||
* able to delete the underlying backend texture.
|
||||
*/
|
||||
static sk_sp<SkImage> MakeFromAdoptedTexture(GrContext* context,
|
||||
const GrBackendTexture& backendTexture,
|
||||
|
@ -86,6 +86,7 @@ private:
|
||||
friend class SkImage;
|
||||
friend class SkSurface;
|
||||
friend class GrBackendTextureImageGenerator;
|
||||
friend class GrProxyProvider;
|
||||
friend class GrGpu;
|
||||
friend class GrGLGpu;
|
||||
friend class GrVkGpu;
|
||||
|
@ -114,15 +114,14 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
|
||||
|
||||
// Must make copies of member variables to capture in the lambda since this image generator may
|
||||
// be deleted before we actuallly execute the lambda.
|
||||
GrSurfaceOrigin surfaceOrigin = fSurfaceOrigin;
|
||||
sk_sp<GrSemaphore> semaphore = fSemaphore;
|
||||
GrBackendTexture backendTexture = fBackendTexture;
|
||||
RefHelper* refHelper = fRefHelper;
|
||||
refHelper->ref();
|
||||
|
||||
sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
|
||||
[refHelper, semaphore, backendTexture, surfaceOrigin]
|
||||
(GrResourceProvider* resourceProvider, GrSurfaceOrigin* outOrigin) {
|
||||
[refHelper, semaphore, backendTexture]
|
||||
(GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) {
|
||||
if (!resourceProvider) {
|
||||
// If we get here then we never created a texture to pass the refHelper ref off
|
||||
// to. Thus we must unref it ourselves.
|
||||
@ -168,7 +167,6 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
|
||||
tex->setRelease(ReleaseRefHelper_TextureReleaseProc, refHelper);
|
||||
}
|
||||
|
||||
*outOrigin = surfaceOrigin;
|
||||
return tex;
|
||||
|
||||
}, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo);
|
||||
|
@ -330,17 +330,46 @@ sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> texture(fResourceProvider->wrapBackendTexture(backendTex, ownership));
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
GrSurfaceDesc desc;
|
||||
desc.fOrigin = origin;
|
||||
desc.fWidth = backendTex.width();
|
||||
desc.fHeight = backendTex.height();
|
||||
desc.fConfig = backendTex.config();
|
||||
GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo;
|
||||
|
||||
sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
|
||||
[backendTex, ownership, releaseProc, releaseCtx]
|
||||
(GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) {
|
||||
if (!resourceProvider) {
|
||||
// This lazy proxy was never initialized. If it has a releaseProc we must call
|
||||
// it now so that the client knows they can free the underlying backend object.
|
||||
if (releaseProc) {
|
||||
releaseProc(releaseCtx);
|
||||
}
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex,
|
||||
ownership);
|
||||
if (!tex) {
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
if (releaseProc) {
|
||||
texture->setRelease(releaseProc, releaseCtx);
|
||||
tex->setRelease(releaseProc, releaseCtx);
|
||||
}
|
||||
SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
|
||||
// Make sure we match how we created the proxy with SkBudgeted::kNo
|
||||
SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted());
|
||||
|
||||
SkASSERT(!texture->asRenderTarget()); // Strictly a GrTexture
|
||||
return tex;
|
||||
}, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo);
|
||||
|
||||
return this->createWrapped(std::move(texture), origin);
|
||||
if (fResourceProvider) {
|
||||
// In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however,
|
||||
// we're better off instantiating the proxy immediately here.
|
||||
proxy->priv().doLazyInstantiation(fResourceProvider);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& tex,
|
||||
|
@ -351,7 +351,19 @@ void GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvide
|
||||
SkASSERT(fProxy->fLazyInstantiateCallback);
|
||||
SkASSERT(!fProxy->fTarget);
|
||||
|
||||
sk_sp<GrTexture> texture = fProxy->fLazyInstantiateCallback(resourceProvider, &fProxy->fOrigin);
|
||||
GrSurfaceOrigin* outOrigin;
|
||||
if (GrSurfaceProxy::LazyState::kPartially == fProxy->lazyInstantiationState()) {
|
||||
// In the partially instantiated case, we set the origin on the SurfaceProxy at creation
|
||||
// time (via a GrSurfaceDesc). In the lambda, the creation of the texture never needs to
|
||||
// know the origin, and it also can't change or have any effect on it. Thus we just pass in
|
||||
// nullptr in this case since it should never be set.
|
||||
outOrigin = nullptr;
|
||||
} else {
|
||||
outOrigin = &fProxy->fOrigin;
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> texture = fProxy->fLazyInstantiateCallback(resourceProvider, outOrigin);
|
||||
|
||||
|
||||
// Indicate we are no longer pending lazy instantiation.
|
||||
fProxy->fLazyInstantiateCallback = nullptr;
|
||||
|
@ -156,6 +156,22 @@ GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
|
||||
GrSurfaceOrigin* origin) const {
|
||||
SkASSERT(fProxy);
|
||||
|
||||
if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
|
||||
// This image was created with a DDL context and cannot be instantiated. Thus we return 0
|
||||
// here which is considered invalid for all backends.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()) {
|
||||
SkASSERT(fContext->contextPriv().resourceProvider());
|
||||
fProxy->priv().doLazyInstantiation(fContext->contextPriv().resourceProvider());
|
||||
if (!fProxy->priv().isInstantiated()) {
|
||||
// We failed to instantiate the lazy proxy. Thus we return 0 here which is considered
|
||||
// invalid for all backends.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
|
||||
return 0;
|
||||
}
|
||||
@ -335,6 +351,10 @@ sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
|
||||
sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
|
||||
const GrBackendTexture& tex, GrSurfaceOrigin origin,
|
||||
SkAlphaType at, sk_sp<SkColorSpace> cs) {
|
||||
if (!ctx->contextPriv().resourceProvider()) {
|
||||
// We have a DDL context and we don't support adopted textures for them.
|
||||
return nullptr;
|
||||
}
|
||||
return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrBackendSurface.h"
|
||||
#include "GrGpu.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDeferredDisplayListRecorder.h"
|
||||
#include "SkGpuDevice.h"
|
||||
@ -178,4 +180,160 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(SkSurfaceCharacterization, reporter, ctxInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr int kSize = 8;
|
||||
|
||||
struct TextureReleaseChecker {
|
||||
TextureReleaseChecker() : fReleaseCount(0) {}
|
||||
int fReleaseCount;
|
||||
static void Release(void* self) {
|
||||
static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
|
||||
}
|
||||
};
|
||||
|
||||
enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
|
||||
|
||||
// This tests the ability to create and use wrapped textures in a DDL world
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
|
||||
GrContext* context = ctxInfo.grContext();
|
||||
GrGpu* gpu = context->contextPriv().getGpu();
|
||||
for (auto lastStage : { DDLStage::kMakeImage, DDLStage::kDrawImage,
|
||||
DDLStage::kDetach, DDLStage::kDrawDDL } ) {
|
||||
for (auto earlyImageReset : { false , true } ) {
|
||||
GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
|
||||
nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
|
||||
if (!backendTex.isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SurfaceParameters params;
|
||||
|
||||
sk_sp<SkSurface> s = params.make(context);
|
||||
if (!s) {
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
SkSurfaceCharacterization c;
|
||||
SkAssertResult(s->characterize(&c));
|
||||
|
||||
std::unique_ptr<SkDeferredDisplayListRecorder> recorder(
|
||||
new SkDeferredDisplayListRecorder(c));
|
||||
|
||||
SkCanvas* canvas = recorder->getCanvas();
|
||||
if (!canvas) {
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
GrContext* deferredContext = canvas->getGrContext();
|
||||
if (!deferredContext) {
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(deferredContext, backendTex,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType, nullptr);
|
||||
// Adopted Textures are not supported in DDL
|
||||
REPORTER_ASSERT(reporter, !image);
|
||||
|
||||
TextureReleaseChecker releaseChecker;
|
||||
image = SkImage::MakeFromTexture(deferredContext, backendTex,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType, nullptr,
|
||||
TextureReleaseChecker::Release, &releaseChecker);
|
||||
|
||||
REPORTER_ASSERT(reporter, image);
|
||||
if (!image) {
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DDLStage::kMakeImage == lastStage) {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
image.reset();
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
recorder.reset();
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas->drawImage(image.get(), 0, 0);
|
||||
|
||||
if (earlyImageReset) {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
image.reset();
|
||||
// Ref should still be held by DDL recorder since we did the draw
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
}
|
||||
|
||||
if (DDLStage::kDrawImage == lastStage) {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
recorder.reset();
|
||||
if (earlyImageReset) {
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
image.reset();
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
}
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<SkDeferredDisplayList> ddl = recorder->detach();
|
||||
if (DDLStage::kDetach == lastStage) {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
recorder.reset();
|
||||
// DDL TODO: Once copies of OpLists from the recorder to DDL are implemented we can
|
||||
// uncomment this check. Currently the texture is getting reset when the recorder
|
||||
// goes away (assuming we did an earlyImageReset).
|
||||
// REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
ddl.reset();
|
||||
if (earlyImageReset) {
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
image.reset();
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
}
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
continue;
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(reporter, s->draw(ddl.get()));
|
||||
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
recorder.reset();
|
||||
// DDL TODO: Once copies of OpLists from the recorder to DDL are implemented we can
|
||||
// uncomment these checks. Currently the texture is getting released when the recorder
|
||||
// goes away (assuming we did an earlyImageReset).
|
||||
// REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
ddl.reset();
|
||||
// REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
|
||||
// Force all draws to flush and sync by calling a read pixels
|
||||
SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType);
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocPixels(imageInfo);
|
||||
s->readPixels(imageInfo, bitmap.getPixels(), 0, 0, 0);
|
||||
|
||||
if (earlyImageReset) {
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
|
||||
image.reset();
|
||||
REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
|
||||
}
|
||||
|
||||
gpu->deleteTestingOnlyBackendTexture(&backendTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user