Chromium Code Reviews| Index: src/gpu/gl/GrGpuGL.cpp |
| =================================================================== |
| --- src/gpu/gl/GrGpuGL.cpp (revision 8655) |
| +++ src/gpu/gl/GrGpuGL.cpp (working copy) |
| @@ -2229,23 +2229,142 @@ |
| 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; |
| + } |
| } |
|
robertphillips
2013/04/15 13:01:08
"its (non-zero) ID is returned"?
bsalomon
2013/04/15 13:51:01
Done.
|
| +// If a temporary FBO was created, its 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)); |
|
robertphillips
2013/04/15 13:01:08
SkIRect::MakeWH?
bsalomon
2013/04/15 13:51:01
It's a GrGLIRect
|
| + 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()) { |
|
robertphillips
2013/04/15 13:01:08
I find the 2nd sentence of this comment a bit conf
bsalomon
2013/04/15 13:51:01
// glCopyTexSubImage2D doesn't work with this conf
|
| + // glCopyTexSubImage2D doesn't work with this config. We'll want to make it a render target |
| + // either or glBlitFramebuffer or let the base class copy 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 @@ |
| } |
| 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 @@ |
| copied = true; |
| } |
| } |
| - if (!copied) { |
| + if (!copied && inheritedCouldCopy) { |
| copied = INHERITED::onCopySurface(dst, src, srcRect, dstPoint); |
| + GrAssert(copied); |
| } |
| return copied; |
| } |
| @@ -2360,21 +2443,21 @@ |
| 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); |
| } |