Add GrRenderTargetContext instantiate & asTextureProxy
This CL also centralizes the instantiation code in GrSurfaceProxy and adds a test.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4494
Change-Id: I0081d9a216dc0af293179f23bcb88acf6a822324
Reviewed-on: https://skia-review.googlesource.com/4494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/gn/tests.gni b/gn/tests.gni
index 135c3ce..4fa653a 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -173,6 +173,7 @@
"$_tests/RefCntTest.cpp",
"$_tests/RefDictTest.cpp",
"$_tests/RegionTest.cpp",
+ "$_tests/RenderTargetContextTest.cpp",
"$_tests/ResourceCacheTest.cpp",
"$_tests/RoundRectTest.cpp",
"$_tests/RRectInPathTest.cpp",
diff --git a/include/gpu/GrRenderTargetContext.h b/include/gpu/GrRenderTargetContext.h
index f728ef1..95d8c9d 100644
--- a/include/gpu/GrRenderTargetContext.h
+++ b/include/gpu/GrRenderTargetContext.h
@@ -33,6 +33,7 @@
class GrRenderTargetOpList;
class GrStyle;
class GrSurface;
+class GrTextureProxy;
struct GrUserStencilSettings;
class SkDrawFilter;
struct SkIPoint;
@@ -342,17 +343,20 @@
bool wasAbandoned() const;
+ GrRenderTarget* instantiate();
+
GrRenderTarget* accessRenderTarget() {
// TODO: usage of this entry point needs to be reduced and potentially eliminated
// since it ends the deferral of the GrRenderTarget's allocation
return fRenderTargetProxy->instantiate(fContext->textureProvider());
}
+ GrTextureProxy* asDeferredTexture();
+
sk_sp<GrTexture> asTexture() {
// TODO: usage of this entry point needs to be reduced and potentially eliminated
// since it ends the deferral of the GrRenderTarget's allocation
- // It's usage should migrate to the soon-to-be-added asDeferredTexture which
- // returns a GrTextureProxy
+ // It's usage should migrate to asDeferredTexture
return sk_ref_sp(this->accessRenderTarget()->asTexture());
}
@@ -362,6 +366,8 @@
GrAuditTrail* auditTrail() { return fAuditTrail; }
+ bool isWrapped_ForTesting() const;
+
protected:
GrRenderTargetContext(GrContext*, GrDrawingManager*, sk_sp<GrRenderTargetProxy>,
sk_sp<SkColorSpace>, const SkSurfaceProps* surfaceProps, GrAuditTrail*,
diff --git a/include/private/GrRenderTargetProxy.h b/include/private/GrRenderTargetProxy.h
index 3bad9df..267d754 100644
--- a/include/private/GrRenderTargetProxy.h
+++ b/include/private/GrRenderTargetProxy.h
@@ -27,7 +27,6 @@
SkBackingFit, SkBudgeted);
static sk_sp<GrRenderTargetProxy> Make(sk_sp<GrRenderTarget>);
- // TODO: add asTextureProxy variants
GrRenderTargetProxy* asRenderTargetProxy() override { return this; }
const GrRenderTargetProxy* asRenderTargetProxy() const override { return this; }
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index e748853..539aaf6 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -13,6 +13,7 @@
#include "SkRect.h"
class GrOpList;
+class GrTextureProvider;
class GrTextureProxy;
class GrRenderTargetProxy;
@@ -127,6 +128,8 @@
return fGpuMemorySize;
}
+ bool isWrapped_ForTesting() const;
+
protected:
// Deferred version
GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted)
@@ -143,6 +146,8 @@
virtual ~GrSurfaceProxy();
+ GrSurface* instantiate(GrTextureProvider* texProvider);
+
// For wrapped resources, 'fDesc' will always be filled in from the wrapped resource.
const GrSurfaceDesc fDesc;
const SkBackingFit fFit; // always exact for wrapped resources
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index e68ef88..75f09de 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -24,7 +24,6 @@
const void* srcData = nullptr, size_t rowBytes = 0);
static sk_sp<GrTextureProxy> Make(sk_sp<GrTexture>);
- // TODO: add asRenderTargetProxy variants
GrTextureProxy* asTextureProxy() override { return this; }
const GrTextureProxy* asTextureProxy() const override { return this; }
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index ad8adb0..20ac412 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -117,6 +117,14 @@
SkSafeUnref(fOpList);
}
+GrRenderTarget* GrRenderTargetContext::instantiate() {
+ return fRenderTargetProxy->instantiate(fContext->textureProvider());
+}
+
+GrTextureProxy* GrRenderTargetContext::asDeferredTexture() {
+ return fRenderTargetProxy->asTextureProxy();
+}
+
GrRenderTargetOpList* GrRenderTargetContext::getOpList() {
ASSERT_SINGLE_OWNER
SkDEBUGCODE(this->validate();)
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index f428a0f..fcc5275 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -37,33 +37,17 @@
}
GrRenderTarget* GrRenderTargetProxy::instantiate(GrTextureProvider* texProvider) {
- if (fTarget) {
- return fTarget->asRenderTarget();
- }
+ SkASSERT(fDesc.fFlags & GrSurfaceFlags::kRenderTarget_GrSurfaceFlag);
- // TODO: it would be nice to not have to copy the desc here
- GrSurfaceDesc desc = fDesc;
- desc.fFlags |= GrSurfaceFlags::kRenderTarget_GrSurfaceFlag;
-
- if (SkBackingFit::kApprox == fFit) {
- fTarget = texProvider->createApproxTexture(desc);
- } else {
- fTarget = texProvider->createTexture(desc, fBudgeted);
- }
- if (!fTarget) {
+ GrSurface* surf = INHERITED::instantiate(texProvider);
+ if (!surf || !surf->asRenderTarget()) {
return nullptr;
}
-#ifdef SK_DEBUG
- if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
- SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
- }
-#endif
-
// Check that our a priori computation matched the ultimate reality
- SkASSERT(fFlags == fTarget->asRenderTarget()->renderTargetPriv().flags());
+ SkASSERT(fFlags == surf->asRenderTarget()->renderTargetPriv().flags());
- return fTarget->asRenderTarget();
+ return surf->asRenderTarget();
}
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index c5afd0f..b6d0e11 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -9,6 +9,7 @@
#include "GrGpuResourcePriv.h"
#include "GrOpList.h"
+#include "GrTextureProvider.h"
GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit)
: INHERITED(std::move(surface))
@@ -27,6 +28,29 @@
SkSafeUnref(fLastOpList);
}
+GrSurface* GrSurfaceProxy::instantiate(GrTextureProvider* texProvider) {
+ if (fTarget) {
+ return fTarget;
+ }
+
+ if (SkBackingFit::kApprox == fFit) {
+ fTarget = texProvider->createApproxTexture(fDesc);
+ } else {
+ fTarget = texProvider->createTexture(fDesc, fBudgeted);
+ }
+ if (!fTarget) {
+ return nullptr;
+ }
+
+#ifdef SK_DEBUG
+ if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
+ SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
+ }
+#endif
+
+ return fTarget;
+}
+
void GrSurfaceProxy::setLastOpList(GrOpList* opList) {
if (fLastOpList) {
// The non-MDB world never closes so we can't check this condition
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index ca773b3..5fe43f7 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -21,22 +21,11 @@
}
GrTexture* GrTextureProxy::instantiate(GrTextureProvider* texProvider) {
- if (fTarget) {
- return fTarget->asTexture();
+ GrSurface* surf = this->INHERITED::instantiate(texProvider);
+ if (!surf) {
+ return nullptr;
}
- if (SkBackingFit::kApprox == fFit) {
- fTarget = texProvider->createApproxTexture(fDesc);
- } else {
- fTarget = texProvider->createTexture(fDesc, fBudgeted);
- }
-
-#ifdef SK_DEBUG
- if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
- SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
- }
-#endif
-
return fTarget->asTexture();
}
diff --git a/tests/RenderTargetContextTest.cpp b/tests/RenderTargetContextTest.cpp
new file mode 100644
index 0000000..9a4b874
--- /dev/null
+++ b/tests/RenderTargetContextTest.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test.
+
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrTextureProxy.h"
+#include "GrRenderTargetContext.h"
+
+static const int kSize = 64;
+
+static sk_sp<GrRenderTargetContext> get_rtc(GrContext* ctx, bool wrapped) {
+
+ if (wrapped) {
+ return ctx->makeRenderTargetContext(SkBackingFit::kExact,
+ kSize, kSize,
+ kRGBA_8888_GrPixelConfig, nullptr);
+ } else {
+ return ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact,
+ kSize, kSize,
+ kRGBA_8888_GrPixelConfig, nullptr);
+ }
+}
+
+static void check_is_wrapped_status(skiatest::Reporter* reporter,
+ GrRenderTargetContext* rtCtx,
+ bool wrappedExpectation) {
+ REPORTER_ASSERT(reporter, rtCtx->isWrapped_ForTesting() == wrappedExpectation);
+
+ GrTextureProxy* tProxy = rtCtx->asDeferredTexture();
+ REPORTER_ASSERT(reporter, tProxy);
+
+ REPORTER_ASSERT(reporter, tProxy->isWrapped_ForTesting() == wrappedExpectation);
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(RenderTargetContextTest, reporter, ctxInfo) {
+ GrContext* ctx = ctxInfo.grContext();
+
+ // A wrapped rtCtx's textureProxy is also wrapped
+ {
+ sk_sp<GrRenderTargetContext> rtCtx(get_rtc(ctx, true));
+ check_is_wrapped_status(reporter, rtCtx.get(), true);
+ }
+
+ // A deferred rtCtx's textureProxy is also deferred and GrRenderTargetContext::instantiate()
+ // swaps both from deferred to wrapped
+ {
+ sk_sp<GrRenderTargetContext> rtCtx(get_rtc(ctx, false));
+
+ check_is_wrapped_status(reporter, rtCtx.get(), false);
+
+ GrRenderTarget* rt = rtCtx->instantiate();
+ REPORTER_ASSERT(reporter, rt);
+
+ check_is_wrapped_status(reporter, rtCtx.get(), true);
+ }
+
+ // Calling instantiate on a GrRenderTargetContext's textureProxy also instantiates the
+ // GrRenderTargetContext
+ {
+ sk_sp<GrRenderTargetContext> rtCtx(get_rtc(ctx, false));
+
+ check_is_wrapped_status(reporter, rtCtx.get(), false);
+
+ GrTextureProxy* tProxy = rtCtx->asDeferredTexture();
+ REPORTER_ASSERT(reporter, tProxy);
+
+ GrTexture* tex = tProxy->instantiate(ctx->textureProvider());
+ REPORTER_ASSERT(reporter, tex);
+
+ check_is_wrapped_status(reporter, rtCtx.get(), true);
+ }
+
+ // readPixels switches a deferred rtCtx to wrapped
+ {
+ sk_sp<GrRenderTargetContext> rtCtx(get_rtc(ctx, false));
+
+ check_is_wrapped_status(reporter, rtCtx.get(), false);
+
+ SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(kSize, kSize);
+ SkAutoTMalloc<uint32_t> dstBuffer(kSize * kSize);
+ static const size_t kRowBytes = sizeof(uint32_t) * kSize;
+
+ bool result = rtCtx->readPixels(dstInfo, dstBuffer.get(), kRowBytes, 0, 0);
+ REPORTER_ASSERT(reporter, result);
+
+ check_is_wrapped_status(reporter, rtCtx.get(), true);
+ }
+
+ // TODO: in a future world we should be able to add a test that the majority of
+ // GrRenderTargetContext calls do not force the instantiation of a deferred
+ // GrRenderTargetContext
+}
+#endif
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index ba870ea..8574399 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -62,6 +62,14 @@
fRenderTargetContext = renderTargetContext;
}
+bool GrSurfaceProxy::isWrapped_ForTesting() const {
+ return SkToBool(fTarget);
+}
+
+bool GrRenderTargetContext::isWrapped_ForTesting() const {
+ return fRenderTargetProxy->isWrapped_ForTesting();
+}
+
void GrContext::getTestTarget(GrTestTarget* tar, sk_sp<GrRenderTargetContext> renderTargetContext) {
this->flush();
SkASSERT(renderTargetContext);