Add SkSurface factory for wrapping an FBO in SkSurface
Review URL: https://codereview.chromium.org/1221853003
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 5d08ee6..5860cf2 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -88,11 +88,27 @@
}
/**
- * Used to wrap a pre-existing backend 3D API texture in a SkSurface. The kRenderTarget flag
- * must be set on GrBackendTextureDesc for this to succeed.
+ * Used to wrap a pre-existing backend 3D API texture as a SkSurface. The kRenderTarget flag
+ * must be set on GrBackendTextureDesc for this to succeed. Skia will not assume ownership
+ * of the texture and the client must ensure the texture is valid for the lifetime of the
+ * SkSurface.
*/
- static SkSurface* NewWrappedRenderTarget(GrContext*, GrBackendTextureDesc,
- const SkSurfaceProps*);
+ static SkSurface* NewFromBackendTexture(GrContext*, const GrBackendTextureDesc&,
+ const SkSurfaceProps*);
+ // Legacy alias
+ static SkSurface* NewWrappedRenderTarget(GrContext* ctx, const GrBackendTextureDesc& desc,
+ const SkSurfaceProps* props) {
+ return NewFromBackendTexture(ctx, desc, props);
+ }
+
+
+ /**
+ * Used to wrap a pre-existing 3D API rendering target as a SkSurface. Skia will not assume
+ * ownership of the render target and the client must ensure the render target is valid for the
+ * lifetime of the SkSurface.
+ */
+ static SkSurface* NewFromBackendRenderTarget(GrContext*, const GrBackendRenderTargetDesc&,
+ const SkSurfaceProps*);
/**
* Return a new surface whose contents will be drawn to an offscreen
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 34035a3..35409be 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -192,9 +192,14 @@
return NULL;
}
-SkSurface* SkSurface::NewWrappedRenderTarget(GrContext*, GrBackendTextureDesc,
+SkSurface* SkSurface::NewFromBackendTexture(GrContext*, const GrBackendTextureDesc&,
const SkSurfaceProps*) {
return NULL;
}
+SkSurface* SkSurface::NewFromBackendRenderTarget(GrContext*, const GrBackendRenderTargetDesc&,
+ const SkSurfaceProps*) {
+ return NULL;
+}
+
#endif
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index d243b65..70866d3 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -116,8 +116,8 @@
return SkNEW_ARGS(SkSurface_Gpu, (device));
}
-SkSurface* SkSurface::NewWrappedRenderTarget(GrContext* context, GrBackendTextureDesc desc,
- const SkSurfaceProps* props) {
+SkSurface* SkSurface::NewFromBackendTexture(GrContext* context, const GrBackendTextureDesc& desc,
+ const SkSurfaceProps* props) {
if (NULL == context) {
return NULL;
}
@@ -137,4 +137,22 @@
return SkNEW_ARGS(SkSurface_Gpu, (device));
}
+SkSurface* SkSurface::NewFromBackendRenderTarget(GrContext* context,
+ const GrBackendRenderTargetDesc& desc,
+ const SkSurfaceProps* props) {
+ if (NULL == context) {
+ return NULL;
+ }
+ SkAutoTUnref<GrRenderTarget> rt(context->textureProvider()->wrapBackendRenderTarget(desc));
+ if (!rt) {
+ return NULL;
+ }
+ SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(rt, props,
+ SkGpuDevice::kUninit_InitContents));
+ if (!device) {
+ return NULL;
+ }
+ return SkNEW_ARGS(SkSurface_Gpu, (device));
+}
+
#endif
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 42f4fcc..43ce203 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -102,7 +102,7 @@
}
#if SK_SUPPORT_GPU
-static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
+static void test_wrapped_surface(skiatest::Reporter* reporter, GrContext* ctx) {
if (NULL == ctx) {
return;
}
@@ -120,77 +120,107 @@
return;
}
- // 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()));
+ 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()));
- 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;
+ 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;
- 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;
+ 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;
+ }
}
}
}
- 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 (texID) {
+ GR_GL_CALL(gl, DeleteTextures(1, &texID));
}
+ if (fboID) {
+ GR_GL_CALL(gl, DeleteFramebuffers(1, &fboID));
+ }
+
}
}
#endif
@@ -837,7 +867,7 @@
TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
test_empty_surface(reporter, context);
test_surface_budget(reporter, context);
- test_wrapped_texture_surface(reporter, context);
+ test_wrapped_surface(reporter, context);
}
}
}