add ability to get FBO ID to Surface
BUG=skia:
Review URL: https://codereview.chromium.org/1220733007
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 5860cf2..57527ed 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -159,11 +159,23 @@
*/
void notifyContentWillChange(ContentChangeMode mode);
- enum TextureHandleAccess {
- kFlushRead_TextureHandleAccess, //!< caller may read from the texture
- kFlushWrite_TextureHandleAccess, //!< caller may write to the texture
- kDiscardWrite_TextureHandleAccess, //!< caller must over-write the entire texture
+ enum BackendHandleAccess {
+ kFlushRead_BackendHandleAccess, //!< caller may read from the backend object
+ kFlushWrite_BackendHandleAccess, //!< caller may write to the backend object
+ kDiscardWrite_BackendHandleAccess, //!< caller must over-write the entire backend object
};
+
+ /*
+ * These are legacy aliases which will be removed soon
+ */
+ static const BackendHandleAccess kFlushRead_TextureHandleAccess =
+ kFlushRead_BackendHandleAccess;
+ static const BackendHandleAccess kFlushWrite_TextureHandleAccess =
+ kFlushWrite_BackendHandleAccess;
+ static const BackendHandleAccess kDiscardWrite_TextureHandleAccess =
+ kDiscardWrite_BackendHandleAccess;
+
+
/**
* Retrieves the backend API handle of the texture used by this surface, or 0 if the surface
* is not backed by a GPU texture.
@@ -171,7 +183,15 @@
* The returned texture-handle is only valid until the next draw-call into the surface,
* or the surface is deleted.
*/
- GrBackendObject getTextureHandle(TextureHandleAccess);
+ GrBackendObject getTextureHandle(BackendHandleAccess);
+
+ /**
+ * Retrieves the backend API handle of the RenderTarget backing this surface. Callers must
+ * ensure this function returns 'true' or else the GrBackendObject will be invalid
+ *
+ * In OpenGL this will return the FramebufferObject ID.
+ */
+ bool getRenderTargetHandle(GrBackendObject*, BackendHandleAccess);
/**
* Return a canvas that will draw into this surface. This will always
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
index 67dcd4f..8983d53 100644
--- a/include/gpu/GrRenderTarget.h
+++ b/include/gpu/GrRenderTarget.h
@@ -138,6 +138,12 @@
};
virtual ResolveType getResolveType() const = 0;
+ /**
+ * Return the native ID or handle to the rendertarget, depending on the
+ * platform. e.g. on OpenGL, return the FBO ID.
+ */
+ virtual GrBackendObject getRenderTargetHandle() const = 0;
+
// Provides access to functions that aren't part of the public API.
GrRenderTargetPriv renderTargetPriv();
const GrRenderTargetPriv renderTargetPriv() const;
diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h
index 2113a80..1e6dc7f 100644
--- a/src/gpu/gl/GrGLRenderTarget.h
+++ b/src/gpu/gl/GrGLRenderTarget.h
@@ -55,6 +55,8 @@
}
}
+ GrBackendObject getRenderTargetHandle() const override { return fRTFBOID; }
+
/** When we don't own the FBO ID we don't attempt to modify its attachments. */
bool canAttemptStencilAttachment() const override {
return kCached_LifeCycle == fRTLifecycle || kUncached_LifeCycle == fRTLifecycle;
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 35409be..2e8c7fa 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -175,10 +175,14 @@
return this->getCanvas()->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
}
-GrBackendObject SkSurface::getTextureHandle(TextureHandleAccess access) {
+GrBackendObject SkSurface::getTextureHandle(BackendHandleAccess access) {
return asSB(this)->onGetTextureHandle(access);
}
+bool SkSurface::getRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
+ return asSB(this)->onGetRenderTargetHandle(obj, access);
+}
+
//////////////////////////////////////////////////////////////////////////////////////
#if !SK_SUPPORT_GPU
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 3f1301e..b8eb7dd 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -18,10 +18,14 @@
SkSurface_Base(const SkImageInfo&, const SkSurfaceProps*);
virtual ~SkSurface_Base();
- virtual GrBackendObject onGetTextureHandle(TextureHandleAccess) {
+ virtual GrBackendObject onGetTextureHandle(BackendHandleAccess) {
return 0;
}
+ virtual bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) {
+ return false;
+ }
+
/**
* Allocate a canvas that will draw into this surface. We will cache this
* canvas, to return the same object to the caller multiple times. We
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 3a306ad..67f54d5 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -26,21 +26,37 @@
fDevice->unref();
}
-GrBackendObject SkSurface_Gpu::onGetTextureHandle(TextureHandleAccess access) {
- GrRenderTarget* rt = fDevice->accessRenderTarget();
+static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
+ SkSurface::BackendHandleAccess access) {
+ GrRenderTarget* rt = surface->getDevice()->accessRenderTarget();
switch (access) {
- case kFlushRead_TextureHandleAccess:
+ case SkSurface::kFlushRead_BackendHandleAccess:
break;
- case kFlushWrite_TextureHandleAccess:
- case kDiscardWrite_TextureHandleAccess:
+ case SkSurface::kFlushWrite_BackendHandleAccess:
+ case SkSurface::kDiscardWrite_BackendHandleAccess:
// for now we don't special-case on Discard, but we may in the future.
- this->notifyContentWillChange(kRetain_ContentChangeMode);
+ surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
// legacy: need to dirty the bitmap's genID in our device (curse it)
- fDevice->fLegacyBitmap.notifyPixelsChanged();
+ surface->getDevice()->accessBitmap(false).notifyPixelsChanged();
break;
}
rt->prepareForExternalIO();
- return rt->asTexture()->getTextureHandle();
+ return rt;
+}
+
+GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
+ GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
+ GrTexture* texture = rt->asTexture();
+ if (texture) {
+ return texture->getTextureHandle();
+ }
+ return 0;
+}
+
+bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
+ GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
+ *obj = rt->getRenderTargetHandle();
+ return true;
}
SkCanvas* SkSurface_Gpu::onNewCanvas() {
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index ed94a24..2324154 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -16,12 +16,11 @@
class SkSurface_Gpu : public SkSurface_Base {
public:
-
-
SkSurface_Gpu(SkGpuDevice*);
virtual ~SkSurface_Gpu();
- GrBackendObject onGetTextureHandle(TextureHandleAccess) override;
+ GrBackendObject onGetTextureHandle(BackendHandleAccess) override;
+ bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) override;
SkCanvas* onNewCanvas() override;
SkSurface* onNewSurface(const SkImageInfo&) override;
SkImage* onNewImageSnapshot(Budgeted) override;
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 1b57b77..e8ff63c 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -102,7 +102,7 @@
}
#if SK_SUPPORT_GPU
-static void test_wrapped_surface(skiatest::Reporter* reporter, GrContext* ctx) {
+static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
if (NULL == ctx) {
return;
}
@@ -120,107 +120,77 @@
return;
}
- for (int useFBO = 0; useFBO < 2; ++useFBO) {
- // Test the wrapped factory for SkSurface by creating a texture using GL and then wrap it in
- // a SkSurface.
- GrGLuint texID;
- static const int kW = 100;
- static const int kH = 100;
- static const uint32_t kOrigColor = 0xFFAABBCC;
- SkAutoTArray<uint32_t> pixels(kW * kH);
- sk_memset32(pixels.get(), kOrigColor, kW * kH);
- GR_GL_CALL(gl, GenTextures(1, &texID));
- GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0));
- GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
- GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texID));
- GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER,
- GR_GL_NEAREST));
- GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER,
- GR_GL_NEAREST));
- GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S,
- GR_GL_CLAMP_TO_EDGE));
- GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T,
- GR_GL_CLAMP_TO_EDGE));
- GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, kW, kH, 0, GR_GL_RGBA,
- GR_GL_UNSIGNED_BYTE,
- pixels.get()));
+ // Test the wrapped factory for SkSurface by creating a texture using GL and then wrap it in
+ // a SkSurface.
+ GrGLuint texID;
+ static const int kW = 100;
+ static const int kH = 100;
+ static const uint32_t kOrigColor = 0xFFAABBCC;
+ SkAutoTArray<uint32_t> pixels(kW * kH);
+ sk_memset32(pixels.get(), kOrigColor, kW * kH);
+ GR_GL_CALL(gl, GenTextures(1, &texID));
+ GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0));
+ GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+ GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texID));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER,
+ GR_GL_NEAREST));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER,
+ GR_GL_NEAREST));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S,
+ GR_GL_CLAMP_TO_EDGE));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T,
+ GR_GL_CLAMP_TO_EDGE));
+ GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, kW, kH, 0, GR_GL_RGBA,
+ GR_GL_UNSIGNED_BYTE,
+ pixels.get()));
- SkAutoTUnref<SkSurface> surface;
- GrGLuint fboID = 0;
- if (useFBO) {
- GR_GL_CALL(gl, GenFramebuffers(1, &fboID));
- GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, fboID));
- GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D, texID, 0));
- GrBackendRenderTargetDesc wrappedDesc;
- wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
- wrappedDesc.fWidth = kW;
- wrappedDesc.fHeight = kH;
- wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
- wrappedDesc.fSampleCnt = 0;
- wrappedDesc.fRenderTargetHandle = fboID;
- wrappedDesc.fStencilBits = 0;
+ GrBackendTextureDesc wrappedDesc;
+ wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
+ wrappedDesc.fWidth = kW;
+ wrappedDesc.fHeight = kH;
+ wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+ wrappedDesc.fSampleCnt = 0;
+ wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
+ wrappedDesc.fTextureHandle = texID;
- ctx->resetContext();
- surface.reset(SkSurface::NewFromBackendRenderTarget(ctx, wrappedDesc, NULL));
- } else {
- GrBackendTextureDesc wrappedDesc;
- wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
- wrappedDesc.fWidth = kW;
- wrappedDesc.fHeight = kH;
- wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
- wrappedDesc.fSampleCnt = 0;
- wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
- wrappedDesc.fTextureHandle = texID;
-
- ctx->resetContext();
- surface.reset(SkSurface::NewFromBackendTexture(ctx, wrappedDesc, NULL));
- }
- REPORTER_ASSERT(reporter, surface);
- if (surface) {
- // Validate that we can draw to the canvas and that the original texture color is
- // preserved in pixels that aren't rendered to via the surface.
- SkPaint paint;
- static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
- paint.setColor(kRectColor);
- surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
- paint);
- SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
- surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
- bool stop = false;
- SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
- (kOrigColor >> 0 & 0xFF),
- (kOrigColor >> 8 & 0xFF),
- (kOrigColor >> 16 & 0xFF));
- SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
- (kRectColor >> 16 & 0xFF),
- (kRectColor >> 8 & 0xFF),
- (kRectColor >> 0 & 0xFF));
- for (int y = 0; y < kH/2 && !stop; ++y) {
- for (int x = 0; x < kW && !stop; ++x) {
- REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
- if (rectColorPM != pixels[x + y * kW]) {
- stop = true;
- }
- }
- }
- stop = false;
- for (int y = kH/2; y < kH && !stop; ++y) {
- for (int x = 0; x < kW && !stop; ++x) {
- REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
- if (origColorPM != pixels[x + y * kW]) {
- stop = true;
- }
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL));
+ REPORTER_ASSERT(reporter, surface);
+ if (surface) {
+ // Validate that we can draw to the canvas and that the original texture color is preserved
+ // in pixels that aren't rendered to via the surface.
+ SkPaint paint;
+ static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
+ paint.setColor(kRectColor);
+ surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
+ paint);
+ SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
+ surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
+ bool stop = false;
+ SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
+ (kOrigColor >> 0 & 0xFF),
+ (kOrigColor >> 8 & 0xFF),
+ (kOrigColor >> 16 & 0xFF));
+ SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
+ (kRectColor >> 16 & 0xFF),
+ (kRectColor >> 8 & 0xFF),
+ (kRectColor >> 0 & 0xFF));
+ for (int y = 0; y < kH/2 && !stop; ++y) {
+ for (int x = 0; x < kW && !stop; ++x) {
+ REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
+ if (rectColorPM != pixels[x + y * kW]) {
+ stop = true;
}
}
}
- if (texID) {
- GR_GL_CALL(gl, DeleteTextures(1, &texID));
+ stop = false;
+ for (int y = kH/2; y < kH && !stop; ++y) {
+ for (int x = 0; x < kW && !stop; ++x) {
+ REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
+ if (origColorPM != pixels[x + y * kW]) {
+ stop = true;
+ }
+ }
}
- if (fboID) {
- GR_GL_CALL(gl, DeleteFramebuffers(1, &fboID));
- }
-
}
}
#endif
@@ -267,37 +237,39 @@
* Note: this needs to be tested separately from checking newImageSnapshot, as calling that
* can also incidentally bump the genID (when a new backing surface is created).
*/
-static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf) {
+template <class F>
+static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf, F f) {
const uint32_t gen0 = get_legacy_gen_id(surf);
- surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
+ f(surf, SkSurface::kFlushRead_BackendHandleAccess);
const uint32_t gen1 = get_legacy_gen_id(surf);
REPORTER_ASSERT(reporter, gen0 == gen1);
- surf->getTextureHandle(SkSurface::kFlushWrite_TextureHandleAccess);
+ f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
const uint32_t gen2 = get_legacy_gen_id(surf);
REPORTER_ASSERT(reporter, gen0 != gen2);
- surf->getTextureHandle(SkSurface::kDiscardWrite_TextureHandleAccess);
+ f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
const uint32_t gen3 = get_legacy_gen_id(surf);
REPORTER_ASSERT(reporter, gen0 != gen3);
REPORTER_ASSERT(reporter, gen2 != gen3);
}
-static void test_texture_handle(skiatest::Reporter* reporter, SkSurface* surf) {
+template <class F>
+static void test_backend_handle(skiatest::Reporter* reporter, SkSurface* surf, F f) {
SkAutoTUnref<SkImage> image0(surf->newImageSnapshot());
- GrBackendObject obj = surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
+ GrBackendObject obj = f(surf, SkSurface::kFlushRead_BackendHandleAccess);
REPORTER_ASSERT(reporter, obj != 0);
SkAutoTUnref<SkImage> image1(surf->newImageSnapshot());
// just read access should not affect the snapshot
REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
- obj = surf->getTextureHandle(SkSurface::kFlushWrite_TextureHandleAccess);
+ obj = f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
REPORTER_ASSERT(reporter, obj != 0);
SkAutoTUnref<SkImage> image2(surf->newImageSnapshot());
// expect a new image, since we claimed we would write
REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
- obj = surf->getTextureHandle(SkSurface::kDiscardWrite_TextureHandleAccess);
+ obj = f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
REPORTER_ASSERT(reporter, obj != 0);
SkAutoTUnref<SkImage> image3(surf->newImageSnapshot());
// expect a new(er) image, since we claimed we would write
@@ -331,9 +303,20 @@
SkAutoTUnref<SkSurface> surf(
SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
surf->getCanvas()->clear(color);
- // test our backing texture while were here...
- test_texture_handle_genID(reporter, surf);
- test_texture_handle(reporter, surf);
+ // test our backing texture / rendertarget while were here...
+ auto textureAccessorFunc =
+ [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
+ return surf->getTextureHandle(access); };
+ auto renderTargetAccessorFunc =
+ [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
+ GrBackendObject obj;
+ SkAssertResult(surf->getRenderTargetHandle(&obj, access));
+ return obj; };
+ test_backend_handle(reporter, surf, textureAccessorFunc);
+ test_backend_handle(reporter, surf, renderTargetAccessorFunc);
+ test_texture_handle_genID(reporter, surf, textureAccessorFunc);
+ test_texture_handle_genID(reporter, surf, renderTargetAccessorFunc);
+
// redraw so our returned image looks as expected.
surf->getCanvas()->clear(color);
return surf->newImageSnapshot();
@@ -912,7 +895,7 @@
TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
test_empty_surface(reporter, context);
test_surface_budget(reporter, context);
- test_wrapped_surface(reporter, context);
+ test_wrapped_texture_surface(reporter, context);
}
}
}