aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/mixedxfermodes.cpp8
-rw-r--r--src/gpu/GrDrawTarget.cpp13
-rw-r--r--src/gpu/gl/GrGLIRect.h2
-rw-r--r--src/gpu/gl/GrGpuGL.cpp151
-rw-r--r--src/gpu/gl/GrGpuGL.h12
5 files changed, 166 insertions, 20 deletions
diff --git a/gm/mixedxfermodes.cpp b/gm/mixedxfermodes.cpp
index beb5d5410e..c0045f84ae 100644
--- a/gm/mixedxfermodes.cpp
+++ b/gm/mixedxfermodes.cpp
@@ -45,12 +45,6 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- // FIXME: Currently necessary for GPU to be able to make dst-copy in SampleApp because
- // main layer is not a texture.
- SkPaint layerPaint;
- layerPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
- canvas->saveLayer(NULL, &layerPaint);
-
SkPaint bgPaint;
bgPaint.setShader(fBG.get());
canvas->drawPaint(bgPaint);
@@ -86,8 +80,6 @@ protected:
areaSqrt/50,
SkIntToScalar(size.fHeight / 2),
txtPaint);
-
- canvas->restore();
}
private:
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index d07d625865..9036a57796 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -411,12 +411,6 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
return true;
}
GrRenderTarget* rt = this->drawState()->getRenderTarget();
- // If the dst is not a texture then we don't currently have a way of copying the
- // texture. TODO: API-specific impl of onCopySurface that can handle more cases.
- if (NULL == rt->asTexture()) {
- GrPrintf("Reading Dst of non-texture render target is not currently supported.\n");
- return false;
- }
const GrClipData* clip = this->getClip();
GrIRect copyRect;
@@ -435,11 +429,8 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
#endif
}
- // The draw will resolve dst if it has MSAA. Two things to consider in the future:
- // 1) to make the dst values be pre-resolve we'd need to be able to copy to MSAA
- // texture and sample it correctly in the shader. 2) If 1 isn't available then we
- // should just resolve and use the resolved texture directly rather than making a
- // copy of it.
+ // 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;
desc.fWidth = copyRect.width();
diff --git a/src/gpu/gl/GrGLIRect.h b/src/gpu/gl/GrGLIRect.h
index cbc4cb89f6..f171cf1374 100644
--- a/src/gpu/gl/GrGLIRect.h
+++ b/src/gpu/gl/GrGLIRect.h
@@ -36,7 +36,7 @@ struct GrGLIRect {
GR_GL_GetIntegerv(gl, GR_GL_VIEWPORT, (GrGLint*) this);
}
- // sometimes we have a GrIRect from the client that we
+ // sometimes we have a SkIRect from the client that we
// want to simultaneously make relative to GL's viewport
// and (optionally) convert from top-down to bottom-up.
void setRelativeTo(const GrGLIRect& glRect,
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index d2996564f3..871937728e 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -2227,6 +2227,157 @@ 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());
+}
+}
+
+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(
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index a71ff39e52..4ea4e1210b 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -85,6 +85,18 @@ public:
void notifyTextureDelete(GrGLTexture* texture);
void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
+protected:
+ virtual bool onCopySurface(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint) SK_OVERRIDE;
+
+ virtual bool onCanCopySurface(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint) SK_OVERRIDE;
+
+
private:
// GrGpu overrides
virtual void onResetContext() SK_OVERRIDE;