SSSA for drawVerts, cleanup determination of when stage is enabled


Review URL: http://codereview.appspot.com/4430066/



git-svn-id: http://skia.googlecode.com/svn/trunk@1195 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index 495eff4..3112112 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -619,6 +619,8 @@
 
     // sets up target to sample coverage of supersampled render target back
     // to the main render target using stage kOffscreenStage.
+    // caller should set view matrix to matrix used for this pass prior to 
+    // calling.
     void setupOffscreenAAPass2(GrDrawTarget* target,
                                const GrPaint& paint,
                                OffscreenRecord* record);
diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h
index fdcb2b1..b0faa2c 100644
--- a/gpu/include/GrContext_impl.h
+++ b/gpu/include/GrContext_impl.h
@@ -17,6 +17,14 @@
 #ifndef GrContext_impl_DEFINED
 #define GrContext_impl_DEFINED
 
+struct GrContext::OffscreenRecord {
+    OffscreenRecord() { fEntry = NULL; }
+    ~OffscreenRecord() { GrAssert(NULL == fEntry); }
+
+    GrTextureEntry*                fEntry;
+    GrDrawTarget::SavedDrawState   fSavedState;
+};
+
 template <typename POS_SRC, typename TEX_SRC,
           typename COL_SRC, typename IDX_SRC>
 inline void GrContext::drawCustomVertices(const GrPaint& paint,
@@ -44,6 +52,16 @@
         layout |= GrDrawTarget::kColor_VertexLayoutBit;
     }
 
+    bool doOffscreenAA = false;
+    OffscreenRecord record;
+    if (paint.fAntiAlias &&
+        !this->getRenderTarget()->isMultisampled() &&
+        !(GrIsPrimTypeLines(primitiveType) && fGpu->supportsAALines()) &&
+        this->setupOffscreenAAPass1(target, false, &record)) {
+        doOffscreenAA = true;
+        layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(kOffscreenStage);
+    }
+
     int vertexCount = posSrc.count();
     int indexCount = (NULL != idxSrc) ? idxSrc->count() : 0;
 
@@ -81,6 +99,47 @@
     } else {
         target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
     }
+
+    if (doOffscreenAA) {
+        // draw to the offscreen
+        if (NULL != indices) {
+            target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+        } else {
+            target->drawNonIndexed(primitiveType, 0, vertexCount);
+        }
+        // When there are custom texture coordinates we can't just draw
+        // a quad to sample the offscreen. Instead we redraw the geometry to
+        // specify the texture coords. This isn't quite right either, primitives
+        // will only be eroded at the edges, not expanded into partial pixels.
+        bool useRect = 0 == (layout & GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));
+        if (useRect) {
+            target->setViewMatrix(GrMatrix::I());
+        }
+        this->setupOffscreenAAPass2(target, paint, &record);
+        if (useRect) {
+            geo.set(NULL, 0, 0, 0);
+            int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
+            stages |= (1 << kOffscreenStage);
+            GrRect dstRect(0, 0, 
+                        target->getRenderTarget()->width(),
+                        target->getRenderTarget()->height());
+                        target->drawSimpleRect(dstRect, NULL, stages);
+            target->drawSimpleRect(dstRect, NULL, stages);
+        } else {
+            if (NULL != indices) {
+                target->drawIndexed (primitiveType, 0, 0, vertexCount, indexCount);
+            } else {
+                target->drawNonIndexed(primitiveType, 0, vertexCount);
+            }
+        }
+        this->endOffscreenAA(target, &record);
+    } else {
+        if (NULL != indices) {
+            target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+        } else {
+            target->drawNonIndexed(primitiveType, 0, vertexCount);
+        }
+    }
 }
 
 class GrNullTexCoordSource {
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index e021a93..cb36d3c 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -797,20 +797,16 @@
                             GrVertexLayout vertexLayout,
                             uint32_t       vertexCount,
                             uint32_t       indexCount) {
-            fTarget = target;
-            fSuccess = fTarget->reserveAndLockGeometry(vertexLayout,
-                                                       vertexCount,
-                                                       indexCount,
-                                                       &fVertices,
-                                                       &fIndices);
+            fTarget = NULL;
+            this->set(target, vertexLayout, vertexCount, indexCount);
         }
 
         AutoReleaseGeometry() {
-            fSuccess = false;
+            fTarget = NULL;
         }
 
         ~AutoReleaseGeometry() {
-            if (fSuccess) {
+            if (NULL != fTarget) {
                 fTarget->releaseReservedGeometry();
             }
         }
@@ -819,19 +815,23 @@
                  GrVertexLayout vertexLayout,
                  uint32_t       vertexCount,
                  uint32_t       indexCount) {
-            if (fSuccess) {
+            if (NULL != fTarget) {
                 fTarget->releaseReservedGeometry();
             }
             fTarget = target;
-            fSuccess = fTarget->reserveAndLockGeometry(vertexLayout,
-                                                       vertexCount,
-                                                       indexCount,
-                                                       &fVertices,
-                                                       &fIndices);
-            return fSuccess;
+            if (NULL != fTarget) {
+                if (!fTarget->reserveAndLockGeometry(vertexLayout,
+                                                     vertexCount,
+                                                     indexCount,
+                                                     &fVertices,
+                                                     &fIndices)) {
+                    fTarget = NULL;
+                }
+            }
+            return NULL != fTarget;
         }
 
-        bool succeeded() const { return fSuccess; }
+        bool succeeded() const { return NULL != fTarget; }
         void* vertices() const { return fVertices; }
         void* indices() const { return fIndices; }
 
@@ -841,7 +841,6 @@
 
     private:
         GrDrawTarget* fTarget;
-        bool          fSuccess;
         void*         fVertices;
         void*         fIndices;
     };
@@ -1020,6 +1019,15 @@
     static void VertexLayoutUnitTest();
 
 protected:
+    // given a vertex layout and a draw state, will a stage be used?
+    static bool StageWillBeUsed(int stage, GrVertexLayout layout, 
+                         const DrState& state) {
+        return NULL != state.fTextures[stage] && VertexUsesStage(stage, layout);
+    }
+
+    bool isStageEnabled(int stage) const {
+        return StageWillBeUsed(stage, fGeometrySrc.fVertexLayout, fCurrDrawState);
+    }
 
     // Helpers for GrDrawTarget subclasses that won't have private access to
     // SavedDrawState but need to peek at the state values.
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 8acb3dc..0584e4b 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -416,14 +416,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-struct GrContext::OffscreenRecord {
-    OffscreenRecord() { fEntry = NULL; }
-    ~OffscreenRecord() { GrAssert(NULL == fEntry); }
-
-    GrTextureEntry*                fEntry;
-    GrDrawTarget::SavedDrawState   fSavedState;
-};
-
 bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
                                       bool requireStencil,
                                       OffscreenRecord* record) {
@@ -484,17 +476,16 @@
 
     target->restoreDrawState(record->fSavedState);
 
-    target->setViewMatrix(GrMatrix::I());
     target->setTexture(kOffscreenStage, offscreen);
-    GrMatrix scaleM;
-
-    scaleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(),
-                    GR_Scalar1 / target->getRenderTarget()->height());
+    GrMatrix sampleM;
+    sampleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(),
+                     GR_Scalar1 / target->getRenderTarget()->height());
+    sampleM.preConcat(target->getViewMatrix());
 
     // use bilinear filtering to get downsample
     GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, 
                            GrSamplerState::kClamp_WrapMode,
-                           scaleM, true);
+                           sampleM, true);
     target->setSamplerState(kOffscreenStage, sampler);
 }
 
@@ -955,6 +946,16 @@
         vertexSize += sizeof(GrColor);
     }
 
+    bool doOffscreenAA = false;
+    OffscreenRecord record;
+    if (paint.fAntiAlias &&
+        !this->getRenderTarget()->isMultisampled() &&
+        !(GrIsPrimTypeLines(primitiveType) && fGpu->supportsAALines()) &&
+        this->setupOffscreenAAPass1(target, false, &record)) {
+        doOffscreenAA = true;
+        layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(kOffscreenStage);
+    }
+
     if (sizeof(GrPoint) != vertexSize) {
         if (!geo.set(target, layout, vertexCount, 0)) {
             GrPrintf("Failed to get space for vertices!");
@@ -984,9 +985,47 @@
 
     if (NULL != indices) {
         target->setIndexSourceToArray(indices, indexCount);
-        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+    }
+
+    if (doOffscreenAA) {
+        // draw to the offscreen
+        if (NULL != indices) {
+            target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+        } else {
+            target->drawNonIndexed(primitiveType, 0, vertexCount);
+        }
+        // When there are custom texture coordinates we can't just draw
+        // a quad to sample the offscreen. Instead we redraw the geometry to
+        // specify the texture coords. This isn't quite right either, primitives
+        // will only be eroded at the edges, not expanded into partial pixels.
+        bool useRect = 0 == (layout & GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));
+        if (useRect) {
+            target->setViewMatrix(GrMatrix::I());
+        }
+        this->setupOffscreenAAPass2(target, paint, &record);
+        if (useRect) {
+            geo.set(NULL, 0, 0, 0);
+            int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
+            stages |= (1 << kOffscreenStage);
+            GrRect dstRect(0, 0, 
+                        target->getRenderTarget()->width(),
+                        target->getRenderTarget()->height());
+                        target->drawSimpleRect(dstRect, NULL, stages);
+            target->drawSimpleRect(dstRect, NULL, stages);
+        } else {
+            if (NULL != indices) {
+                target->drawIndexed (primitiveType, 0, 0, vertexCount, indexCount);
+            } else {
+                target->drawNonIndexed(primitiveType, 0, vertexCount);
+            }
+        }
+        this->endOffscreenAA(target, &record);
     } else {
-        target->drawNonIndexed(primitiveType, 0, vertexCount);
+        if (NULL != indices) {
+            target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+        } else {
+            target->drawNonIndexed(primitiveType, 0, vertexCount);
+        }
     }
 }
 
@@ -1010,8 +1049,9 @@
          if (this->setupOffscreenAAPass1(target, needsStencil, &record)) {
              pr->drawPath(target, 0, path, fill, translate);
              
+             target->setViewMatrix(GrMatrix::I());
              this->setupOffscreenAAPass2(target, paint, &record);
-             
+
              int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
              stages |= (1 << kOffscreenStage);
              GrRect dstRect(0, 0, 
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index c33f15c..1ac02f2 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -494,12 +494,12 @@
 
     // ...and there isn't a texture with an alpha channel...
     for (int s = 0; s < kNumStages; ++s) {
-        if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) {
+        if (this->isStageEnabled(s)) {
             GrAssert(NULL != fCurrDrawState.fTextures[s]);
+
             GrPixelConfig config = fCurrDrawState.fTextures[s]->config();
 
-            if (kRGB_565_GrPixelConfig != config &&
-                kRGBX_8888_GrPixelConfig != config) {
+            if (!GrPixelConfigIsOpaque(config)) {
                 return false;
             }
         }
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 0ea83a8..4bdf10e 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -1704,75 +1704,70 @@
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
 
     for (int s = 0; s < kNumStages; ++s) {
-        bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
-
         // bind texture and set sampler state
-        if (usingTexture) {
+        if (this->isStageEnabled(s)) {
             GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
 
-            if (NULL != nextTexture) {
-                // if we created a rt/tex and rendered to it without using a
-                // texture and now we're texuring from the rt it will still be
-                // the last bound texture, but it needs resolving. So keep this
-                // out of the "last != next" check.
-                GrGLRenderTarget* texRT = 
-                    static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
-                if (NULL != texRT) {
-                    resolveRenderTarget(texRT);
-                }
-
-                if (fHWDrawState.fTextures[s] != nextTexture) {
-                    setTextureUnit(s);
-                    GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID()));
-                #if GR_COLLECT_STATS
-                    ++fStats.fTextureChngCnt;
-                #endif
-                    //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
-                    fHWDrawState.fTextures[s] = nextTexture;
-                }
-
-                const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
-                const GrGLTexture::TexParams& oldTexParams =
-                                                    nextTexture->getTexParams();
-                GrGLTexture::TexParams newTexParams;
-
-                newTexParams.fFilter = sampler.isFilter() ? GR_GL_LINEAR :
-                                                            GR_GL_NEAREST;
-                newTexParams.fWrapS =
-                            GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()];
-                newTexParams.fWrapT =
-                            GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()];
-
-                if (newTexParams.fFilter != oldTexParams.fFilter) {
-                    setTextureUnit(s);
-                    GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
-                                        GR_GL_TEXTURE_MAG_FILTER,
-                                        newTexParams.fFilter));
-                    GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
-                                        GR_GL_TEXTURE_MIN_FILTER,
-                                        newTexParams.fFilter));
-                }
-                if (newTexParams.fWrapS != oldTexParams.fWrapS) {
-                    setTextureUnit(s);
-                    GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
-                                        GR_GL_TEXTURE_WRAP_S,
-                                        newTexParams.fWrapS));
-                }
-                if (newTexParams.fWrapT != oldTexParams.fWrapT) {
-                    setTextureUnit(s);
-                    GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
-                                        GR_GL_TEXTURE_WRAP_T,
-                                        newTexParams.fWrapT));
-                }
-                nextTexture->setTexParams(newTexParams);
-
-                // The texture matrix has to compensate for texture width/height
-                // and NPOT-embedded-in-POT
-                fDirtyFlags.fTextureChangedMask |= (1 << s);
-            } else {
-                GrAssert(!"Rendering with texture vert flag set but no texture");
-                return false;
+            // true for now, but maybe not with GrEffect.
+            GrAssert(NULL != nextTexture);
+            // if we created a rt/tex and rendered to it without using a
+            // texture and now we're texuring from the rt it will still be
+            // the last bound texture, but it needs resolving. So keep this
+            // out of the "last != next" check.
+            GrGLRenderTarget* texRT = 
+                static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
+            if (NULL != texRT) {
+                resolveRenderTarget(texRT);
             }
+
+            if (fHWDrawState.fTextures[s] != nextTexture) {
+                setTextureUnit(s);
+                GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID()));
+            #if GR_COLLECT_STATS
+                ++fStats.fTextureChngCnt;
+            #endif
+                //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
+                fHWDrawState.fTextures[s] = nextTexture;
+            }
+
+            const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
+            const GrGLTexture::TexParams& oldTexParams =
+                                                nextTexture->getTexParams();
+            GrGLTexture::TexParams newTexParams;
+
+            newTexParams.fFilter = sampler.isFilter() ? GR_GL_LINEAR :
+                                                        GR_GL_NEAREST;
+            newTexParams.fWrapS =
+                        GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()];
+            newTexParams.fWrapT =
+                        GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()];
+
+            if (newTexParams.fFilter != oldTexParams.fFilter) {
+                setTextureUnit(s);
+                GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
+                                    GR_GL_TEXTURE_MAG_FILTER,
+                                    newTexParams.fFilter));
+                GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
+                                    GR_GL_TEXTURE_MIN_FILTER,
+                                    newTexParams.fFilter));
+            }
+            if (newTexParams.fWrapS != oldTexParams.fWrapS) {
+                setTextureUnit(s);
+                GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
+                                    GR_GL_TEXTURE_WRAP_S,
+                                    newTexParams.fWrapS));
+            }
+            if (newTexParams.fWrapT != oldTexParams.fWrapT) {
+                setTextureUnit(s);
+                GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
+                                    GR_GL_TEXTURE_WRAP_T,
+                                    newTexParams.fWrapT));
+            }
+            nextTexture->setTexParams(newTexParams);
+
+            // The texture matrix has to compensate for texture width/height
+            // and NPOT-embedded-in-POT
+            fDirtyFlags.fTextureChangedMask |= (1 << s);
         }
     }
 
@@ -1822,7 +1817,7 @@
 #if GR_DEBUG
     // check for circular rendering
     for (int s = 0; s < kNumStages; ++s) {
-        GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
+        GrAssert(!this->isStageEnabled(s) ||
                  NULL == fCurrDrawState.fRenderTarget ||
                  NULL == fCurrDrawState.fTextures[s] ||
                  fCurrDrawState.fTextures[s]->asRenderTarget() !=
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index 446949f..4440bcd 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -127,8 +127,7 @@
     bool usingTextures[kNumStages];
 
     for (int s = 0; s < kNumStages; ++s) {
-        usingTextures[s] = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
-
+        usingTextures[s] = this->isStageEnabled(s);
         if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) {
             unimpl("Fixed pipe doesn't support radial/sweep gradients");
             return false;
@@ -152,7 +151,7 @@
     }
 
     for (int s = 0; s < kNumStages; ++s) {
-        bool wasUsingTexture = VertexUsesStage(s, fHWGeometryState.fVertexLayout);
+        bool wasUsingTexture = StageWillBeUsed(s, fHWGeometryState.fVertexLayout, fHWDrawState);
         if (usingTextures[s] != wasUsingTexture) {
             setTextureUnit(s);
             if (usingTextures[s]) {
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 66056c9..ff9f3a4 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -515,7 +515,7 @@
     for (int s = 0; s < kNumStages; ++s) {
         GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
 
-        stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
+        stage.fEnabled = this->isStageEnabled(s);
 
         if (stage.fEnabled) {
             GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
index 851732e..ab8a4bb 100644
--- a/gpu/src/GrGpuGLShaders2.cpp
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -1044,7 +1044,7 @@
     for (int s = 0; s < kNumStages; ++s) {
         StageDesc& stage = desc->fStages[s];
 
-        stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
+        stage.fEnabled = this->isStageEnabled(s);
 
         if (stage.fEnabled) {
             GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];