Add discard API to SkCanvas, plumb it to glDiscardFramebuffer()


BUG=skia:2349
R=robertphillips@google.com, reed@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/211683002

git-svn-id: http://skia.googlecode.com/svn/trunk@13976 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 3a2bbe8..c26327e 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -1440,6 +1440,14 @@
     fGpu->resolveRenderTarget(target);
 }
 
+void GrContext::discardRenderTarget(GrRenderTarget* target) {
+    SkASSERT(target);
+    ASSERT_OWNED_RESOURCE(target);
+    AutoRestoreEffects are;
+    AutoCheckFlush acf(this);
+    this->prepareToDraw(NULL, BUFFERED_DRAW, &are, &acf)->discard(target);
+}
+
 void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft) {
     if (NULL == src || NULL == dst) {
         return;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 8d3ded2..1069844 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -1019,6 +1019,7 @@
     fBufferLockSupport = false;
     fPathRenderingSupport = false;
     fDstReadInShaderSupport = false;
+    fDiscardRenderTargetSupport = false;
     fReuseScratchTextures = true;
     fGpuTracingSupport = false;
 
@@ -1042,6 +1043,7 @@
     fBufferLockSupport = other.fBufferLockSupport;
     fPathRenderingSupport = other.fPathRenderingSupport;
     fDstReadInShaderSupport = other.fDstReadInShaderSupport;
+    fDiscardRenderTargetSupport = other.fDiscardRenderTargetSupport;
     fReuseScratchTextures = other.fReuseScratchTextures;
     fGpuTracingSupport = other.fGpuTracingSupport;
 
@@ -1057,23 +1059,24 @@
 SkString GrDrawTargetCaps::dump() const {
     SkString r;
     static const char* gNY[] = {"NO", "YES"};
-    r.appendf("8 Bit Palette Support       : %s\n", gNY[f8BitPaletteSupport]);
-    r.appendf("MIP Map Support             : %s\n", gNY[fMipMapSupport]);
-    r.appendf("NPOT Texture Tile Support   : %s\n", gNY[fNPOTTextureTileSupport]);
-    r.appendf("Two Sided Stencil Support   : %s\n", gNY[fTwoSidedStencilSupport]);
-    r.appendf("Stencil Wrap Ops  Support   : %s\n", gNY[fStencilWrapOpsSupport]);
-    r.appendf("HW AA Lines Support         : %s\n", gNY[fHWAALineSupport]);
-    r.appendf("Shader Derivative Support   : %s\n", gNY[fShaderDerivativeSupport]);
-    r.appendf("Geometry Shader Support     : %s\n", gNY[fGeometryShaderSupport]);
-    r.appendf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]);
-    r.appendf("Buffer Lock Support         : %s\n", gNY[fBufferLockSupport]);
-    r.appendf("Path Rendering Support      : %s\n", gNY[fPathRenderingSupport]);
-    r.appendf("Dst Read In Shader Support  : %s\n", gNY[fDstReadInShaderSupport]);
-    r.appendf("Reuse Scratch Textures      : %s\n", gNY[fReuseScratchTextures]);
-    r.appendf("Gpu Tracing Support         : %s\n", gNY[fGpuTracingSupport]);
-    r.appendf("Max Texture Size            : %d\n", fMaxTextureSize);
-    r.appendf("Max Render Target Size      : %d\n", fMaxRenderTargetSize);
-    r.appendf("Max Sample Count            : %d\n", fMaxSampleCount);
+    r.appendf("8 Bit Palette Support        : %s\n", gNY[f8BitPaletteSupport]);
+    r.appendf("MIP Map Support              : %s\n", gNY[fMipMapSupport]);
+    r.appendf("NPOT Texture Tile Support    : %s\n", gNY[fNPOTTextureTileSupport]);
+    r.appendf("Two Sided Stencil Support    : %s\n", gNY[fTwoSidedStencilSupport]);
+    r.appendf("Stencil Wrap Ops  Support    : %s\n", gNY[fStencilWrapOpsSupport]);
+    r.appendf("HW AA Lines Support          : %s\n", gNY[fHWAALineSupport]);
+    r.appendf("Shader Derivative Support    : %s\n", gNY[fShaderDerivativeSupport]);
+    r.appendf("Geometry Shader Support      : %s\n", gNY[fGeometryShaderSupport]);
+    r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]);
+    r.appendf("Buffer Lock Support          : %s\n", gNY[fBufferLockSupport]);
+    r.appendf("Path Rendering Support       : %s\n", gNY[fPathRenderingSupport]);
+    r.appendf("Dst Read In Shader Support   : %s\n", gNY[fDstReadInShaderSupport]);
+    r.appendf("Discard Render Target Support: %s\n", gNY[fDiscardRenderTargetSupport]);
+    r.appendf("Reuse Scratch Textures       : %s\n", gNY[fReuseScratchTextures]);
+    r.appendf("Gpu Tracing Support          : %s\n", gNY[fGpuTracingSupport]);
+    r.appendf("Max Texture Size             : %d\n", fMaxTextureSize);
+    r.appendf("Max Render Target Size       : %d\n", fMaxRenderTargetSize);
+    r.appendf("Max Sample Count             : %d\n", fMaxSampleCount);
 
     static const char* kConfigNames[] = {
         "Unknown",  // kUnknown_GrPixelConfig
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 5b26ff5..6b3d463 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -438,6 +438,12 @@
                        GrRenderTarget* renderTarget = NULL) = 0;
 
     /**
+     * Discards the contents render target. NULL indicates that the current render target should
+     * be discarded.
+     **/
+    virtual void discard(GrRenderTarget* = NULL) = 0;
+
+    /**
      * Called at start and end of gpu trace marking
      * GR_CREATE_GPU_TRACE_MARKER(marker_str, target) will automatically call these at the start
      * and end of a code block respectively
diff --git a/src/gpu/GrDrawTargetCaps.h b/src/gpu/GrDrawTargetCaps.h
index b33217a..a77bce4 100644
--- a/src/gpu/GrDrawTargetCaps.h
+++ b/src/gpu/GrDrawTargetCaps.h
@@ -40,6 +40,7 @@
     bool bufferLockSupport() const { return fBufferLockSupport; }
     bool pathRenderingSupport() const { return fPathRenderingSupport; }
     bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; }
+    bool discardRenderTargetSupport() const { return fDiscardRenderTargetSupport; }
     bool gpuTracingSupport() const { return fGpuTracingSupport; }
 
     // Scratch textures not being reused means that those scratch textures
@@ -71,6 +72,7 @@
     bool fBufferLockSupport         : 1;
     bool fPathRenderingSupport      : 1;
     bool fDstReadInShaderSupport    : 1;
+    bool fDiscardRenderTargetSupport: 1;
     bool fReuseScratchTextures      : 1;
     bool fGpuTracingSupport         : 1;
 
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 178df75..8d34e6c 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -504,6 +504,7 @@
         rect = &r;
     }
     Clear* clr = this->recordClear();
+    GrColorIsPMAssert(color);
     clr->fColor = color;
     clr->fRect = *rect;
     clr->fCanIgnoreRect = canIgnoreRect;
@@ -511,6 +512,20 @@
     renderTarget->ref();
 }
 
+void GrInOrderDrawBuffer::discard(GrRenderTarget* renderTarget) {
+    if (!this->caps()->discardRenderTargetSupport()) {
+        return;
+    }
+    if (NULL == renderTarget) {
+        renderTarget = this->drawState()->getRenderTarget();
+        SkASSERT(NULL != renderTarget);
+    }
+    Clear* clr = this->recordClear();
+    clr->fColor = GrColor_ILLEGAL;
+    clr->fRenderTarget = renderTarget;
+    renderTarget->ref();
+}
+
 void GrInOrderDrawBuffer::reset() {
     SkASSERT(1 == fGeoPoolStateStack.count());
     this->resetVertexSource();
@@ -630,10 +645,14 @@
                 ++currClip;
                 break;
             case kClear_Cmd:
-                fDstGpu->clear(&fClears[currClear].fRect,
-                               fClears[currClear].fColor,
-                               fClears[currClear].fCanIgnoreRect,
-                               fClears[currClear].fRenderTarget);
+                if (GrColor_ILLEGAL == fClears[currClear].fColor) {
+                    fDstGpu->discard(fClears[currClear].fRenderTarget);
+                } else {
+                    fDstGpu->clear(&fClears[currClear].fRect,
+                                   fClears[currClear].fColor,
+                                   fClears[currClear].fCanIgnoreRect,
+                                   fClears[currClear].fRenderTarget);
+                }
                 ++currClear;
                 break;
             case kCopySurface_Cmd:
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 72d0f96..0e0c57d 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -72,7 +72,9 @@
     virtual void clear(const SkIRect* rect,
                        GrColor color,
                        bool canIgnoreRect,
-                       GrRenderTarget* renderTarget = NULL) SK_OVERRIDE;
+                       GrRenderTarget* renderTarget) SK_OVERRIDE;
+
+    virtual void discard(GrRenderTarget*) SK_OVERRIDE;
 
     virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
 
@@ -125,6 +127,7 @@
         GrDeviceCoordTexture fDstCopy;
     };
 
+    // This is also used to record a discard by setting the color to GrColor_ILLEGAL
     struct Clear : public ::SkNoncopyable {
         Clear() : fRenderTarget(NULL) {}
         ~Clear() { SkSafeUnref(fRenderTarget); }
diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp
index f18df2c..729aa0d 100644
--- a/src/gpu/GrRenderTarget.cpp
+++ b/src/gpu/GrRenderTarget.cpp
@@ -54,6 +54,15 @@
     context->resolveRenderTarget(this);
 }
 
+void GrRenderTarget::discard() {
+    // go through context so that all necessary flushing occurs
+    GrContext* context = this->getContext();
+    if (NULL == context) {
+        return;
+    }
+    context->discardRenderTarget(this);
+}
+
 size_t GrRenderTarget::sizeInBytes() const {
     size_t colorBits;
     if (kUnknown_GrPixelConfig == fDesc.fConfig) {
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 47f3f0f..bf7939c 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -45,7 +45,6 @@
     fUseNonVBOVertexAndIndexDynamicData = false;
     fIsCoreProfile = false;
     fFixedFunctionSupport = false;
-    fDiscardFBSupport = false;
     fFullClearIsFree = false;
     fDropsTileOnZeroDivide = false;
 }
@@ -83,7 +82,6 @@
     fUseNonVBOVertexAndIndexDynamicData = caps.fUseNonVBOVertexAndIndexDynamicData;
     fIsCoreProfile = caps.fIsCoreProfile;
     fFixedFunctionSupport = caps.fFixedFunctionSupport;
-    fDiscardFBSupport = caps.fDiscardFBSupport;
     fFullClearIsFree = caps.fFullClearIsFree;
     fDropsTileOnZeroDivide = caps.fDropsTileOnZeroDivide;
 
@@ -224,7 +222,7 @@
         fUseNonVBOVertexAndIndexDynamicData = true;
     }
 
-    fDiscardFBSupport = ctxInfo.hasExtension("GL_EXT_discard_framebuffer");
+    fDiscardRenderTargetSupport = ctxInfo.hasExtension("GL_EXT_discard_framebuffer");
 
     if (kARM_GrGLVendor == ctxInfo.vendor() || kImagination_GrGLVendor == ctxInfo.vendor()) {
         fFullClearIsFree = true;
@@ -664,7 +662,6 @@
     r.appendf("Vertex array object support: %s\n", (fVertexArrayObjectSupport ? "YES": "NO"));
     r.appendf("Use non-VBO for dynamic data: %s\n",
              (fUseNonVBOVertexAndIndexDynamicData ? "YES" : "NO"));
-    r.appendf("Discard FrameBuffer support: %s\n", (fDiscardFBSupport ? "YES" : "NO"));
     r.appendf("Full screen clear is free: %s\n", (fFullClearIsFree ? "YES" : "NO"));
     r.appendf("Drops tile on zero divide: %s\n", (fDropsTileOnZeroDivide ? "YES" : "NO"));
     return r;
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 0939f80..21176d1 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -245,9 +245,6 @@
 
     bool fixedFunctionSupport() const { return fFixedFunctionSupport; }
 
-    /// Is there support for discarding the frame buffer
-    bool discardFBSupport() const { return fDiscardFBSupport; }
-
     bool fullClearIsFree() const { return fFullClearIsFree; }
 
     bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; }
@@ -332,7 +329,6 @@
     bool fUseNonVBOVertexAndIndexDynamicData : 1;
     bool fIsCoreProfile : 1;
     bool fFixedFunctionSupport : 1;
-    bool fDiscardFBSupport : 1;
     bool fFullClearIsFree : 1;
     bool fDropsTileOnZeroDivide : 1;
 
diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h
index 0dbd425..a4dc2f7 100644
--- a/src/gpu/gl/GrGLDefines.h
+++ b/src/gpu/gl/GrGLDefines.h
@@ -691,6 +691,11 @@
 #define GR_GL_DEPTH_ATTACHMENT               0x8D00
 #define GR_GL_STENCIL_ATTACHMENT             0x8D20
 
+// GL_EXT_discard_framebuffer
+#define GR_GL_COLOR                          0x1800
+#define GR_GL_DEPTH                          0x1801
+#define GR_GL_STENCIL                        0x1802
+
 #define GR_GL_NONE                           0
 
 #define GR_GL_FRAMEBUFFER_COMPLETE                      0x8CD5
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index dc2ef7d..78bf8f9 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1295,6 +1295,25 @@
     GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
 }
 
+void GrGpuGL::discard(GrRenderTarget* renderTarget) {
+    if (NULL == renderTarget) {
+        renderTarget = this->drawState()->getRenderTarget();
+        if (NULL == renderTarget) {
+            return;
+        }
+    }
+
+    GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget);
+    if (renderTarget != fHWBoundRenderTarget) {
+        fHWBoundRenderTarget = NULL;
+        GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRT->renderFBOID()));
+    }
+    GrGLenum attachments[] = { GR_GL_COLOR };
+    GL_CALL(DiscardFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), attachments));
+    renderTarget->flagAsResolved();
+}
+
+
 void GrGpuGL::clearStencil() {
     if (NULL == this->getDrawState().getRenderTarget()) {
         return;
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 6a89575..e173aef 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -40,6 +40,8 @@
     GrGLSLGeneration glslGeneration() const { return fGLContext.glslGeneration(); }
     const GrGLCaps& glCaps() const { return *fGLContext.caps(); }
 
+    virtual void discard(GrRenderTarget*) SK_OVERRIDE;
+
     // Used by GrGLProgram and GrGLTexGenProgramEffects to configure OpenGL state.
     void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture);
     void setProjectionMatrix(const SkMatrix& matrix,