Add SkSurface factory for wrapping an FBO in SkSurface

Review URL: https://codereview.chromium.org/1221853003
This commit is contained in:
bsalomon 2015-06-30 12:04:40 -07:00 committed by Commit bot
parent c49e8682ab
commit d3e259a16c
4 changed files with 143 additions and 74 deletions

View File

@ -88,11 +88,27 @@ public:
}
/**
* 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

View File

@ -192,9 +192,14 @@ SkSurface* SkSurface::NewRenderTarget(GrContext*, Budgeted, const SkImageInfo&,
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

View File

@ -116,8 +116,8 @@ SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, Budgeted budgeted, const S
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 @@ SkSurface* SkSurface::NewWrappedRenderTarget(GrContext* context, GrBackendTextur
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

View File

@ -102,7 +102,7 @@ static void test_empty_surface(skiatest::Reporter* reporter, GrContext* ctx) {
}
#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 @@ static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext
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 @@ DEF_GPUTEST(Surface, reporter, factory) {
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);
}
}
}