Index: src/gpu/gl/GrGpuGL.cpp |
=================================================================== |
--- src/gpu/gl/GrGpuGL.cpp (revision 8613) |
+++ src/gpu/gl/GrGpuGL.cpp (working copy) |
@@ -2227,6 +2227,157 @@ |
} |
} |
+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()); |
+} |
+} |
+ |
+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 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)) { |
+ SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, |
+ srcRect.width(), srcRect.height()); |
+ bool selfOverlap = false; |
+ if (dst->isSameAs(src)) { |
+ selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect); |
+ } |
+ |
+ if (!selfOverlap) { |
+ GrGLuint dstFBO = 0; |
+ GrGLuint srcFBO = 0; |
+ 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 |
+ fHWBoundRenderTarget = NULL; |
+ GrGLIRect srcGLRect; |
+ GrGLIRect dstGLRect; |
+ srcGLRect.setRelativeTo(srcVP, |
+ srcRect.fLeft, |
+ srcRect.fTop, |
+ srcRect.width(), |
+ srcRect.height(), |
+ src->origin()); |
+ dstGLRect.setRelativeTo(dstVP, |
+ dstRect.fLeft, |
+ dstRect.fTop, |
+ dstRect.width(), |
+ dstRect.height(), |
+ dst->origin()); |
+ |
+ GrAutoTRestore<ScissorState> asr; |
+ if (GrGLCaps::kDesktopEXT_MSFBOType == this->glCaps().msFBOType()) { |
+ // The EXT version applies the scissor during the blit, so disable it. |
+ asr.reset(&fScissorState); |
+ fScissorState.fEnabled = false; |
+ this->flushScissor(); |
+ } |
+ GrGLint srcY0; |
+ GrGLint srcY1; |
+ // Does the blit need to y-mirror or not? |
+ if (src->origin() == dst->origin()) { |
+ srcY0 = srcGLRect.fBottom; |
+ srcY1 = srcGLRect.fBottom + srcGLRect.fHeight; |
+ } else { |
+ srcY0 = srcGLRect.fBottom + srcGLRect.fHeight; |
+ srcY1 = srcGLRect.fBottom; |
+ } |
+ GL_CALL(BlitFramebuffer(srcGLRect.fLeft, |
+ srcY0, |
+ srcGLRect.fLeft + srcGLRect.fWidth, |
+ srcY1, |
+ dstGLRect.fLeft, |
+ dstGLRect.fBottom, |
+ dstGLRect.fLeft + dstGLRect.fWidth, |
+ dstGLRect.fBottom + dstGLRect.fHeight, |
+ GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); |
+ if (dstFBO) { |
+ GL_CALL(DeleteFramebuffers(1, &dstFBO)); |
+ } |
+ if (srcFBO) { |
+ GL_CALL(DeleteFramebuffers(1, &srcFBO)); |
+ } |
+ copied = true; |
+ } |
+ } |
+ if (!copied) { |
+ copied = INHERITED::onCopySurface(dst, src, srcRect, dstPoint); |
+ } |
+ return copied; |
+} |
+ |
+bool GrGpuGL::onCanCopySurface(GrSurface* dst, |
+ GrSurface* src, |
+ const SkIRect& srcRect, |
+ const SkIPoint& dstPoint) { |
+ // This mirrors the logic in onCopySurface. |
+ bool canBlitFramebuffer = false; |
+ 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); |
+ } else { |
+ canBlitFramebuffer = true; |
+ } |
+ } |
+ if (canBlitFramebuffer) { |
+ return true; |
+ } else { |
+ return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint); |
+ } |
+} |
+ |
+ |
/////////////////////////////////////////////////////////////////////////////// |
GrGLAttribArrayState* GrGpuGL::HWGeometryState::bindArrayAndBuffersToDraw( |