diff options
-rw-r--r-- | gn/gpu.gni | 1 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageProcessor.cpp | 55 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageProcessor.h | 18 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp | 99 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp | 71 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCubicShader.cpp | 40 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCubicShader.h | 9 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCQuadraticShader.cpp | 61 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCQuadraticShader.h | 12 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCTriangleShader.h | 46 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLShaderBuilder.h | 1 |
11 files changed, 220 insertions, 193 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni index 6aa950fc11..b3f4eb1680 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -314,7 +314,6 @@ skia_gpu_sources = [ "$_src/gpu/ccpr/GrCCPathProcessor.h", "$_src/gpu/ccpr/GrCCQuadraticShader.cpp", "$_src/gpu/ccpr/GrCCQuadraticShader.h", - "$_src/gpu/ccpr/GrCCTriangleShader.h", "$_src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp", "$_src/gpu/ccpr/GrCoverageCountingPathRenderer.h", diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp index c44d464826..aac16afe90 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp @@ -12,20 +12,36 @@ #include "SkMakeUnique.h" #include "ccpr/GrCCCubicShader.h" #include "ccpr/GrCCQuadraticShader.h" -#include "ccpr/GrCCTriangleShader.h" #include "glsl/GrGLSLVertexGeoBuilder.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLVertexGeoBuilder.h" -void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc, - GrGLSLFPFragmentBuilder* f, - const char* skOutputColor, - const char* skOutputCoverage) const { - f->codeAppendf("half coverage = 0;"); - this->onEmitFragmentCode(f, "coverage"); - f->codeAppendf("%s.a = coverage;", skOutputColor); - f->codeAppendf("%s = half4(1);", skOutputCoverage); -} +class GrCCCoverageProcessor::TriangleShader : public GrCCCoverageProcessor::Shader { + void onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope, + SkString* code, const char* position, const char* coverage, + const char* cornerCoverage) override { + if (!cornerCoverage) { + fCoverages.reset(kHalf_GrSLType, scope); + varyingHandler->addVarying("coverage", &fCoverages); + code->appendf("%s = %s;", OutName(fCoverages), coverage); + } else { + fCoverages.reset(kHalf3_GrSLType, scope); + varyingHandler->addVarying("coverages", &fCoverages); + code->appendf("%s = half3(%s, %s);", OutName(fCoverages), coverage, cornerCoverage); + } + } + + void onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const override { + if (kHalf_GrSLType == fCoverages.type()) { + f->codeAppendf("%s = %s;", outputCoverage, fCoverages.fsIn()); + } else { + f->codeAppendf("%s = %s.z * %s.y + %s.x;", + outputCoverage, fCoverages.fsIn(), fCoverages.fsIn(), fCoverages.fsIn()); + } + } + + GrGLSLVarying fCoverages; +}; void GrCCCoverageProcessor::Shader::EmitEdgeDistanceEquation(GrGLSLVertexGeoBuilder* s, const char* leftPt, @@ -92,10 +108,9 @@ void GrCCCoverageProcessor::Shader::CalcEdgeCoveragesAtBloatVertices(GrGLSLVerte s->codeAppendf("}"); } -void GrCCCoverageProcessor::Shader::CalcCornerCoverageAttenuation(GrGLSLVertexGeoBuilder* s, - const char* leftDir, - const char* rightDir, - const char* outputAttenuation) { +void GrCCCoverageProcessor::Shader::CalcCornerAttenuation(GrGLSLVertexGeoBuilder* s, + const char* leftDir, const char* rightDir, + const char* outputAttenuation) { // obtuseness = cos(corner_angle) if corner_angle > 90 degrees // 0 if corner_angle <= 90 degrees s->codeAppendf("half obtuseness = max(dot(%s, %s), 0);", leftDir, rightDir); @@ -153,7 +168,7 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShad std::unique_ptr<Shader> shader; switch (fPrimitiveType) { case PrimitiveType::kTriangles: - shader = skstd::make_unique<GrCCTriangleShader>(); + shader = skstd::make_unique<TriangleShader>(); break; case PrimitiveType::kQuadratics: shader = skstd::make_unique<GrCCQuadraticShader>(); @@ -166,6 +181,16 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShad : this->createVSImpl(std::move(shader)); } +void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc, + GrGLSLFPFragmentBuilder* f, + const char* skOutputColor, + const char* skOutputCoverage) const { + f->codeAppendf("half coverage = 0;"); + this->onEmitFragmentCode(f, "coverage"); + f->codeAppendf("%s.a = coverage;", skOutputColor); + f->codeAppendf("%s = half4(1);", skOutputCoverage); +} + void GrCCCoverageProcessor::draw(GrOpFlushState* flushState, const GrPipeline& pipeline, const GrMesh meshes[], const GrPipeline::DynamicState dynamicStates[], int meshCount, diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h index 8824646a05..9b83fc9275 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor.h +++ b/src/gpu/ccpr/GrCCCoverageProcessor.h @@ -126,10 +126,9 @@ public: void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope, SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) { + const char* cornerCoverage) { SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope); - this->onEmitVaryings(varyingHandler, scope, code, position, coverage, - attenuatedCoverage); + this->onEmitVaryings(varyingHandler, scope, code, position, coverage, cornerCoverage); } void emitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*, @@ -163,9 +162,8 @@ public: // regular (linearly-interpolated) coverage. This function calculates the attenuation value // to use in the single, outermost vertex. The remaining three vertices of the corner box // all use an attenuation value of 1. - static void CalcCornerCoverageAttenuation(GrGLSLVertexGeoBuilder*, const char* leftDir, - const char* rightDir, - const char* outputAttenuation); + static void CalcCornerAttenuation(GrGLSLVertexGeoBuilder*, const char* leftDir, + const char* rightDir, const char* outputAttenuation); virtual ~Shader() {} @@ -177,7 +175,7 @@ public: // 'coverage' will only be +1 or -1 on curves. virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) = 0; + const char* cornerCoverage) = 0; // Emits the fragment code that calculates a pixel's signed coverage value. virtual void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, @@ -190,15 +188,19 @@ public: SkASSERT(Scope::kVertToGeo != varying.scope()); return Scope::kGeoToFrag == varying.scope() ? varying.gsOut() : varying.vsOut(); } + + // Our friendship with GrGLSLShaderBuilder does not propogate to subclasses. + inline static SkString& AccessCodeString(GrGLSLShaderBuilder* s) { return s->code(); } }; +private: class GSImpl; class GSTriangleHullImpl; class GSCurveHullImpl; class GSCornerImpl; class VSImpl; + class TriangleShader; -private: // Slightly undershoot a bloat radius of 0.5 so vertices that fall on integer boundaries don't // accidentally bleed into neighbor pixels. static constexpr float kAABloatRadius = 0.491111f; diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp index 0bb34b16a0..4207f85c15 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp @@ -21,7 +21,6 @@ protected: GSImpl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {} virtual bool hasCoverage() const { return false; } - virtual bool hasAttenuatedCoverage() const { return false; } void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, FPCoordTransformIter&& transformIter) final { @@ -81,21 +80,20 @@ protected: if (this->hasCoverage()) { coverage = emitArgs.emplace_back("coverage", kHalf_GrSLType).c_str(); } - const char* attenuatedCoverage = nullptr; - if (this->hasAttenuatedCoverage()) { - attenuatedCoverage = emitArgs.emplace_back("attenuated_coverage", - kHalf2_GrSLType).c_str(); + const char* cornerCoverage = nullptr; + if (GSSubpass::kCorners == proc.fGSSubpass) { + cornerCoverage = emitArgs.emplace_back("corner_coverage", kHalf2_GrSLType).c_str(); } g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() { SkString fnBody; if (coverage) { fnBody.appendf("%s *= %s;", coverage, wind.c_str()); } - if (attenuatedCoverage) { - fnBody.appendf("%s.x *= %s;", attenuatedCoverage, wind.c_str()); + if (cornerCoverage) { + fnBody.appendf("%s.x *= %s;", cornerCoverage, wind.c_str()); } fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kGeoToFrag, &fnBody, - position, coverage ? coverage : wind.c_str(), attenuatedCoverage); + position, coverage ? coverage : wind.c_str(), cornerCoverage); g->emitVertex(&fnBody, position, rtAdjust); return fnBody; }().c_str(), &emitVertexFn); @@ -303,7 +301,6 @@ public: GSCornerImpl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {} bool hasCoverage() const override { return true; } - bool hasAttenuatedCoverage() const override { return true; } void onEmitGeometryShader(const GrCCCoverageProcessor& proc, GrGLSLGeometryBuilder* g, const GrShaderVar& wind, const char* emitVertexFn) const override { @@ -334,47 +331,57 @@ public: "leftdir.y > rightdir.y ? +1 : -1);"); g->codeAppend ("float2 crossbloat = float2(-outbloat.y, +outbloat.x);"); - g->codeAppend ("half2 left_coverages; {"); - Shader::CalcEdgeCoveragesAtBloatVertices(g, "left", "corner", "-outbloat", "-crossbloat", - "left_coverages"); + g->codeAppend ("half attenuation; {"); + Shader::CalcCornerAttenuation(g, "leftdir", "rightdir", "attenuation"); g->codeAppend ("}"); - g->codeAppend ("half2 right_coverages; {"); - Shader::CalcEdgeCoveragesAtBloatVertices(g, "corner", "right", "-outbloat", "crossbloat", - "right_coverages"); - g->codeAppend ("}"); + if (isTriangle) { + g->codeAppend ("half2 left_coverages; {"); + Shader::CalcEdgeCoveragesAtBloatVertices(g, "left", "corner", "-outbloat", + "-crossbloat", "left_coverages"); + g->codeAppend ("}"); + + g->codeAppend ("half2 right_coverages; {"); + Shader::CalcEdgeCoveragesAtBloatVertices(g, "corner", "right", "-outbloat", + "crossbloat", "right_coverages"); + g->codeAppend ("}"); + + // Emit a corner box. The first coverage argument erases the values that were written + // previously by the hull and edge geometry. The second pair are multiplied together by + // the fragment shader. They ramp to 0 with attenuation in the direction of outbloat, + // and linearly from left-edge coverage to right-edge coverage in the direction of + // crossbloat. + // + // NOTE: Since this is not a linear mapping, it is important that the box's diagonal + // shared edge points in the direction of outbloat. + g->codeAppendf("%s(corner - crossbloat * bloat, right_coverages[1] - left_coverages[1]," + "half2(1 + left_coverages[1], 1));", + emitVertexFn); - g->codeAppend ("half attenuation; {"); - Shader::CalcCornerCoverageAttenuation(g, "leftdir", "rightdir", "attenuation"); - g->codeAppend ("}"); + g->codeAppendf("%s(corner + outbloat * bloat, " + "1 + left_coverages[0] + right_coverages[0], half2(0, attenuation));", + emitVertexFn); - // Emit a corner box. The first coverage argument erases the values that were written - // previously by the hull and edge geometry. The second pair are multiplied together by the - // fragment shader. They ramp to 0 with attenuation in the direction of outbloat, and - // linearly from left-edge coverage to right-edge coverage in the direction of crossbloat. - // - // NOTE: Since this is not a linear mapping, it is important that the box's diagonal shared - // edge points in the direction of outbloat. - g->codeAppendf("%s(corner - crossbloat * bloat, %s, half2(1 + left_coverages[1], 1));", - emitVertexFn, - // Erase what the hull wrote previously. - isTriangle ? "right_coverages[1] - left_coverages[1]" : "-1"); - - g->codeAppendf("%s(corner + outbloat * bloat, %s, half2(0, attenuation));", - emitVertexFn, - // Erase what the hull wrote previously. - isTriangle ? "1 + left_coverages[0] + right_coverages[0]" : "-1"); - - g->codeAppendf("%s(corner - outbloat * bloat, %s, " - "half2(1 + left_coverages[0] + right_coverages[0], 1));", - emitVertexFn, - // Erase what the hull wrote previously. - isTriangle ? "-1 - left_coverages[0] - right_coverages[0]" : "-1"); - - g->codeAppendf("%s(corner + crossbloat * bloat, %s, half2(1 + right_coverages[1], 1));", - emitVertexFn, - // Erase what the hull wrote previously. - isTriangle ? "left_coverages[1] - right_coverages[1]" : "-1"); + g->codeAppendf("%s(corner - outbloat * bloat, " + "-1 - left_coverages[0] - right_coverages[0], " + "half2(1 + left_coverages[0] + right_coverages[0], 1));", + emitVertexFn); + + g->codeAppendf("%s(corner + crossbloat * bloat, left_coverages[1] - right_coverages[1]," + "half2(1 + right_coverages[1], 1));", + emitVertexFn); + } else { + // Curves are simpler. The first coverage value of -1 means "wind = -wind", and causes + // the Shader to erase what it had written previously for the hull. Then, at each vertex + // of the corner box, the Shader will calculate the curve's local coverage value, + // interpolate it alongside our attenuation parameter, and multiply the two together for + // a final coverage value. + g->codeAppendf("%s(corner - crossbloat * bloat, -1, half2(1));", emitVertexFn); + g->codeAppendf("%s(corner + outbloat * bloat, -1, half2(0, attenuation));", + emitVertexFn); + g->codeAppendf("%s(corner - outbloat * bloat, -1, half2(1));", emitVertexFn); + g->codeAppendf("%s(corner + crossbloat * bloat, -1, half2(1));", emitVertexFn); + } g->configure(InputType::kLines, OutputType::kTriangleStrip, 4, isTriangle ? 3 : 2); } diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp index 7af1a739fc..a63b37e19e 100644 --- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp +++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp @@ -369,22 +369,18 @@ void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) v->codeAppend ("float2 vertex = corner + bloatdir * bloat;"); gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex"); - v->codeAppend ("half left_coverage; {"); - Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "left_coverage"); - v->codeAppend ("}"); - - v->codeAppend ("half right_coverage; {"); - Shader::CalcEdgeCoverageAtBloatVertex(v, "corner", "right", "bloatdir", "right_coverage"); - v->codeAppend ("}"); - - v->codeAppend ("half attenuation; {"); - Shader::CalcCornerCoverageAttenuation(v, "leftdir", "rightdir", "attenuation"); - v->codeAppend ("}"); - // Hulls have a coverage of +1 all around. v->codeAppend ("half coverage = +1;"); if (3 == fNumSides) { + v->codeAppend ("half left_coverage; {"); + Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "left_coverage"); + v->codeAppend ("}"); + + v->codeAppend ("half right_coverage; {"); + Shader::CalcEdgeCoverageAtBloatVertex(v, "corner", "right", "bloatdir", "right_coverage"); + v->codeAppend ("}"); + v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge? proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsEdgeBit); v->codeAppend ( "coverage = left_coverage;"); @@ -397,39 +393,52 @@ void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) v->codeAppend ("}"); } - // Corner boxes require attenuation. - v->codeAppend ("half2 attenuated_coverage = half2(0, 1);"); + // Non-corner geometry should have zero effect from corner coverage. + v->codeAppend ("half2 corner_coverage = half2(0);"); v->codeAppendf("if (0 != (%s & %i)) {", // Are we a corner? proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsCornerBit); // We use coverage=-1 to erase what the hull geometry wrote. + // + // In the context of curves, this effectively means "wind = -wind" and + // causes the Shader to erase what it had written previously for the hull. + // + // For triangles it just erases the "+1" value written by the hull geometry. v->codeAppend ( "coverage = -1;"); if (3 == fNumSides) { // Triangle corners also have to erase what the edge geometry wrote. v->codeAppend ("coverage -= left_coverage + right_coverage;"); } - // The x and y components of "attenuated_coverage" are multiplied - // together by the fragment shader. They ramp to 0 with attenuation in - // the diagonal that points out of the corner, and linearly from - // left-edge coverage to right in the opposite diagonal. - // bloatidx=0 is the outermost vertex; the one that has attenuation. - v->codeAppend ( "attenuated_coverage = (0 == bloatidx)" - "? half2(0, attenuation) : half2(1);"); - v->codeAppend ( "if (1 == bloatidx || 2 == bloatidx) {"); - v->codeAppend ( "attenuated_coverage.x += right_coverage;"); - v->codeAppend ( "}"); - v->codeAppend ( "if (bloatidx >= 2) {"); - v->codeAppend ( "attenuated_coverage.x += left_coverage;"); + + // Corner boxes require attenuated coverage. + v->codeAppend ( "half attenuation; {"); + Shader::CalcCornerAttenuation(v, "leftdir", "rightdir", "attenuation"); v->codeAppend ( "}"); + + // Attenuate corner coverage towards the outermost vertex (where bloatidx=0). + // This is all that curves need: At each vertex of the corner box, the curve + // Shader will calculate the curve's local coverage value, interpolate it + // alongside our attenuation parameter, and multiply the two together for a + // final coverage value. + v->codeAppend ( "corner_coverage = (0 == bloatidx) ? half2(0, attenuation) : half2(1);"); + + if (3 == fNumSides) { + // For triangles we also provide the actual coverage values at each vertex of + // the corner box. + v->codeAppend ("if (1 == bloatidx || 2 == bloatidx) {"); + v->codeAppend ( "corner_coverage.x += right_coverage;"); + v->codeAppend ("}"); + v->codeAppend ("if (bloatidx >= 2) {"); + v->codeAppend ( "corner_coverage.x += left_coverage;"); + v->codeAppend ("}"); + } v->codeAppend ("}"); GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - SkString varyingCode; v->codeAppend ("coverage *= wind;"); - v->codeAppend ("attenuated_coverage.x *= wind;"); - fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &varyingCode, - gpArgs->fPositionVar.c_str(), "coverage", "attenuated_coverage"); - v->codeAppend(varyingCode.c_str()); + v->codeAppend ("corner_coverage.x *= wind;"); + fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &v->code(), + gpArgs->fPositionVar.c_str(), "coverage", "corner_coverage"); varyingHandler->emitAttributes(proc); SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform()); diff --git a/src/gpu/ccpr/GrCCCubicShader.cpp b/src/gpu/ccpr/GrCCCubicShader.cpp index c5fefdd78e..4c9485eba0 100644 --- a/src/gpu/ccpr/GrCCCubicShader.cpp +++ b/src/gpu/ccpr/GrCCCubicShader.cpp @@ -99,16 +99,16 @@ void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts, void GrCCCubicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope, SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) { - fKLMD.reset(kFloat4_GrSLType, scope); - varyingHandler->addVarying("klmd", &fKLMD); + const char* cornerCoverage) { + fKLM_fEdge.reset(kFloat4_GrSLType, scope); + varyingHandler->addVarying("klm_and_edge", &fKLM_fEdge); code->appendf("float3 klm = float3(%s, 1) * %s;", position, fKLMMatrix.c_str()); // We give L & M both the same sign as wind, in order to pass this value to the fragment shader. // (Cubics are pre-chopped such that L & M do not change sign within any individual segment.) code->appendf("%s.xyz = klm * float3(1, %s, %s);", - OutName(fKLMD), coverage, coverage); // coverage == wind on curves. + OutName(fKLM_fEdge), coverage, coverage); // coverage == wind on curves. code->appendf("%s.w = dot(float3(%s, 1), %s);", // Flat edge opposite the curve. - OutName(fKLMD), position, fEdgeDistanceEquation.c_str()); + OutName(fKLM_fEdge), position, fEdgeDistanceEquation.c_str()); fGradMatrix.reset(kFloat2x2_GrSLType, scope); varyingHandler->addVarying("grad_matrix", &fGradMatrix); @@ -117,28 +117,27 @@ void GrCCCubicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, code->appendf("%s[1] = -2*bloat * (klm[1] * %s[2].xy + klm[2] * %s[1].xy);", OutName(fGradMatrix), fKLMMatrix.c_str(), fKLMMatrix.c_str()); - if (attenuatedCoverage) { + if (cornerCoverage) { + code->appendf("half hull_coverage; {"); + this->calcHullCoverage(code, OutName(fKLM_fEdge), OutName(fGradMatrix), "hull_coverage"); + code->appendf("}"); fCornerCoverage.reset(kHalf2_GrSLType, scope); varyingHandler->addVarying("corner_coverage", &fCornerCoverage); - code->appendf("%s = %s;", // Attenuated corner coverage. - OutName(fCornerCoverage), attenuatedCoverage); + code->appendf("%s = half2(hull_coverage, 1) * %s;", + OutName(fCornerCoverage), cornerCoverage); } } void GrCCCubicShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const { - f->codeAppendf("float k = %s.x, l = %s.y, m = %s.z;", fKLMD.fsIn(), fKLMD.fsIn(), fKLMD.fsIn()); - f->codeAppend ("float f = k*k*k - l*m;"); - f->codeAppendf("float2 grad = %s * float2(k, 1);", fGradMatrix.fsIn()); - f->codeAppend ("float fwidth = abs(grad.x) + abs(grad.y);"); - f->codeAppendf("%s = clamp(0.5 - f/fwidth, 0, 1);", outputCoverage); + this->calcHullCoverage(&AccessCodeString(f), fKLM_fEdge.fsIn(), fGradMatrix.fsIn(), + outputCoverage); - f->codeAppendf("half d = min(%s.w, 0);", fKLMD.fsIn()); // Flat edge opposite the curve. // Wind is the sign of both L and/or M. Take the sign of whichever has the larger magnitude. // (In reality, either would be fine because we chop cubics with more than a half pixel of // padding around the L & M lines, so neither should approach zero.) f->codeAppend ("half wind = sign(l + m);"); - f->codeAppendf("%s = (%s + d) * wind;", outputCoverage, outputCoverage); + f->codeAppendf("%s *= wind;", outputCoverage); if (fCornerCoverage.fsIn()) { f->codeAppendf("%s = %s.x * %s.y + %s;", // Attenuated corner coverage. @@ -146,3 +145,14 @@ void GrCCCubicShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, outputCoverage); } } + +void GrCCCubicShader::calcHullCoverage(SkString* code, const char* klmAndEdge, + const char* gradMatrix, const char* outputCoverage) const { + code->appendf("float k = %s.x, l = %s.y, m = %s.z;", klmAndEdge, klmAndEdge, klmAndEdge); + code->append ("float f = k*k*k - l*m;"); + code->appendf("float2 grad = %s * float2(k, 1);", gradMatrix); + code->append ("float fwidth = abs(grad.x) + abs(grad.y);"); + code->appendf("%s = min(0.5 - f/fwidth, 1);", outputCoverage); // Curve coverage. + code->appendf("half d = min(%s.w, 0);", klmAndEdge); // Flat edge opposite the curve. + code->appendf("%s = max(%s + d, 0);", outputCoverage, outputCoverage); // Total hull coverage. +} diff --git a/src/gpu/ccpr/GrCCCubicShader.h b/src/gpu/ccpr/GrCCCubicShader.h index 39ca55fd9e..24558804a6 100644 --- a/src/gpu/ccpr/GrCCCubicShader.h +++ b/src/gpu/ccpr/GrCCCubicShader.h @@ -22,18 +22,23 @@ * (Use GrCCGeometry::cubicTo().) */ class GrCCCubicShader : public GrCCCoverageProcessor::Shader { +public: void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind, const char** tighterHull) const override; void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) override; + const char* cornerCoverage) override; void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, const char* outputCoverage) const override; +private: + void calcHullCoverage(SkString* code, const char* klmAndEdge, const char* gradMatrix, + const char* outputCoverage) const; + const GrShaderVar fKLMMatrix{"klm_matrix", kFloat3x3_GrSLType}; const GrShaderVar fEdgeDistanceEquation{"edge_distance_equation", kFloat3_GrSLType}; - GrGLSLVarying fKLMD; + GrGLSLVarying fKLM_fEdge; GrGLSLVarying fGradMatrix; GrGLSLVarying fCornerCoverage; }; diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp index 236c407ade..2398282755 100644 --- a/src/gpu/ccpr/GrCCQuadraticShader.cpp +++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp @@ -48,40 +48,51 @@ void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* p void GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope, SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) { - fCoord.reset(kFloat4_GrSLType, scope); - varyingHandler->addVarying("coord", &fCoord); + const char* cornerCoverage) { + fCoord_fGrad.reset(kFloat4_GrSLType, scope); + varyingHandler->addVarying("coord_and_grad", &fCoord_fGrad); code->appendf("%s.xy = %s * (%s - %s);", // Quadratic coords. - OutName(fCoord), fQCoordMatrix.c_str(), position, fQCoord0.c_str()); + OutName(fCoord_fGrad), fQCoordMatrix.c_str(), position, fQCoord0.c_str()); code->appendf("%s.zw = 2*bloat * float2(2 * %s.x, -1) * %s;", // Gradient. - OutName(fCoord), OutName(fCoord), fQCoordMatrix.c_str()); + OutName(fCoord_fGrad), OutName(fCoord_fGrad), fQCoordMatrix.c_str()); // Coverages need full precision since distance to the opposite edge can be large. - fCoverages.reset(attenuatedCoverage ? kFloat4_GrSLType : kFloat2_GrSLType, scope); - varyingHandler->addVarying("coverages", &fCoverages); - code->appendf("%s.x = dot(%s, float3(%s, 1));", // Distance to flat edge opposite the curve. - OutName(fCoverages), fEdgeDistanceEquation.c_str(), position); - code->appendf("%s.y = %s;", OutName(fCoverages), coverage); // Wind. - if (attenuatedCoverage) { - code->appendf("%s.zw = %s;", // Attenuated corner coverage. - OutName(fCoverages), attenuatedCoverage); + fEdge_fWind_fCorner.reset(cornerCoverage ? kFloat4_GrSLType : kFloat2_GrSLType, scope); + varyingHandler->addVarying("edge_and_wind_and_corner", &fEdge_fWind_fCorner); + code->appendf("float edge = dot(%s, float3(%s, 1));", // Distance to flat opposite edge. + fEdgeDistanceEquation.c_str(), position); + code->appendf("%s.x = edge;", OutName(fEdge_fWind_fCorner)); + code->appendf("%s.y = %s;", OutName(fEdge_fWind_fCorner), coverage); // coverage == wind. + + if (cornerCoverage) { + code->appendf("half hull_coverage;"); + this->calcHullCoverage(code, OutName(fCoord_fGrad), "edge", "hull_coverage"); + code->appendf("%s.zw = half2(hull_coverage, 1) * %s;", + OutName(fEdge_fWind_fCorner), cornerCoverage); } } void GrCCQuadraticShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const { - f->codeAppendf("float x = %s.x, y = %s.y;", fCoord.fsIn(), fCoord.fsIn()); - f->codeAppend ("float f = x*x - y;"); - f->codeAppendf("float2 grad = %s.zw;", fCoord.fsIn()); - f->codeAppend ("float fwidth = abs(grad.x) + abs(grad.y);"); - f->codeAppendf("%s = clamp(0.5 - f/fwidth, 0, 1);", outputCoverage); - - f->codeAppendf("half d = min(%s.x, 0);", fCoverages.fsIn()); // Flat edge opposite the curve. - f->codeAppendf("half wind = %s.y;", fCoverages.fsIn()); - f->codeAppendf("%s = (%s + d) * wind;", outputCoverage, outputCoverage); + this->calcHullCoverage(&AccessCodeString(f), fCoord_fGrad.fsIn(), + SkStringPrintf("%s.x", fEdge_fWind_fCorner.fsIn()).c_str(), + outputCoverage); + f->codeAppendf("%s *= %s.y;", outputCoverage, fEdge_fWind_fCorner.fsIn()); // Wind. - if (kFloat4_GrSLType == fCoverages.type()) { - f->codeAppendf("%s = %s.z * %s.w + %s;", // Attenuated corner coverage. - outputCoverage, fCoverages.fsIn(), fCoverages.fsIn(), outputCoverage); + if (kFloat4_GrSLType == fEdge_fWind_fCorner.type()) { + f->codeAppendf("%s = %s.z * %s.w + %s;",// Attenuated corner coverage. + outputCoverage, fEdge_fWind_fCorner.fsIn(), fEdge_fWind_fCorner.fsIn(), + outputCoverage); } } + +void GrCCQuadraticShader::calcHullCoverage(SkString* code, const char* coordAndGrad, + const char* edge, const char* outputCoverage) const { + code->appendf("float x = %s.x, y = %s.y;", coordAndGrad, coordAndGrad); + code->appendf("float2 grad = %s.zw;", coordAndGrad); + code->append ("float f = x*x - y;"); + code->append ("float fwidth = abs(grad.x) + abs(grad.y);"); + code->appendf("%s = min(0.5 - f/fwidth, 1);", outputCoverage); // Curve coverage. + code->appendf("half d = min(%s, 0);", edge); // Flat edge opposite the curve. + code->appendf("%s = max(%s + d, 0);", outputCoverage, outputCoverage); // Total hull coverage. +} diff --git a/src/gpu/ccpr/GrCCQuadraticShader.h b/src/gpu/ccpr/GrCCQuadraticShader.h index 30c5230154..daf9eee1ab 100644 --- a/src/gpu/ccpr/GrCCQuadraticShader.h +++ b/src/gpu/ccpr/GrCCQuadraticShader.h @@ -21,21 +21,25 @@ * (Use GrCCGeometry::quadraticTo().) */ class GrCCQuadraticShader : public GrCCCoverageProcessor::Shader { -protected: +public: void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind, const char** tighterHull) const override; void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) override; + const char* cornerCoverage) override; void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, const char* outputCoverage) const override; +private: + void calcHullCoverage(SkString* code, const char* coordAndGrad, const char* d, + const char* outputCoverage) const; + const GrShaderVar fQCoordMatrix{"qcoord_matrix", kFloat2x2_GrSLType}; const GrShaderVar fQCoord0{"qcoord0", kFloat2_GrSLType}; const GrShaderVar fEdgeDistanceEquation{"edge_distance_equation", kFloat3_GrSLType}; - GrGLSLVarying fCoord; - GrGLSLVarying fCoverages; + GrGLSLVarying fCoord_fGrad; + GrGLSLVarying fEdge_fWind_fCorner; }; #endif diff --git a/src/gpu/ccpr/GrCCTriangleShader.h b/src/gpu/ccpr/GrCCTriangleShader.h deleted file mode 100644 index f9af13c3be..0000000000 --- a/src/gpu/ccpr/GrCCTriangleShader.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCCTriangleShader_DEFINED -#define GrCCTriangleShader_DEFINED - -#include "ccpr/GrCCCoverageProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" - -/** - * This class renders AA triangles. It relies on the coverage processor to set up the geometry and - * provide coverage values at each vertex, then simply interpolates these values in the fragment - * shader. - */ -class GrCCTriangleShader : public GrCCCoverageProcessor::Shader { - void onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope, - SkString* code, const char* position, const char* coverage, - const char* attenuatedCoverage) override { - if (!attenuatedCoverage) { - fCoverages.reset(kHalf_GrSLType, scope); - varyingHandler->addVarying("coverage", &fCoverages); - code->appendf("%s = %s;", OutName(fCoverages), coverage); - } else { - fCoverages.reset(kHalf3_GrSLType, scope); - varyingHandler->addVarying("coverages", &fCoverages); - code->appendf("%s = half3(%s, %s);", OutName(fCoverages), attenuatedCoverage, coverage); - } - } - - void onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const override { - if (kHalf_GrSLType == fCoverages.type()) { - f->codeAppendf("%s = %s;", outputCoverage, fCoverages.fsIn()); - } else { - f->codeAppendf("%s = %s.x * %s.y + %s.z;", - outputCoverage, fCoverages.fsIn(), fCoverages.fsIn(), fCoverages.fsIn()); - } - } - - GrGLSLVarying fCoverages; -}; - -#endif diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h index 8459218059..cfddbfff15 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -250,6 +250,7 @@ protected: int fCodeIndex; bool fFinalized; + friend class GrCCCoverageProcessor; // to access code(). friend class GrGLSLProgramBuilder; friend class GrGLProgramBuilder; friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature. |