aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-15 13:51:00 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-15 13:51:00 +0000
commiteb85117c05471e1a55ce387cbc38279f857a4584 (patch)
tree76ea39395f668d66cb6128bad10b8cf56dc7cad7
parentab38e560e922b554ea9fa98adc4f79aee7eca8ba (diff)
Add support for using glCopyTexSubImage2D when possible to copy surfaces.
Review URL: https://codereview.chromium.org/13915011 git-svn-id: http://skia.googlecode.com/svn/trunk@8675 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--src/gpu/GrDrawTarget.cpp13
-rw-r--r--src/gpu/GrDrawTarget.h8
-rw-r--r--src/gpu/GrInOrderDrawBuffer.cpp4
-rw-r--r--src/gpu/GrInOrderDrawBuffer.h3
-rw-r--r--src/gpu/gl/GrGpuGL.cpp207
-rw-r--r--src/gpu/gl/GrGpuGL.h3
6 files changed, 171 insertions, 67 deletions
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 9036a57796..e875f0f93c 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -432,11 +432,9 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
// MSAA consideration: When there is support for reading MSAA samples in the shader we could
// have per-sample dst values by making the copy multisampled.
GrTextureDesc desc;
- desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ this->initCopySurfaceDstDesc(rt, &desc);
desc.fWidth = copyRect.width();
desc.fHeight = copyRect.height();
- desc.fSampleCnt = 0;
- desc.fConfig = rt->config();
GrAutoScratchTexture ast(fContext, desc, GrContext::kApprox_ScratchTexMatch);
@@ -447,7 +445,7 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
SkIPoint dstPoint = {0, 0};
if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) {
info->fDstCopy.setTexture(ast.texture());
- info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
+ info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
return true;
} else {
return false;
@@ -881,6 +879,13 @@ bool GrDrawTarget::onCopySurface(GrSurface* dst,
return true;
}
+void GrDrawTarget::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
+ // Make the dst of the copy be a render target because the default copySurface draws to the dst.
+ desc->fOrigin = kDefault_GrSurfaceOrigin;
+ desc->fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc->fConfig = src->config();
+}
+
///////////////////////////////////////////////////////////////////////////////
SK_DEFINE_INST_COUNT(GrDrawTargetCaps)
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 13abee92d3..8f5f09fd65 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -432,6 +432,14 @@ public:
const SkIPoint& dstPoint);
/**
+ * This is can be called before allocating a texture to be a dst for copySurface. It will
+ * populate the origin, config, and flags fields of the desc such that copySurface is more
+ * likely to succeed and be efficient.
+ */
+ virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc);
+
+
+ /**
* Release any resources that are cached but not currently in use. This
* is intended to give an application some recourse when resources are low.
*/
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 481a39546f..7bd3f5d996 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -540,6 +540,10 @@ bool GrInOrderDrawBuffer::onCanCopySurface(GrSurface* dst,
return fDstGpu->canCopySurface(dst, src, srcRect, dstPoint);
}
+void GrInOrderDrawBuffer::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
+ fDstGpu->initCopySurfaceDstDesc(src, desc);
+}
+
void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(
int vertexCount,
int indexCount) {
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index c365501ba3..6090235263 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -77,6 +77,9 @@ public:
GrColor color,
GrRenderTarget* renderTarget = NULL) SK_OVERRIDE;
+ virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
+
+
protected:
virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 871937728e..0fba75daf2 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -2229,23 +2229,142 @@ void GrGpuGL::setSpareTextureUnit() {
namespace {
// Determines whether glBlitFramebuffer could be used between src and dst.
-inline bool can_blit_framebuffer(const GrSurface* dst, const GrSurface* src, const GrGpuGL* gpu) {
- return gpu->isConfigRenderable(dst->config()) && gpu->isConfigRenderable(src->config()) &&
- (GrGLCaps::kDesktopEXT_MSFBOType == gpu->glCaps().msFBOType() ||
- GrGLCaps::kDesktopARB_MSFBOType == gpu->glCaps().msFBOType());
+inline bool can_blit_framebuffer(const GrSurface* dst,
+ const GrSurface* src,
+ const GrGpuGL* gpu,
+ bool* wouldNeedTempFBO = NULL) {
+ if (gpu->isConfigRenderable(dst->config()) && gpu->isConfigRenderable(src->config()) &&
+ (GrGLCaps::kDesktopEXT_MSFBOType == gpu->glCaps().msFBOType() ||
+ GrGLCaps::kDesktopARB_MSFBOType == gpu->glCaps().msFBOType())) {
+ if (NULL != wouldNeedTempFBO) {
+ *wouldNeedTempFBO = NULL == dst->asRenderTarget() || NULL == src->asRenderTarget();
+ }
+ return true;
+ } else {
+ return false;
+ }
}
+
+inline bool can_copy_texsubimage(const GrSurface* dst,
+ const GrSurface* src,
+ const GrGpuGL* gpu,
+ bool* wouldNeedTempFBO = NULL) {
+ // Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage
+ // and BGRA isn't in the spec. There doesn't appear to be any extension that adds it. Perhaps
+ // many drivers would allow it to work, but ANGLE does not.
+ if (kES2_GrGLBinding == gpu->glBinding() && gpu->glCaps().bgraIsInternalFormat() &&
+ (kBGRA_8888_GrPixelConfig == dst->config() || kBGRA_8888_GrPixelConfig == src->config())) {
+ return false;
+ }
+ const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget());
+ // If dst is multisampled (and uses an extension where there is a separate MSAA renderbuffer)
+ // then we don't want to copy to the texture but to the MSAA buffer.
+ if (NULL != dstRT && dstRT->renderFBOID() != dstRT->textureFBOID()) {
+ return false;
+ }
+ if (gpu->isConfigRenderable(src->config()) && NULL != dst->asTexture() &&
+ dst->origin() == src->origin() && kIndex_8_GrPixelConfig != src->config()) {
+ if (NULL != wouldNeedTempFBO) {
+ *wouldNeedTempFBO = NULL == src->asRenderTarget();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is
+// relative to is output.
+inline GrGLuint bind_surface_as_fbo(const GrGLInterface* gl,
+ GrSurface* surface,
+ GrGLenum fboTarget,
+ GrGLIRect* viewport) {
+ GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
+ GrGLuint tempFBOID;
+ if (NULL == rt) {
+ GrAssert(NULL != surface->asTexture());
+ GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
+ GR_GL_CALL(gl, GenFramebuffers(1, &tempFBOID));
+ GR_GL_CALL(gl, BindFramebuffer(fboTarget, tempFBOID));
+ GR_GL_CALL(gl, FramebufferTexture2D(fboTarget,
+ GR_GL_COLOR_ATTACHMENT0,
+ GR_GL_TEXTURE_2D,
+ texID,
+ 0));
+ viewport->fLeft = 0;
+ viewport->fBottom = 0;
+ viewport->fWidth = surface->width();
+ viewport->fHeight = surface->height();
+ } else {
+ tempFBOID = 0;
+ GR_GL_CALL(gl, BindFramebuffer(fboTarget, rt->renderFBOID()));
+ *viewport = rt->getViewport();
+ }
+ return tempFBOID;
+}
+
+}
+
+void GrGpuGL::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
+ // Check for format issues with glCopyTexSubImage2D
+ if (kES2_GrGLBinding == this->glBinding() && this->glCaps().bgraIsInternalFormat() &&
+ kBGRA_8888_GrPixelConfig == src->config()) {
+ // glCopyTexSubImage2D doesn't work with this config. We'll want to make it a render target
+ // to in order to call glBlitFramebuffer or to copy to it by rendering.
+ INHERITED::initCopySurfaceDstDesc(src, desc);
+ } else if (NULL == src->asRenderTarget()) {
+ // We don't want to have to create an FBO just to use glCopyTexSubImage2D. Let the base
+ // class handle it by rendering.
+ INHERITED::initCopySurfaceDstDesc(src, desc);
+ } else {
+ desc->fConfig = src->config();
+ desc->fOrigin = src->origin();
+ desc->fFlags = kNone_GrTextureFlags;
+ }
}
bool GrGpuGL::onCopySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
- // TODO: Add support for glCopyTexSubImage for cases when src is an FBO and dst is not
- // renderable or we don't have glBlitFramebuffer.
+ bool inheritedCouldCopy = INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
bool copied = false;
- // Check whether both src and dst could be attached to an FBO and we're on a GL that supports
- // glBlitFramebuffer.
- if (can_blit_framebuffer(dst, src, this)) {
+ bool wouldNeedTempFBO = false;
+ if (can_copy_texsubimage(dst, src, this, &wouldNeedTempFBO) &&
+ (!wouldNeedTempFBO || !inheritedCouldCopy)) {
+ GrGLuint srcFBO;
+ GrGLIRect srcVP;
+ srcFBO = bind_surface_as_fbo(this->glInterface(), src, GR_GL_FRAMEBUFFER, &srcVP);
+ GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
+ GrAssert(NULL != dstTex);
+ // We modified the bound FBO
+ fHWBoundRenderTarget = NULL;
+ GrGLIRect srcGLRect;
+ srcGLRect.setRelativeTo(srcVP,
+ srcRect.fLeft,
+ srcRect.fTop,
+ srcRect.width(),
+ srcRect.height(),
+ src->origin());
+
+ this->setSpareTextureUnit();
+ GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID()));
+ GrGLint dstY;
+ if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
+ dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight);
+ } else {
+ dstY = dstPoint.fY;
+ }
+ GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0,
+ dstPoint.fX, dstY,
+ srcGLRect.fLeft, srcGLRect.fBottom,
+ srcGLRect.fWidth, srcGLRect.fHeight));
+ copied = true;
+ if (srcFBO) {
+ GL_CALL(DeleteFramebuffers(1, &srcFBO));
+ }
+ } else if (can_blit_framebuffer(dst, src, this, &wouldNeedTempFBO) &&
+ (!wouldNeedTempFBO || !inheritedCouldCopy)) {
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
srcRect.width(), srcRect.height());
bool selfOverlap = false;
@@ -2254,50 +2373,13 @@ bool GrGpuGL::onCopySurface(GrSurface* dst,
}
if (!selfOverlap) {
- GrGLuint dstFBO = 0;
- GrGLuint srcFBO = 0;
+ GrGLuint dstFBO;
+ GrGLuint srcFBO;
GrGLIRect dstVP;
GrGLIRect srcVP;
- GrGLRenderTarget* dstRT = static_cast<GrGLRenderTarget*>(dst->asRenderTarget());
- GrGLRenderTarget* srcRT = static_cast<GrGLRenderTarget*>(src->asRenderTarget());
- if (NULL == dstRT) {
- GrAssert(NULL != dst->asTexture());
- GrGLuint texID = static_cast<GrGLTexture*>(dst->asTexture())->textureID();
- GL_CALL(GenFramebuffers(1, &dstFBO));
- GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, dstFBO));
- GL_CALL(FramebufferTexture2D(GR_GL_DRAW_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D,
- texID,
- 0));
- dstVP.fLeft = 0;
- dstVP.fBottom = 0;
- dstVP.fWidth = dst->width();
- dstVP.fHeight = dst->height();
- } else {
- GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, dstRT->renderFBOID()));
- dstVP = dstRT->getViewport();
- }
- if (NULL == srcRT) {
- GrAssert(NULL != src->asTexture());
- GrGLuint texID = static_cast<GrGLTexture*>(src->asTexture())->textureID();
- GL_CALL(GenFramebuffers(1, &srcFBO));
- GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, srcFBO));
- GL_CALL(FramebufferTexture2D(GR_GL_READ_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D,
- texID,
- 0));
- srcVP.fLeft = 0;
- srcVP.fBottom = 0;
- srcVP.fWidth = src->width();
- srcVP.fHeight = src->height();
- } else {
- GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, srcRT->renderFBOID()));
- srcVP = srcRT->getViewport();
- }
-
- // We modified the bound FB
+ dstFBO = bind_surface_as_fbo(this->glInterface(), dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP);
+ srcFBO = bind_surface_as_fbo(this->glInterface(), src, GR_GL_READ_FRAMEBUFFER, &srcVP);
+ // We modified the bound FBO
fHWBoundRenderTarget = NULL;
GrGLIRect srcGLRect;
GrGLIRect dstGLRect;
@@ -2349,8 +2431,9 @@ bool GrGpuGL::onCopySurface(GrSurface* dst,
copied = true;
}
}
- if (!copied) {
+ if (!copied && inheritedCouldCopy) {
copied = INHERITED::onCopySurface(dst, src, srcRect, dstPoint);
+ GrAssert(copied);
}
return copied;
}
@@ -2360,21 +2443,21 @@ bool GrGpuGL::onCanCopySurface(GrSurface* dst,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
// This mirrors the logic in onCopySurface.
- bool canBlitFramebuffer = false;
+ if (can_copy_texsubimage(dst, src, this)) {
+ return true;
+ }
if (can_blit_framebuffer(dst, src, this)) {
- SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
- srcRect.width(), srcRect.height());
if (dst->isSameAs(src)) {
- canBlitFramebuffer = !SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect);
+ SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
+ srcRect.width(), srcRect.height());
+ if(!SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) {
+ return true;
+ }
} else {
- canBlitFramebuffer = true;
+ return true;
}
}
- if (canBlitFramebuffer) {
- return true;
- } else {
- return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
- }
+ return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
}
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 4ea4e1210b..0f75280178 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -55,6 +55,8 @@ public:
size_t rowBytes) const SK_OVERRIDE;
virtual bool fullReadPixelsIsFasterThanPartial() const SK_OVERRIDE;
+ virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
+
virtual void abandonResources() SK_OVERRIDE;
const GrGLCaps& glCaps() const { return *fGLContext.info().caps(); }
@@ -96,7 +98,6 @@ protected:
const SkIRect& srcRect,
const SkIPoint& dstPoint) SK_OVERRIDE;
-
private:
// GrGpu overrides
virtual void onResetContext() SK_OVERRIDE;