Revert "ccpr: Handle winding and even-odd in the same shader"

This reverts commit 5dd3fccb3c7d9fce2663803a1284734237d8546d.

Reason for revert: fma() not supported pre-3.1

Original change's description:
> ccpr: Handle winding and even-odd in the same shader
> 
> We are already waiting for an entire texture lookup anyway. A couple
> extra flops should still complete before the texture fetch. This also
> gives us better batching.
> 
> Bug: skia:
> Change-Id: I83a7a8ba6c05cd1ad6b1756a987429233e69ed6c
> Reviewed-on: https://skia-review.googlesource.com/129422
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Brian Salomon <bsalomon@google.com>

TBR=bsalomon@google.com,csmartdalton@google.com

Change-Id: Iaa6b72686fdf89b58a0ea8418296985c2a3dc27e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/129900
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ccpr/GrCCClipPath.cpp b/src/gpu/ccpr/GrCCClipPath.cpp
index 9b8a737..6b8a96c 100644
--- a/src/gpu/ccpr/GrCCClipPath.cpp
+++ b/src/gpu/ccpr/GrCCClipPath.cpp
@@ -48,12 +48,11 @@
     fAccessRect = accessRect;
 }
 
-void GrCCClipPath::renderPathInAtlas(GrCCPerFlushResources* resources,
-                                     GrOnFlushResourceProvider* onFlushRP) {
+void GrCCClipPath::placePathInAtlas(GrCCPerFlushResources* resources,
+                                    GrOnFlushResourceProvider* onFlushRP) {
     SkASSERT(this->isInitialized());
     SkASSERT(!fHasAtlas);
-    fAtlas = resources->renderDeviceSpacePathInAtlas(*onFlushRP->caps(), fAccessRect,
-                                                     fDeviceSpacePath, fPathDevIBounds,
-                                                     &fAtlasOffsetX, &fAtlasOffsetY);
+    fAtlas = resources->addDeviceSpacePathToAtlas(*onFlushRP->caps(), fAccessRect, fDeviceSpacePath,
+                                                  fPathDevIBounds, &fAtlasOffsetX, &fAtlasOffsetY);
     SkDEBUGCODE(fHasAtlas = true);
 }
diff --git a/src/gpu/ccpr/GrCCClipPath.h b/src/gpu/ccpr/GrCCClipPath.h
index 290ac29..4b4ad75 100644
--- a/src/gpu/ccpr/GrCCClipPath.h
+++ b/src/gpu/ccpr/GrCCClipPath.h
@@ -55,7 +55,7 @@
         return fPathDevIBounds;
     }
 
-    void renderPathInAtlas(GrCCPerFlushResources*, GrOnFlushResourceProvider*);
+    void placePathInAtlas(GrCCPerFlushResources*, GrOnFlushResourceProvider*);
 
     const SkVector& atlasScale() const { SkASSERT(fHasAtlasTransform); return fAtlasScale; }
     const SkVector& atlasTranslate() const { SkASSERT(fHasAtlasTransform); return fAtlasTranslate; }
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index 39c1b26..b3fd711 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -60,7 +60,8 @@
     SkASSERT(!that->fOwningPerOpListPaths || that->fOwningPerOpListPaths == fOwningPerOpListPaths);
     SkASSERT(that->fNumDraws);
 
-    if (fSRGBFlags != that->fSRGBFlags || fProcessors != that->fProcessors ||
+    if (this->getFillType() != that->getFillType() || fSRGBFlags != that->fSRGBFlags ||
+        fProcessors != that->fProcessors ||
         fViewMatrixIfUsingLocalCoords != that->fViewMatrixIfUsingLocalCoords) {
         return false;
     }
@@ -94,35 +95,35 @@
     const GrCCAtlas* currentAtlas = nullptr;
     SkASSERT(fNumDraws > 0);
     SkASSERT(-1 == fBaseInstance);
-    fBaseInstance = resources->nextPathInstanceIdx();
+    fBaseInstance = resources->pathInstanceCount();
 
     for (const SingleDraw& draw : fDraws) {
-        // renderPathInAtlas gives us two tight bounding boxes: one in device space, as well as a
+        // addPathToAtlas gives us two tight bounding boxes: one in device space, as well as a
         // second one rotated an additional 45 degrees. The path vertex shader uses these two
         // bounding boxes to generate an octagon that circumscribes the path.
         SkRect devBounds, devBounds45;
         int16_t atlasOffsetX, atlasOffsetY;
-        GrCCAtlas* atlas = resources->renderPathInAtlas(*onFlushRP->caps(), draw.fClipIBounds,
-                                                        draw.fMatrix, draw.fPath, &devBounds,
-                                                        &devBounds45, &atlasOffsetX, &atlasOffsetY);
+        GrCCAtlas* atlas = resources->addPathToAtlas(*onFlushRP->caps(), draw.fClipIBounds,
+                                                     draw.fMatrix, draw.fPath, &devBounds,
+                                                     &devBounds45, &atlasOffsetX, &atlasOffsetY);
         if (!atlas) {
             SkDEBUGCODE(++fNumSkippedInstances);
             continue;
         }
         if (currentAtlas != atlas) {
             if (currentAtlas) {
-                this->addAtlasBatch(currentAtlas, resources->nextPathInstanceIdx());
+                this->addAtlasBatch(currentAtlas, resources->pathInstanceCount());
             }
             currentAtlas = atlas;
         }
 
-        resources->appendDrawPathInstance().set(draw.fPath.getFillType(), devBounds, devBounds45,
-                                                atlasOffsetX, atlasOffsetY, draw.fColor);
+        resources->appendDrawPathInstance() =
+                {devBounds, devBounds45, {{atlasOffsetX, atlasOffsetY}}, draw.fColor};
     }
 
-    SkASSERT(resources->nextPathInstanceIdx() == fBaseInstance + fNumDraws - fNumSkippedInstances);
+    SkASSERT(resources->pathInstanceCount() == fBaseInstance + fNumDraws - fNumSkippedInstances);
     if (currentAtlas) {
-        this->addAtlasBatch(currentAtlas, resources->nextPathInstanceIdx());
+        this->addAtlasBatch(currentAtlas, resources->pathInstanceCount());
     }
 }
 
@@ -155,7 +156,7 @@
         }
 
         GrCCPathProcessor pathProc(flushState->resourceProvider(),
-                                   sk_ref_sp(batch.fAtlas->textureProxy()),
+                                   sk_ref_sp(batch.fAtlas->textureProxy()), this->getFillType(),
                                    fViewMatrixIfUsingLocalCoords);
         pathProc.drawPaths(flushState, pipeline, resources->indexBuffer(),
                            resources->vertexBuffer(), resources->instanceBuffer(),
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h
index 92ba3dd..5406d89 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.h
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.h
@@ -48,6 +48,11 @@
     void onExecute(GrOpFlushState*) override;
 
 private:
+    SkPath::FillType getFillType() const {
+        SkASSERT(fNumDraws >= 1);
+        return fDraws.head().fPath.getFillType();
+    }
+
     struct AtlasBatch {
         const GrCCAtlas* fAtlas;
         int fEndInstanceIdx;
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index de470ce..588e2bc 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -76,9 +76,10 @@
 }
 
 GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* resourceProvider,
-                                     sk_sp<GrTextureProxy> atlas,
+                                     sk_sp<GrTextureProxy> atlas, SkPath::FillType fillType,
                                      const SkMatrix& viewMatrixIfUsingLocalCoords)
         : INHERITED(kGrCCPathProcessor_ClassID)
+        , fFillType(fillType)
         , fAtlasAccess(std::move(atlas), GrSamplerState::Filter::kNearest,
                        GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag) {
     this->addInstanceAttrib("devbounds", kFloat4_GrVertexAttribType);
@@ -112,6 +113,10 @@
     }
 }
 
+void GrCCPathProcessor::getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
+    b->add32((fFillType << 16) | this->atlasProxy()->origin());
+}
+
 class GLSLPathProcessor : public GrGLSLGeometryProcessor {
 public:
     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override;
@@ -168,7 +173,7 @@
 
     varyingHandler->emitAttributes(proc);
 
-    GrGLSLVarying texcoord(kFloat3_GrSLType);
+    GrGLSLVarying texcoord(kFloat2_GrSLType);
     GrGLSLVarying color(kHalf4_GrSLType);
     varyingHandler->addVarying("texcoord", &texcoord);
     varyingHandler->addPassThroughAttribute(&proc.getInstanceAttrib(InstanceAttribs::kColor),
@@ -188,11 +193,9 @@
 
     // N[0] is the normal for the edge we are intersecting from the regular bounding box, pointing
     // out of the octagon.
-    v->codeAppendf("float4 devbounds = %s;",
+    v->codeAppendf("float2 refpt = (0 == sk_VertexID >> 2) ? %s.xy : %s.zw;",
+                   proc.getInstanceAttrib(InstanceAttribs::kDevBounds).fName,
                    proc.getInstanceAttrib(InstanceAttribs::kDevBounds).fName);
-    v->codeAppend ("float2 refpt = (0 == sk_VertexID >> 2)"
-                           "? float2(min(devbounds.x, devbounds.z), devbounds.y)"
-                           ": float2(max(devbounds.x, devbounds.z), devbounds.w);");
     v->codeAppendf("refpt += N[0] * %f;", kAABloatRadius); // bloat for AA.
 
     // N[1] is the normal for the edge we are intersecting from the 45-degree bounding box, pointing
@@ -212,15 +215,12 @@
     v->codeAppendf("float2 atlascoord = octocoord + float2(%s);",
                    proc.getInstanceAttrib(InstanceAttribs::kAtlasOffset).fName);
     if (kTopLeft_GrSurfaceOrigin == proc.atlasProxy()->origin()) {
-        v->codeAppendf("%s.xy = atlascoord * %s;", texcoord.vsOut(), atlasAdjust);
+        v->codeAppendf("%s = atlascoord * %s;", texcoord.vsOut(), atlasAdjust);
     } else {
         SkASSERT(kBottomLeft_GrSurfaceOrigin == proc.atlasProxy()->origin());
-        v->codeAppendf("%s.xy = float2(atlascoord.x * %s.x, 1 - atlascoord.y * %s.y);",
+        v->codeAppendf("%s = float2(atlascoord.x * %s.x, 1 - atlascoord.y * %s.y);",
                        texcoord.vsOut(), atlasAdjust, atlasAdjust);
     }
-    // The third texture coordinate is -.5 for even-odd paths and +.5 for winding ones.
-    // ("right < left" indicates even-odd fill type.)
-    v->codeAppendf("%s.z = sign(devbounds.z - devbounds.x) * .5;", texcoord.vsOut());
 
     this->emitTransforms(v, varyingHandler, uniHandler, GrShaderVar("octocoord", kFloat2_GrSLType),
                          proc.localMatrix(), args.fFPCoordTransformHandler);
@@ -228,19 +228,15 @@
     // Fragment shader.
     GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
 
-    // Look up coverage count in the atlas.
-    f->codeAppend ("half coverage = ");
-    f->appendTextureLookup(args.fTexSamplers[0], SkStringPrintf("%s.xy", texcoord.fsIn()).c_str(),
-                           kFloat2_GrSLType);
+    f->codeAppend ("half coverage_count = ");
+    f->appendTextureLookup(args.fTexSamplers[0], texcoord.fsIn(), kFloat2_GrSLType);
     f->codeAppend (".a;");
 
-    // Scale coverage count by .5. Make it negative for even-odd paths and positive for winding
-    // ones. Clamp winding coverage counts at 1.0 (i.e. min(coverage/2, .5)).
-    f->codeAppendf("coverage = min(abs(coverage) * %s.z, .5);", texcoord.fsIn());
-
-    // For negative values, this finishes the even-odd sawtooth function. Since positive (winding)
-    // values were clamped at "coverage/2 = .5", this only undoes the previous multiply by .5.
-    f->codeAppend ("coverage = 1 - abs(fma(fract(coverage), 2, -1));");
-
-    f->codeAppendf("%s = half4(coverage);", args.fOutputCoverage);
+    if (SkPath::kWinding_FillType == proc.fillType()) {
+        f->codeAppendf("%s = half4(min(abs(coverage_count), 1));", args.fOutputCoverage);
+    } else {
+        SkASSERT(SkPath::kEvenOdd_FillType == proc.fillType());
+        f->codeAppend ("half t = mod(abs(coverage_count), 2);");
+        f->codeAppendf("%s = half4(1 - abs(t - 1));", args.fOutputCoverage);
+    }
 }
diff --git a/src/gpu/ccpr/GrCCPathProcessor.h b/src/gpu/ccpr/GrCCPathProcessor.h
index 198bc60..4789326 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.h
+++ b/src/gpu/ccpr/GrCCPathProcessor.h
@@ -38,14 +38,13 @@
     static constexpr int kNumInstanceAttribs = 1 + (int)InstanceAttribs::kColor;
 
     struct Instance {
-        SkRect fDevBounds; // "right < left" indicates even-odd fill type.
+        SkRect fDevBounds;
         SkRect fDevBounds45; // Bounding box in "| 1  -1 | * devCoords" space.
                              //                  | 1   1 |
         std::array<int16_t, 2> fAtlasOffset;
         uint32_t fColor;
 
-        void set(SkPath::FillType, const SkRect& devBounds, const SkRect& devBounds45,
-                 int16_t atlasOffsetX, int16_t atlasOffsetY, uint32_t color);
+        GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT);
     };
 
     GR_STATIC_ASSERT(4 * 10 == sizeof(Instance));
@@ -53,13 +52,14 @@
     static sk_sp<const GrBuffer> FindVertexBuffer(GrOnFlushResourceProvider*);
     static sk_sp<const GrBuffer> FindIndexBuffer(GrOnFlushResourceProvider*);
 
-    GrCCPathProcessor(GrResourceProvider*, sk_sp<GrTextureProxy> atlas,
+    GrCCPathProcessor(GrResourceProvider*, sk_sp<GrTextureProxy> atlas, SkPath::FillType,
                       const SkMatrix& viewMatrixIfUsingLocalCoords = SkMatrix::I());
 
     const char* name() const override { return "GrCCPathProcessor"; }
     const GrSurfaceProxy* atlasProxy() const { return fAtlasAccess.proxy(); }
     const GrTexture* atlas() const { return fAtlasAccess.peekTexture(); }
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
+    SkPath::FillType fillType() const { return fFillType; }
     const Attribute& getInstanceAttrib(InstanceAttribs attribID) const {
         const Attribute& attrib = this->getAttrib((int)attribID);
         SkASSERT(Attribute::InputRate::kPerInstance == attrib.fInputRate);
@@ -72,7 +72,7 @@
         return attrib;
     }
 
-    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
+    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
     void drawPaths(GrOpFlushState*, const GrPipeline&, const GrBuffer* indexBuffer,
@@ -80,25 +80,11 @@
                    int endInstance, const SkRect& bounds) const;
 
 private:
+    const SkPath::FillType fFillType;
     const TextureSampler fAtlasAccess;
     SkMatrix fLocalMatrix;
 
     typedef GrGeometryProcessor INHERITED;
 };
 
-inline void GrCCPathProcessor::Instance::set(SkPath::FillType fillType, const SkRect& devBounds,
-                                             const SkRect& devBounds45, int16_t atlasOffsetX,
-                                             int16_t atlasOffsetY, uint32_t color) {
-    if (SkPath::kEvenOdd_FillType == fillType) {
-        // "right < left" indicates even-odd fill type.
-        fDevBounds.setLTRB(devBounds.fRight, devBounds.fTop, devBounds.fLeft, devBounds.fBottom);
-    } else {
-        SkASSERT(SkPath::kWinding_FillType == fillType);
-        fDevBounds = devBounds;
-    }
-    fDevBounds45 = devBounds45;
-    fAtlasOffset = {{atlasOffsetX, atlasOffsetY}};
-    fColor = color;
-}
-
 #endif
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index 3f02ac7..a658bf7 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -38,10 +38,10 @@
     SkDEBUGCODE(fPathInstanceBufferCount = numPathDraws);
 }
 
-GrCCAtlas* GrCCPerFlushResources::renderPathInAtlas(const GrCaps& caps, const SkIRect& clipIBounds,
-                                                    const SkMatrix& m, const SkPath& path,
-                                                    SkRect* devBounds, SkRect* devBounds45,
-                                                    int16_t* atlasOffsetX, int16_t* atlasOffsetY) {
+GrCCAtlas* GrCCPerFlushResources::addPathToAtlas(const GrCaps& caps, const SkIRect& clipIBounds,
+                                                 const SkMatrix& m, const SkPath& path,
+                                                 SkRect* devBounds, SkRect* devBounds45,
+                                                 int16_t* atlasOffsetX, int16_t* atlasOffsetY) {
     SkASSERT(this->isMapped());
     SkIRect devIBounds;
     fPathParser->parsePath(m, path, devBounds, devBounds45);
@@ -49,12 +49,12 @@
     return this->placeParsedPathInAtlas(caps, clipIBounds, devIBounds, atlasOffsetX, atlasOffsetY);
 }
 
-GrCCAtlas* GrCCPerFlushResources::renderDeviceSpacePathInAtlas(const GrCaps& caps,
-                                                               const SkIRect& clipIBounds,
-                                                               const SkPath& devPath,
-                                                               const SkIRect& devPathIBounds,
-                                                               int16_t* atlasOffsetX,
-                                                               int16_t* atlasOffsetY) {
+GrCCAtlas* GrCCPerFlushResources::addDeviceSpacePathToAtlas(const GrCaps& caps,
+                                                            const SkIRect& clipIBounds,
+                                                            const SkPath& devPath,
+                                                            const SkIRect& devPathIBounds,
+                                                            int16_t* atlasOffsetX,
+                                                            int16_t* atlasOffsetY) {
     SkASSERT(this->isMapped());
     fPathParser->parseDeviceSpacePath(devPath);
     return this->placeParsedPathInAtlas(caps, clipIBounds, devPathIBounds, atlasOffsetX,
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.h b/src/gpu/ccpr/GrCCPerFlushResources.h
index bc6b6ed..d1a6d8f 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.h
+++ b/src/gpu/ccpr/GrCCPerFlushResources.h
@@ -26,21 +26,22 @@
 
     bool isMapped() const { return SkToBool(fPathInstanceData); }
 
-    GrCCAtlas* renderPathInAtlas(const GrCaps&, const SkIRect& clipIBounds, const SkMatrix&,
-                                 const SkPath&, SkRect* devBounds, SkRect* devBounds45,
-                                 int16_t* offsetX, int16_t* offsetY);
-    GrCCAtlas* renderDeviceSpacePathInAtlas(const GrCaps&, const SkIRect& clipIBounds,
-                                            const SkPath& devPath, const SkIRect& devPathIBounds,
-                                            int16_t* atlasOffsetX, int16_t* atlasOffsetY);
+    GrCCAtlas* addPathToAtlas(const GrCaps&, const SkIRect& clipIBounds, const SkMatrix&,
+                              const SkPath&, SkRect* devBounds, SkRect* devBounds45,
+                              int16_t* offsetX, int16_t* offsetY);
+    GrCCAtlas* addDeviceSpacePathToAtlas(const GrCaps&, const SkIRect& clipIBounds,
+                                         const SkPath& devPath, const SkIRect& devPathIBounds,
+                                         int16_t* atlasOffsetX, int16_t* atlasOffsetY);
 
     GrCCPathProcessor::Instance& appendDrawPathInstance() {
         SkASSERT(this->isMapped());
-        SkASSERT(fNextPathInstanceIdx < fPathInstanceBufferCount);
-        return fPathInstanceData[fNextPathInstanceIdx++];
+        SkASSERT(fPathInstanceCount < fPathInstanceBufferCount);
+        return fPathInstanceData[fPathInstanceCount++];
     }
-    int nextPathInstanceIdx() const { return fNextPathInstanceIdx; }
+    int pathInstanceCount() const { return fPathInstanceCount; }
 
-    bool finalize(GrOnFlushResourceProvider*, SkTArray<sk_sp<GrRenderTargetContext>>* atlasDraws);
+    bool finalize(GrOnFlushResourceProvider*,
+                  SkTArray<sk_sp<GrRenderTargetContext>>* atlasDraws);
 
     const GrBuffer* indexBuffer() const { SkASSERT(!this->isMapped()); return fIndexBuffer.get(); }
     const GrBuffer* vertexBuffer() const { SkASSERT(!this->isMapped()); return fVertexBuffer.get();}
@@ -58,7 +59,7 @@
     sk_sp<GrBuffer> fInstanceBuffer;
 
     GrCCPathProcessor::Instance* fPathInstanceData = nullptr;
-    int fNextPathInstanceIdx = 0;
+    int fPathInstanceCount = 0;
     SkDEBUGCODE(int fPathInstanceBufferCount);
 
     GrSTAllocator<4, GrCCAtlas> fAtlases;
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index a069f6e..ee0dbde 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -215,10 +215,10 @@
             SkDEBUGCODE(numSkippedPaths += op->numSkippedInstances_debugOnly());
         }
         for (auto& clipsIter : flushingPaths->fClipPaths) {
-            clipsIter.second.renderPathInAtlas(resources.get(), onFlushRP);
+            clipsIter.second.placePathInAtlas(resources.get(), onFlushRP);
         }
     }
-    SkASSERT(resources->nextPathInstanceIdx() == numPathDraws - numSkippedPaths);
+    SkASSERT(resources->pathInstanceCount() == numPathDraws - numSkippedPaths);
 
     // Allocate the atlases and create instance buffers to draw them.
     if (!resources->finalize(onFlushRP, atlasDraws)) {