aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2018-04-05 18:43:40 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-06 15:59:43 +0000
commit4c2393493ad6d5f72eecd1190fee20cce732b959 (patch)
treed72cfd780ec5087ea141e7d9d7290e3424e3f348
parent0cfd547b465a3611506dc4c4c0ba973ccb2e7f30 (diff)
ccpr: Make curve corners more seamless
Interpolates the acual curve's local coverage values from the corner box vertices, rather than an approximation based on the tangent. Clamps curve segment total coverage values above 0. This prevents us from using negative coverage (which is obviously wrong) when the curve approximation function is slightly inaccurate. Moves GrCCTriangleShader.h into GrCCCoverageProcessor.cpp. Bug: skia: Change-Id: I95de8e940c1508d4a359f5f802c3a688f2b84094 Reviewed-on: https://skia-review.googlesource.com/119066 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
-rw-r--r--gn/gpu.gni1
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.cpp55
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.h18
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp99
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp71
-rw-r--r--src/gpu/ccpr/GrCCCubicShader.cpp40
-rw-r--r--src/gpu/ccpr/GrCCCubicShader.h9
-rw-r--r--src/gpu/ccpr/GrCCQuadraticShader.cpp61
-rw-r--r--src/gpu/ccpr/GrCCQuadraticShader.h12
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.h46
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.h1
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.