aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2018-03-07 17:30:10 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-08 02:19:50 +0000
commit622650a1949f9a68793ac895d9fbadee7177d860 (patch)
tree3718d4b63745f71bbc8381e8aac86c40b0aac7c8
parentdf04ce29490a24f9d5b4f5caafd8f6a3368a19e0 (diff)
ccpr: Simplify triangle corners
Modifies triangle corner shaders to just approximate their coverage with linear values that ramp to zero at bloat vertices outside the triangle. For the vertex backend, since corners now have the same fragment shader as the rest of the triangle, we fold them in with the other steps and draw triangles in a single pass. The geometry backend still draws triangles in two passes, as there is not an apparent performance advantage in combining them. Bug: skia: Change-Id: Ib4a89d793a3c706f734d0271875c8a3e5c87c49b Reviewed-on: https://skia-review.googlesource.com/112632 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
-rw-r--r--gn/gpu.gni2
-rw-r--r--samplecode/SampleCCPRGeometry.cpp4
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.cpp65
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.h130
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp107
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp521
-rw-r--r--src/gpu/ccpr/GrCCCubicShader.cpp18
-rw-r--r--src/gpu/ccpr/GrCCCubicShader.h7
-rw-r--r--src/gpu/ccpr/GrCCPathParser.cpp12
-rw-r--r--src/gpu/ccpr/GrCCQuadraticShader.cpp21
-rw-r--r--src/gpu/ccpr/GrCCQuadraticShader.h8
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.cpp151
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.h49
13 files changed, 490 insertions, 605 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 27a50a9a70..82f50ba905 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -314,8 +314,6 @@ skia_gpu_sources = [
"$_src/gpu/ccpr/GrCCPathProcessor.h",
"$_src/gpu/ccpr/GrCCQuadraticShader.cpp",
"$_src/gpu/ccpr/GrCCQuadraticShader.h",
- "$_src/gpu/ccpr/GrCCTriangleShader.cpp",
- "$_src/gpu/ccpr/GrCCTriangleShader.h",
"$_src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp",
"$_src/gpu/ccpr/GrCoverageCountingPathRenderer.h",
diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp
index 2a7d6640a6..272c59fbff 100644
--- a/samplecode/SampleCCPRGeometry.cpp
+++ b/samplecode/SampleCCPRGeometry.cpp
@@ -280,7 +280,7 @@ void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) {
if (!mesh.empty()) {
SkASSERT(1 == mesh.count());
- state->rtCommandBuffer()->draw(pipeline, proc, mesh.begin(), nullptr, 1, this->bounds());
+ proc.draw(state, pipeline, mesh.begin(), nullptr, 1, this->bounds());
}
if (glGpu) {
@@ -337,7 +337,7 @@ bool CCPRGeometryView::onQuery(SkEvent* evt) {
}
SkUnichar unichar;
if (SampleCode::CharQ(*evt, &unichar)) {
- if (unichar >= '1' && unichar <= '4') {
+ if (unichar >= '1' && unichar <= '3') {
fRenderPass = RenderPass(unichar - '1');
this->updateAndInval();
return true;
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index 76ca8f562e..3a9eb7bfa7 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -7,17 +7,21 @@
#include "GrCCCoverageProcessor.h"
+#include "GrGpuCommandBuffer.h"
+#include "GrOpFlushState.h"
#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::getGLSLProcessorKey(const GrShaderCaps&,
GrProcessorKeyBuilder* b) const {
- int key = (int)fRenderPass << 2;
+ int key = ((int)fRenderPass << 3);
+ if (GSTriangleSubpass::kCorners == fGSTriangleSubpass) {
+ key |= 4;
+ }
if (WindMethod::kInstanceData == fWindMethod) {
key |= 2;
}
@@ -36,10 +40,7 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShad
std::unique_ptr<Shader> shader;
switch (fRenderPass) {
case RenderPass::kTriangles:
- shader = skstd::make_unique<GrCCTriangleShader>();
- break;
- case RenderPass::kTriangleCorners:
- shader = skstd::make_unique<GrCCTriangleCornerShader>();
+ shader = skstd::make_unique<Shader>();
break;
case RenderPass::kQuadratics:
shader = skstd::make_unique<GrCCQuadraticShader>();
@@ -52,12 +53,45 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShad
: this->createVSImpl(std::move(shader));
}
+void GrCCCoverageProcessor::draw(GrOpFlushState* flushState, const GrPipeline& pipeline,
+ const GrMesh meshes[],
+ const GrPipeline::DynamicState dynamicStates[], int meshCount,
+ const SkRect& drawBounds) const {
+ GrGpuRTCommandBuffer* cmdBuff = flushState->rtCommandBuffer();
+ cmdBuff->draw(pipeline, *this, meshes, dynamicStates, meshCount, drawBounds);
+
+ // Geometry shader backend draws triangles in two subpasses.
+ if (RenderPass::kTriangles == fRenderPass && Impl::kGeometryShader == fImpl) {
+ SkASSERT(GSTriangleSubpass::kHullsAndEdges == fGSTriangleSubpass);
+ GrCCCoverageProcessor cornerProc(*this, GSTriangleSubpass::kCorners);
+ cmdBuff->draw(pipeline, cornerProc, meshes, dynamicStates, meshCount, drawBounds);
+ }
+}
+
+void GrCCCoverageProcessor::Shader::emitVaryings(GrGLSLVaryingHandler* varyingHandler,
+ GrGLSLVarying::Scope scope, SkString* code,
+ const char* position, const char* coverage,
+ const char* wind) {
+ SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope);
+ code->appendf("half coverageTimesWind = %s * %s;", coverage, wind);
+ CoverageHandling coverageHandling = this->onEmitVaryings(varyingHandler, scope, code, position,
+ "coverageTimesWind");
+ if (CoverageHandling::kNotHandled == coverageHandling) {
+ fCoverageTimesWind.reset(kHalf_GrSLType, scope);
+ varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
+ code->appendf("%s = coverageTimesWind;", OutName(fCoverageTimesWind));
+ }
+}
+
void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc,
GrGLSLFPFragmentBuilder* f,
const char* skOutputColor,
const char* skOutputCoverage) const {
- f->codeAppendf("half coverage = 0;");
+ f->codeAppendf("half coverage = +1;");
this->onEmitFragmentCode(proc, f, "coverage");
+ if (fCoverageTimesWind.fsIn()) {
+ f->codeAppendf("coverage *= %s;", fCoverageTimesWind.fsIn());
+ }
f->codeAppendf("%s.a = coverage;", skOutputColor);
f->codeAppendf("%s = half4(1);", skOutputCoverage);
#ifdef SK_DEBUG
@@ -102,3 +136,20 @@ void GrCCCoverageProcessor::Shader::CalcEdgeCoverageAtBloatVertex(GrGLSLVertexGe
// GPU divides by multiplying by the reciprocal?) It also guards against NaN when nwidth=0.
s->codeAppendf("%s = (abs(t) != nwidth ? t / nwidth : sign(t)) * -.5 - .5;", outputCoverage);
}
+
+void GrCCCoverageProcessor::Shader::CalcEdgeCoveragesAtBloatVertices(GrGLSLVertexGeoBuilder* s,
+ const char* leftPt,
+ const char* rightPt,
+ const char* bloatDir1,
+ const char* bloatDir2,
+ const char* outputCoverages) {
+ // See comments in CalcEdgeCoverageAtBloatVertex.
+ s->codeAppendf("float2 n = float2(%s.y - %s.y, %s.x - %s.x);",
+ rightPt, leftPt, leftPt, rightPt);
+ s->codeAppend ("float nwidth = abs(n.x) + abs(n.y);");
+ s->codeAppendf("float2 t = n * float2x2(%s, %s);", bloatDir1, bloatDir2);
+ s->codeAppendf("for (int i = 0; i < 2; ++i) {");
+ s->codeAppendf( "%s[i] = (abs(t[i]) != nwidth ? t[i] / nwidth : sign(t[i])) * -.5 - .5;",
+ outputCoverages);
+ s->codeAppendf("}");
+}
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index 7db424e219..a8ad18ce55 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -10,6 +10,7 @@
#include "GrCaps.h"
#include "GrGeometryProcessor.h"
+#include "GrPipeline.h"
#include "GrShaderCaps.h"
#include "SkNx.h"
#include "glsl/GrGLSLGeometryProcessor.h"
@@ -18,6 +19,7 @@
class GrGLSLFPFragmentBuilder;
class GrGLSLVertexGeoBuilder;
class GrMesh;
+class GrOpFlushState;
/**
* This is the geometry processor for the simple convex primitive shapes (triangles and closed,
@@ -54,11 +56,9 @@ public:
void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans, float w);
};
// Here we enumerate every render pass needed in order to produce a complete coverage count
- // mask. Triangles require two render passes: One to draw a rough outline, and a second pass to
- // touch up the corners. This is an exhaustive list of all ccpr coverage shaders.
+ // mask. This is an exhaustive list of all ccpr coverage shaders.
enum class RenderPass {
kTriangles,
- kTriangleCorners,
kQuadratics,
kCubics,
};
@@ -83,18 +83,6 @@ public:
}
}
- // Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array
- // of either TriPointInstance or QuadPointInstance, depending on this processor's RendererPass,
- // with coordinates in the desired shape's final atlas-space position.
- void appendMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
- SkTArray<GrMesh>* out) {
- if (Impl::kGeometryShader == fImpl) {
- this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out);
- } else {
- this->appendVSMesh(instanceBuffer, instanceCount, baseInstance, out);
- }
- }
-
// GrPrimitiveProcessor overrides.
const char* name() const override { return RenderPassName(fRenderPass); }
SkString dumpInfo() const override {
@@ -111,39 +99,39 @@ public:
float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }
#endif
- // The Shader provides code to calculate each pixel's coverage in a RenderPass. It also
- // provides details about shape-specific geometry.
- class Shader {
- public:
- union GeometryVars {
- struct {
- const char* fAlternatePoints; // floatNx2 (if left null, will use input points).
- } fHullVars;
-
- struct {
- const char* fPoint; // float2
- } fCornerVars;
+ // Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array
+ // of either TriPointInstance or QuadPointInstance, depending on this processor's RendererPass,
+ // with coordinates in the desired shape's final atlas-space position.
+ void appendMesh(GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
+ SkTArray<GrMesh>* out) const {
+ if (Impl::kGeometryShader == fImpl) {
+ this->appendGSMesh(instanceBuffer, instanceCount, baseInstance, out);
+ } else {
+ this->appendVSMesh(instanceBuffer, instanceCount, baseInstance, out);
+ }
+ }
- GeometryVars() { memset(this, 0, sizeof(*this)); }
- };
+ void draw(GrOpFlushState*, const GrPipeline&, const GrMesh[], const GrPipeline::DynamicState[],
+ int meshCount, const SkRect& drawBounds) const;
- // Called before generating geometry. Subclasses must fill out the applicable fields in
- // GeometryVars (if any), and may also use this opportunity to setup internal member
- // variables that will be needed during onEmitVaryings (e.g. transformation matrices).
+ // The Shader provides code to calculate a pixel's coverage.
+ class Shader {
+ public:
+ // Called before generating geometry. Subclasses may use this opportunity to setup internal
+ // member variables that will be needed during onEmitVaryings (e.g. transformation
+ // matrices).
//
- // repetitionID is a 0-based index and indicates which edge or corner is being generated.
- // It will be null when generating a hull.
- virtual void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts,
- const char* repetitionID, const char* wind,
- GeometryVars*) const {}
-
- void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
- SkString* code, const char* position, const char* inputCoverage,
- const char* wind) {
- SkASSERT(GrGLSLVarying::Scope::kVertToGeo != scope);
- this->onEmitVaryings(varyingHandler, scope, code, position, inputCoverage, wind);
+ // Returns the name of a newly defined list of points around which the Impl should generate
+ // its geometry, or null if it should just use the input points. (Regardless, the size of
+ // whatever list of points indicated should match the size expected by the Impl: 3 points
+ // for triangles, and 4 for quadratics and cubics.)
+ virtual const char* emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts) const {
+ return nullptr;
}
+ void emitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
+ const char* position, const char* coverage, const char* wind);
+
void emitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
const char* skOutputColor, const char* skOutputCoverage) const;
@@ -157,20 +145,37 @@ public:
const char* rightPt, const char* rasterVertexDir,
const char* outputCoverage);
+ // Calculates an edge's coverage at two conservative raster vertices.
+ // (See CalcEdgeCoverageAtBloatVertex).
+ static void CalcEdgeCoveragesAtBloatVertices(GrGLSLVertexGeoBuilder*, const char* leftPt,
+ const char* rightPt, const char* bloatDir1,
+ const char* bloatDir2,
+ const char* outputCoverages);
+
virtual ~Shader() {}
protected:
+ enum class CoverageHandling : bool {
+ kHandled,
+ kNotHandled
+ };
+
// Here the subclass adds its internal varyings to the handler and produces code to
- // initialize those varyings from a given position, input coverage value, and wind.
+ // initialize those varyings from a given position and coverage/wind.
//
- // NOTE: the coverage input is only relevant for triangles. Otherwise it is null.
- virtual void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
- const char* position, const char* inputCoverage,
- const char* wind) = 0;
+ // Returns whether the subclass will handle coverage modulation or if this base class should
+ // take charge of multiplying the final coverage output by 'coverageTimesWind'.
+ virtual CoverageHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope,
+ SkString* code, const char* position,
+ const char* coverageTimesWind) {
+ return CoverageHandling::kNotHandled;
+ }
- // Emits the fragment code that calculates a pixel's signed coverage value.
+ // Emits the fragment code that calculates a pixel's coverage value. If using
+ // CoverageHandling::kHandled, this value must be signed and modulated appropriately by
+ // coverage.
virtual void onEmitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
- const char* outputCoverage) const = 0;
+ const char* outputCoverage) const {}
// Returns the name of a Shader's internal varying at the point where where its value is
// assigned. This is intended to work whether called for a vertex or a geometry shader.
@@ -179,6 +184,9 @@ public:
SkASSERT(Scope::kVertToGeo != varying.scope());
return Scope::kGeoToFrag == varying.scope() ? varying.gsOut() : varying.vsOut();
}
+
+ private:
+ GrGLSLVarying fCoverageTimesWind;
};
class GSImpl;
@@ -197,6 +205,24 @@ private:
kVertexShader
};
+ // Geometry shader backend draws triangles in two subpasses.
+ enum class GSTriangleSubpass : bool {
+ kHullsAndEdges,
+ kCorners
+ };
+
+ GrCCCoverageProcessor(const GrCCCoverageProcessor& proc, GSTriangleSubpass subpass)
+ : INHERITED(kGrCCCoverageProcessor_ClassID)
+ , fRenderPass(RenderPass::kTriangles)
+ , fWindMethod(proc.fWindMethod)
+ , fImpl(Impl::kGeometryShader)
+ SkDEBUGCODE(, fDebugBloat(proc.fDebugBloat))
+ , fGSTriangleSubpass(subpass) {
+ SkASSERT(RenderPass::kTriangles == proc.fRenderPass);
+ SkASSERT(Impl::kGeometryShader == proc.fImpl);
+ this->initGS();
+ }
+
void initGS();
void initVS(GrResourceProvider*);
@@ -213,6 +239,9 @@ private:
const Impl fImpl;
SkDEBUGCODE(float fDebugBloat = 0);
+ // Used by GSImpl.
+ const GSTriangleSubpass fGSTriangleSubpass = GSTriangleSubpass::kHullsAndEdges;
+
// Used by VSImpl.
sk_sp<const GrBuffer> fVertexBuffer;
sk_sp<const GrBuffer> fIndexBuffer;
@@ -254,7 +283,6 @@ inline void GrCCCoverageProcessor::QuadPointInstance::set(const SkPoint& p0, con
inline const char* GrCCCoverageProcessor::RenderPassName(RenderPass pass) {
switch (pass) {
case RenderPass::kTriangles: return "kTriangles";
- case RenderPass::kTriangleCorners: return "kTriangleCorners";
case RenderPass::kQuadratics: return "kQuadratics";
case RenderPass::kCubics: return "kCubics";
}
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
index e64b8c0838..1fef1c3338 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
@@ -75,10 +75,7 @@ protected:
SkString emitVertexFn;
SkSTArray<2, GrShaderVar> emitArgs;
const char* position = emitArgs.emplace_back("position", kFloat2_GrSLType).c_str();
- const char* coverage = nullptr;
- if (RenderPass::kTriangleCorners != proc.fRenderPass) {
- coverage = emitArgs.emplace_back("coverage", kHalf_GrSLType).c_str();
- }
+ const char* coverage = emitArgs.emplace_back("coverage", kHalf_GrSLType).c_str();
g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() {
SkString fnBody;
fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kGeoToFrag, &fnBody,
@@ -116,7 +113,7 @@ protected:
* coverage ramp from -1 to 0. These edge coverage values convert jagged conservative raster edges
* into smooth, antialiased ones.
*
- * The final corners get touched up in a later step by GSCornerImpl.
+ * The final corners get touched up in a later step by GSTriangleCornerImpl.
*/
class GSTriangleImpl : public GrCCCoverageProcessor::GSImpl {
public:
@@ -124,6 +121,8 @@ public:
void onEmitGeometryShader(GrGLSLGeometryBuilder* g, const GrShaderVar& wind,
const char* emitVertexFn) const override {
+ SkAssertResult(!fShader->emitSetupCode(g, "pts"));
+
// Visualize the input triangle as upright and equilateral, with a flat base. Paying special
// attention to wind, we can identify the points as top, bottom-left, and bottom-right.
//
@@ -212,19 +211,69 @@ public:
};
/**
+ * Generates conservative rasters around triangle corners (aka pixel-size boxes) and calculates
+ * coverage ramps that fix up the coverage values written by GSTriangleImpl.
+ */
+class GSTriangleCornerImpl : public GrCCCoverageProcessor::GSImpl {
+public:
+ GSTriangleCornerImpl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {}
+
+ void onEmitGeometryShader(GrGLSLGeometryBuilder* g, const GrShaderVar& wind,
+ const char* emitVertexFn) const override {
+ SkAssertResult(!fShader->emitSetupCode(g, "pts"));
+
+ g->codeAppendf("float2 corner = pts[sk_InvocationID];");
+ g->codeAppendf("float2 left = pts[(sk_InvocationID + (%s > 0 ? 2 : 1)) %% 3];",
+ wind.c_str());
+ g->codeAppendf("float2 right = pts[(sk_InvocationID + (%s > 0 ? 1 : 2)) %% 3];",
+ wind.c_str());
+
+ // Find "outbloat" and "crossbloat" at our corner. The outbloat points diagonally out of the
+ // triangle, in the direction that should ramp to zero coverage. The crossbloat runs
+ // perpindicular to outbloat, and ramps from left-edge coverage to right-edge coverage.
+ g->codeAppend ("float2 leftdir = normalize(corner - left);");
+ g->codeAppend ("float2 rightdir = normalize(right - corner);");
+ g->codeAppend ("float2 outbloat = float2(leftdir.x > rightdir.x ? +1 : -1, "
+ "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 ("}");
+
+ g->codeAppend ("half2 right_coverages; {");
+ Shader::CalcEdgeCoveragesAtBloatVertices(g, "corner", "right", "outbloat", "-crossbloat",
+ "right_coverages");
+ g->codeAppend ("}");
+
+ // Emit a corner box that erases whatever coverage was written previously, and replaces it
+ // using linearly-interpolated values that ramp to zero in bloat vertices that fall outside
+ // the triangle.
+ //
+ // NOTE: Since this is not a linear mapping, it is important that the box's diagonal shared
+ // edge points out of the triangle as much as possible.
+ g->codeAppendf("%s(corner - crossbloat * bloat, -right_coverages[1]);", emitVertexFn);
+ g->codeAppendf("%s(corner + outbloat * bloat, "
+ "-1 - left_coverages[0] - right_coverages[0]);", emitVertexFn);
+ g->codeAppendf("%s(corner - outbloat * bloat, 0);", emitVertexFn);
+ g->codeAppendf("%s(corner + crossbloat * bloat, -left_coverages[1]);", emitVertexFn);
+
+ g->configure(InputType::kLines, OutputType::kTriangleStrip, 4, 3);
+ }
+};
+
+/**
* Generates a conservative raster hull around a convex quadrilateral that encloses a cubic or
* quadratic, as well as its shared edge.
*/
-class GSHull4Impl : public GrCCCoverageProcessor::GSImpl {
+class GSCurveImpl : public GrCCCoverageProcessor::GSImpl {
public:
- GSHull4Impl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {}
+ GSCurveImpl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {}
void onEmitGeometryShader(GrGLSLGeometryBuilder* g, const GrShaderVar& wind,
const char* emitVertexFn) const override {
- Shader::GeometryVars vars;
- fShader->emitSetupCode(g, "pts", nullptr, wind.c_str(), &vars);
-
- const char* hullPts = vars.fHullVars.fAlternatePoints;
+ const char* hullPts = fShader->emitSetupCode(g, "pts");
if (!hullPts) {
hullPts = "pts";
}
@@ -314,34 +363,6 @@ public:
}
};
-/**
- * Generates conservative rasters around corners. (See comments for RenderPass)
- */
-class GSCornerImpl : public GrCCCoverageProcessor::GSImpl {
-public:
- GSCornerImpl(std::unique_ptr<Shader> shader, int numCorners)
- : GSImpl(std::move(shader)), fNumCorners(numCorners) {}
-
- void onEmitGeometryShader(GrGLSLGeometryBuilder* g, const GrShaderVar& wind,
- const char* emitVertexFn) const override {
- Shader::GeometryVars vars;
- fShader->emitSetupCode(g, "pts", "sk_InvocationID", wind.c_str(), &vars);
-
- const char* corner = vars.fCornerVars.fPoint;
- SkASSERT(corner);
-
- g->codeAppendf("%s(%s + float2(-bloat, -bloat));", emitVertexFn, corner);
- g->codeAppendf("%s(%s + float2(-bloat, +bloat));", emitVertexFn, corner);
- g->codeAppendf("%s(%s + float2(+bloat, -bloat));", emitVertexFn, corner);
- g->codeAppendf("%s(%s + float2(+bloat, +bloat));", emitVertexFn, corner);
-
- g->configure(InputType::kLines, OutputType::kTriangleStrip, 4, fNumCorners);
- }
-
-private:
- const int fNumCorners;
-};
-
void GrCCCoverageProcessor::initGS() {
SkASSERT(Impl::kGeometryShader == fImpl);
if (RenderPass::kCubics == fRenderPass || WindMethod::kInstanceData == fWindMethod) {
@@ -372,12 +393,12 @@ void GrCCCoverageProcessor::appendGSMesh(GrBuffer* instanceBuffer, int instanceC
GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGSImpl(std::unique_ptr<Shader> shadr) const {
switch (fRenderPass) {
case RenderPass::kTriangles:
- return new GSTriangleImpl(std::move(shadr));
- case RenderPass::kTriangleCorners:
- return new GSCornerImpl(std::move(shadr), 3);
+ return (GSTriangleSubpass::kHullsAndEdges == fGSTriangleSubpass)
+ ? (GSImpl*) new GSTriangleImpl(std::move(shadr))
+ : (GSImpl*) new GSTriangleCornerImpl(std::move(shadr));
case RenderPass::kQuadratics:
case RenderPass::kCubics:
- return new GSHull4Impl(std::move(shadr));
+ return new GSCurveImpl(std::move(shadr));
}
SK_ABORT("Invalid RenderPass");
return nullptr;
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
index 08398e1900..c64ee755fe 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
@@ -10,89 +10,15 @@
#include "GrMesh.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
-using Shader = GrCCCoverageProcessor::Shader;
-
static constexpr int kAttribIdx_X = 0;
static constexpr int kAttribIdx_Y = 1;
static constexpr int kAttribIdx_VertexData = 2;
-/**
- * This class and its subclasses implement the coverage processor with vertex shaders.
- */
-class GrCCCoverageProcessor::VSImpl : public GrGLSLGeometryProcessor {
-protected:
- VSImpl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
-
- void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
- FPCoordTransformIter&& transformIter) final {
- this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
- }
-
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
- const GrCCCoverageProcessor& proc = args.fGP.cast<GrCCCoverageProcessor>();
-
- // Vertex shader.
- GrGLSLVertexBuilder* v = args.fVertBuilder;
- int numInputPoints = proc.numInputPoints();
-
- const char* swizzle = (4 == numInputPoints) ? "xyzw" : "xyz";
- v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));",
- numInputPoints, numInputPoints, proc.getAttrib(kAttribIdx_X).fName, swizzle,
- proc.getAttrib(kAttribIdx_Y).fName, swizzle);
-
- if (WindMethod::kCrossProduct == proc.fWindMethod) {
- v->codeAppend ("float area_x2 = determinant(float2x2(pts[0] - pts[1], "
- "pts[0] - pts[2]));");
- if (4 == numInputPoints) {
- v->codeAppend ("area_x2 += determinant(float2x2(pts[0] - pts[2], "
- "pts[0] - pts[3]));");
- }
- v->codeAppend ("half wind = sign(area_x2);");
- } else {
- SkASSERT(WindMethod::kInstanceData == proc.fWindMethod);
- SkASSERT(3 == numInputPoints);
- SkASSERT(kFloat4_GrVertexAttribType == proc.getAttrib(kAttribIdx_X).fType);
- v->codeAppendf("half wind = %s.w;", proc.getAttrib(kAttribIdx_X).fName);
- }
-
- float bloat = kAABloatRadius;
-#ifdef SK_DEBUG
- if (proc.debugVisualizationsEnabled()) {
- bloat *= proc.debugBloat();
- }
-#endif
- v->defineConstant("bloat", bloat);
-
- const char* coverage = this->emitVertexPosition(proc, v, gpArgs);
- SkASSERT(kFloat2_GrSLType == gpArgs->fPositionVar.getType());
-
- GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
- SkString varyingCode;
- fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &varyingCode,
- gpArgs->fPositionVar.c_str(), coverage, "wind");
- v->codeAppend(varyingCode.c_str());
-
- varyingHandler->emitAttributes(proc);
- SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
-
- // Fragment shader.
- fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
- }
-
- virtual const char* emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder*,
- GrGPArgs*) const = 0;
-
- virtual ~VSImpl() {}
-
- const std::unique_ptr<Shader> fShader;
-
- typedef GrGLSLGeometryProcessor INHERITED;
-};
-
-static constexpr int kVertexData_LeftNeighborIdShift = 9;
-static constexpr int kVertexData_RightNeighborIdShift = 7;
-static constexpr int kVertexData_BloatIdxShift = 5;
-static constexpr int kVertexData_InvertNegativeCoverageBit = 1 << 4;
+static constexpr int kVertexData_LeftNeighborIdShift = 10;
+static constexpr int kVertexData_RightNeighborIdShift = 8;
+static constexpr int kVertexData_BloatIdxShift = 6;
+static constexpr int kVertexData_InvertNegativeCoverageBit = 1 << 5;
+static constexpr int kVertexData_IsCornerBit = 1 << 4;
static constexpr int kVertexData_IsEdgeBit = 1 << 3;
static constexpr int kVertexData_IsHullBit = 1 << 2;
@@ -119,8 +45,12 @@ static constexpr int32_t edge_vertex_data(int32_t leftID, int rightID, int32_t b
return pack_vertex_data(leftID, leftID, bloatIdx, rightID, kVertexData_IsEdgeBit | extraData);
}
+static constexpr int32_t triangle_corner_vertex_data(int32_t cornerID, int32_t bloatIdx) {
+ return pack_vertex_data((cornerID + 2) % 3, (cornerID + 1) % 3, bloatIdx, cornerID,
+ kVertexData_IsCornerBit);
+}
-static constexpr int32_t kHull3AndEdgeVertices[] = {
+static constexpr int32_t kTriangleVertices[] = {
hull_vertex_data(0, 0, 3),
hull_vertex_data(0, 1, 3),
hull_vertex_data(0, 2, 3),
@@ -151,21 +81,39 @@ static constexpr int32_t kHull3AndEdgeVertices[] = {
edge_vertex_data(0, 2, 0, kVertexData_InvertNegativeCoverageBit),
edge_vertex_data(0, 2, 1, kVertexData_InvertNegativeCoverageBit),
edge_vertex_data(0, 2, 2, kVertexData_InvertNegativeCoverageBit),
+
+ triangle_corner_vertex_data(0, 0),
+ triangle_corner_vertex_data(0, 1),
+ triangle_corner_vertex_data(0, 2),
+ triangle_corner_vertex_data(0, 3),
+
+ triangle_corner_vertex_data(1, 0),
+ triangle_corner_vertex_data(1, 1),
+ triangle_corner_vertex_data(1, 2),
+ triangle_corner_vertex_data(1, 3),
+
+ triangle_corner_vertex_data(2, 0),
+ triangle_corner_vertex_data(2, 1),
+ triangle_corner_vertex_data(2, 2),
+ triangle_corner_vertex_data(2, 3),
};
-GR_DECLARE_STATIC_UNIQUE_KEY(gHull3AndEdgeVertexBufferKey);
+GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey);
static constexpr uint16_t kRestartStrip = 0xffff;
-static constexpr uint16_t kHull3AndEdgeIndicesAsStrips[] = {
+static constexpr uint16_t kTriangleIndicesAsStrips[] = {
1, 2, 0, 3, 8, kRestartStrip, // First corner and main body of the hull.
4, 5, 3, 6, 8, 7, kRestartStrip, // Opposite side and corners of the hull.
10, 9, 11, 14, 12, 13, kRestartStrip, // First edge.
16, 15, 17, 20, 18, 19, kRestartStrip, // Second edge.
- 22, 21, 23, 26, 24, 25 // Third edge.
+ 22, 21, 23, 26, 24, 25, kRestartStrip, // Third edge.
+ 27, 28, 30, 29, kRestartStrip, // First corner.
+ 31, 32, 34, 33, kRestartStrip, // Second corner.
+ 35, 36, 38, 37 // Third corner.
};
-static constexpr uint16_t kHull3AndEdgeIndicesAsTris[] = {
+static constexpr uint16_t kTriangleIndicesAsTris[] = {
// First corner and main body of the hull.
1, 2, 0,
2, 3, 0,
@@ -194,9 +142,21 @@ static constexpr uint16_t kHull3AndEdgeIndicesAsTris[] = {
21, 26, 23,
23, 26, 24,
26, 25, 24,
+
+ // First corner.
+ 27, 28, 30,
+ 28, 29, 30,
+
+ // Second corner.
+ 31, 32, 34,
+ 32, 33, 34,
+
+ // Third corner.
+ 35, 36, 38,
+ 36, 37, 38,
};
-GR_DECLARE_STATIC_UNIQUE_KEY(gHull3AndEdgeIndexBufferKey);
+GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
static constexpr int32_t kHull4AndEdgeVertices[] = {
hull_vertex_data(0, 0, 4),
@@ -252,162 +212,229 @@ static constexpr uint16_t kHull4AndEdgeIndicesAsTris[] = {
GR_DECLARE_STATIC_UNIQUE_KEY(gHull4AndEdgeIndexBufferKey);
+
/**
- * Generates a conservative raster hull around a triangle or curve. For triangles we generate
- * additional conservative rasters with coverage ramps around the edges. For curves we
- * generate an additional raster with coverage ramps around its shared edge.
- *
- * Triangle rough outlines are drawn in two steps: (1) Draw a conservative raster of the entire
- * triangle, with a coverage of +1. (2) Draw conservative rasters around each edge, with a
- * coverage ramp from -1 to 0. These edge coverage values convert jagged conservative raster edges
- * into smooth, antialiased ones. The final corners get touched up in a later step by VSCornerImpl.
- *
- * Curves are drawn in two steps: (1) Draw a conservative raster around the input points, passing
- * coverage=+1 to the Shader. (2) Draw an additional conservative raster around the curve's shared
- * edge, using coverage=-1 at bloat vertices that fall outside the input points. This erases what
- * the hull just wrote and ramps coverage to zero.
+ * This class and its subclasses implement the coverage processor with vertex shaders.
*/
-class VSHullAndEdgeImpl : public GrCCCoverageProcessor::VSImpl {
+class GrCCCoverageProcessor::VSImpl : public GrGLSLGeometryProcessor {
public:
- VSHullAndEdgeImpl(std::unique_ptr<Shader> shader, int numSides)
- : VSImpl(std::move(shader)), fNumSides(numSides) {}
+ VSImpl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
- const char* emitVertexPosition(const GrCCCoverageProcessor& proc, GrGLSLVertexBuilder* v,
- GrGPArgs* gpArgs) const override {
- Shader::GeometryVars vars;
- fShader->emitSetupCode(v, "pts", nullptr, "wind", &vars);
+private:
+ void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
+ FPCoordTransformIter&& transformIter) override {
+ this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
+ }
- const char* hullPts = vars.fHullVars.fAlternatePoints;
- if (!hullPts) {
- hullPts = "pts";
- }
+ void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override;
- // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0].
- v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;",
- proc.getAttrib(kAttribIdx_VertexData).fName,
- ((fNumSides - 1) << kVertexData_LeftNeighborIdShift) |
- ((fNumSides - 1) << kVertexData_RightNeighborIdShift) |
- (((1 << kVertexData_RightNeighborIdShift) - 1) ^ 3) |
- (fNumSides - 1),
- proc.getAttrib(kAttribIdx_VertexData).fName);
-
- // Here we generate conservative raster geometry for the input polygon. It is the convex
- // hull of N pixel-size boxes, one centered on each the input points. Each corner has three
- // vertices, where one or two may cause degenerate triangles. The vertex data tells us how
- // to offset each vertex. Edges are also handled here using the same concept. For more
- // details on conservative raster, see:
- // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html
- v->codeAppendf("float2 corner = %s[clockwise_indices & 3];", hullPts);
- v->codeAppendf("float2 left = %s[clockwise_indices >> %i];",
- hullPts, kVertexData_LeftNeighborIdShift);
- v->codeAppendf("float2 right = %s[(clockwise_indices >> %i) & 3];",
- hullPts, kVertexData_RightNeighborIdShift);
-
- v->codeAppend ("float2 leftbloat = sign(corner - left);");
- v->codeAppend ("leftbloat = float2(0 != leftbloat.y ? leftbloat.y : leftbloat.x, "
- "0 != leftbloat.x ? -leftbloat.x : -leftbloat.y);");
-
- v->codeAppend ("float2 rightbloat = sign(right - corner);");
- v->codeAppend ("rightbloat = float2(0 != rightbloat.y ? rightbloat.y : rightbloat.x, "
- "0 != rightbloat.x ? -rightbloat.x : -rightbloat.y);");
-
- v->codeAppend ("bool2 left_right_notequal = notEqual(leftbloat, rightbloat);");
-
- // At each corner of the polygon, our hull will have either 1, 2, or 3 vertices. We begin
- // with the first hull vertex (leftbloat), then continue rotating 90 degrees clockwise until
- // we reach the desired vertex for this invocation. Corners with less than 3 corresponding
- // hull vertices will result in redundant vertices and degenerate triangles.
- v->codeAppend ("float2 bloatdir = leftbloat;");
- v->codeAppendf("int bloatidx = (%s >> %i) & 3;",
- proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_BloatIdxShift);
- v->codeAppend ("switch (bloatidx) {");
- v->codeAppend ( "case 2:");
- v->codeAppendf( "if (all(left_right_notequal)) {");
- v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);");
- v->codeAppend ( "}");
- // fallthru.
- v->codeAppend ( "case 1:");
- v->codeAppendf( "if (any(left_right_notequal)) {");
- v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);");
- v->codeAppend ( "}");
- // fallthru.
- v->codeAppend ("}");
+ const char* emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder*,
+ GrGPArgs*) const;
- v->codeAppend ("float2 vertex = corner + bloatdir * bloat;");
- gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
-
- // The hull has a coverage of +1 all around.
- v->codeAppend ("half coverage = +1;");
-
- if (3 == fNumSides) {
- v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge?
- proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsEdgeBit);
- Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "coverage");
- v->codeAppend ("}");
- } else {
- SkASSERT(4 == fNumSides);
- v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge?
- proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsEdgeBit);
- v->codeAppend ( "coverage = -1;");
- v->codeAppend ("}");
- }
+ const std::unique_ptr<Shader> fShader;
+};
- v->codeAppendf("if (0 != (%s & %i)) {", // Invert coverage?
- proc.getAttrib(kAttribIdx_VertexData).fName,
- kVertexData_InvertNegativeCoverageBit);
- v->codeAppend ( "coverage = -1 - coverage;");
- v->codeAppend ("}");
+void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
+ const GrCCCoverageProcessor& proc = args.fGP.cast<GrCCCoverageProcessor>();
- return "coverage";
- }
+ // Vertex shader.
+ GrGLSLVertexBuilder* v = args.fVertBuilder;
+ int numInputPoints = proc.numInputPoints();
-private:
- const int fNumSides;
-};
+ const char* swizzle = (4 == numInputPoints) ? "xyzw" : "xyz";
+ v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));",
+ numInputPoints, numInputPoints, proc.getAttrib(kAttribIdx_X).fName, swizzle,
+ proc.getAttrib(kAttribIdx_Y).fName, swizzle);
-static constexpr uint16_t kCornerIndicesAsStrips[] = {
- 0, 1, 2, 3, kRestartStrip, // First corner.
- 4, 5, 6, 7, kRestartStrip, // Second corner.
- 8, 9, 10, 11 // Third corner.
-};
+ if (WindMethod::kCrossProduct == proc.fWindMethod) {
+ v->codeAppend ("float area_x2 = determinant(float2x2(pts[0] - pts[1], "
+ "pts[0] - pts[2]));");
+ if (4 == numInputPoints) {
+ v->codeAppend ("area_x2 += determinant(float2x2(pts[0] - pts[2], "
+ "pts[0] - pts[3]));");
+ }
+ v->codeAppend ("half wind = sign(area_x2);");
+ } else {
+ SkASSERT(WindMethod::kInstanceData == proc.fWindMethod);
+ SkASSERT(3 == numInputPoints);
+ SkASSERT(kFloat4_GrVertexAttribType == proc.getAttrib(kAttribIdx_X).fType);
+ v->codeAppendf("half wind = %s.w;", proc.getAttrib(kAttribIdx_X).fName);
+ }
-static constexpr uint16_t kCornerIndicesAsTris[] = {
- // First corner.
- 0, 1, 2,
- 1, 3, 2,
+ float bloat = kAABloatRadius;
+#ifdef SK_DEBUG
+ if (proc.debugVisualizationsEnabled()) {
+ bloat *= proc.debugBloat();
+ }
+#endif
+ v->defineConstant("bloat", bloat);
- // Second corner.
- 4, 5, 6,
- 5, 7, 6,
+ const char* coverage = this->emitVertexPosition(proc, v, gpArgs);
+ SkASSERT(kFloat2_GrSLType == gpArgs->fPositionVar.getType());
- // Third corner.
- 8, 9, 10,
- 9, 11, 10,
-};
+ GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
+ SkString varyingCode;
+ fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &varyingCode,
+ gpArgs->fPositionVar.c_str(), coverage, "wind");
+ v->codeAppend(varyingCode.c_str());
+
+ varyingHandler->emitAttributes(proc);
+ SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
-GR_DECLARE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey);
+ // Fragment shader.
+ fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
+}
/**
- * Generates conservative rasters around corners. (See comments for RenderPass)
+ * Generates a conservative raster hull around a triangle or curve. For triangles we generate
+ * additional conservative rasters with coverage ramps around the edges. For curves we generate an
+ * additional raster with coverage ramps around its shared edge.
+ *
+ * Triangles are drawn in three steps: (1) Draw a conservative raster of the entire triangle, with a
+ * coverage of +1. (2) Draw conservative rasters around each edge, with a coverage ramp from -1 to
+ * 0. These edge coverage values convert jagged conservative raster edges into smooth, antialiased
+ * ones. (3) Draw conservative rasters (aka pixel-size boxes) around each corner, replacing the
+ * previous coverage values with ones that ramp to zero in the bloat vertices that fall outside the
+ * triangle.
+ *
+ * Curves are drawn in two steps: (1) Draw a conservative raster around the input points, passing
+ * coverage=+1 to the Shader. (2) Draw an additional conservative raster around the curve's shared
+ * edge, using coverage=-1 at bloat vertices that fall outside the input points. This erases what
+ * the hull just wrote and ramps coverage to zero.
*/
-class VSCornerImpl : public GrCCCoverageProcessor::VSImpl {
-public:
- VSCornerImpl(std::unique_ptr<Shader> shader) : VSImpl(std::move(shader)) {}
+const char* GrCCCoverageProcessor::VSImpl::emitVertexPosition(const GrCCCoverageProcessor& proc,
+ GrGLSLVertexBuilder* v,
+ GrGPArgs* gpArgs) const {
+ int numSides = (RenderPass::kTriangles == proc.fRenderPass) ? 3 : 4;
+ const char* hullPts = fShader->emitSetupCode(v, "pts");
+ if (!hullPts) {
+ SkASSERT(numSides == proc.numInputPoints());
+ hullPts = "pts";
+ }
- const char* emitVertexPosition(const GrCCCoverageProcessor&, GrGLSLVertexBuilder* v,
- GrGPArgs* gpArgs) const override {
- Shader::GeometryVars vars;
- v->codeAppend ("int corner_id = sk_VertexID / 4;");
- fShader->emitSetupCode(v, "pts", "corner_id", "wind", &vars);
+ // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0].
+ v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;",
+ proc.getAttrib(kAttribIdx_VertexData).fName,
+ ((numSides - 1) << kVertexData_LeftNeighborIdShift) |
+ ((numSides - 1) << kVertexData_RightNeighborIdShift) |
+ (((1 << kVertexData_RightNeighborIdShift) - 1) ^ 3) |
+ (numSides - 1),
+ proc.getAttrib(kAttribIdx_VertexData).fName);
+
+ // Here we generate conservative raster geometry for the input polygon. It is the convex hull of
+ // N pixel-size boxes, one centered on each the input points. Each corner has three vertices,
+ // where one or two may cause degenerate triangles. The vertex data tells us how to offset each
+ // vertex. Edges are also handled here using the same concept. For more details on conservative
+ // raster, see: https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html
+ v->codeAppendf("float2 corner = %s[clockwise_indices & 3];", hullPts);
+ v->codeAppendf("float2 left = %s[clockwise_indices >> %i];",
+ hullPts, kVertexData_LeftNeighborIdShift);
+ v->codeAppendf("float2 right = %s[(clockwise_indices >> %i) & 3];",
+ hullPts, kVertexData_RightNeighborIdShift);
+
+ v->codeAppend ("float2 leftbloat = sign(corner - left);");
+ v->codeAppend ("leftbloat = float2(0 != leftbloat.y ? leftbloat.y : leftbloat.x, "
+ "0 != leftbloat.x ? -leftbloat.x : -leftbloat.y);");
+
+ v->codeAppend ("float2 rightbloat = sign(right - corner);");
+ v->codeAppend ("rightbloat = float2(0 != rightbloat.y ? rightbloat.y : rightbloat.x, "
+ "0 != rightbloat.x ? -rightbloat.x : -rightbloat.y);");
+
+ v->codeAppend ("bool2 left_right_notequal = notEqual(leftbloat, rightbloat);");
+
+ v->codeAppend ("float2 bloatdir = leftbloat;");
+
+ if (RenderPass::kTriangles == proc.fRenderPass) { // Only triangles emit corner boxes.
+ v->codeAppendf("if (0 != (%s & %i)) {", // Are we a corner?
+ proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsCornerBit);
+
+ // For corner boxes, we hack 'left_right_notequal' to [true, true]. This
+ // causes the upcoming code to always rotate, which is the right thing
+ // for corners.
+ v->codeAppendf( "left_right_notequal = bool2(true, true);");
+
+ // In corner boxes, all 4 coverage values will not map linearly, so it is
+ // important to rotate the box so its diagonal shared edge points out of
+ // the triangle, in the direction that ramps to zero.
+ v->codeAppend ( "float2 bisect = normalize(corner - right) + normalize(corner - left);");
+ v->codeAppend ( "if (sign(bisect) == sign(leftbloat)) {");
+ v->codeAppend ( "bloatdir = float2(+bloatdir.y, -bloatdir.x);");
+ v->codeAppend ( "}");
+ v->codeAppend ("}");
+ }
- v->codeAppendf("float2 vertex = %s;", vars.fCornerVars.fPoint);
- v->codeAppend ("vertex.x += (0 == (sk_VertexID & 2)) ? -bloat : +bloat;");
- v->codeAppend ("vertex.y += (0 == (sk_VertexID & 1)) ? -bloat : +bloat;");
+ // At each corner of the polygon, our hull will have either 1, 2, or 3 vertices (or 4 if it's a
+ // corner box). We begin with the first hull vertex (leftbloat), then continue rotating 90
+ // degrees clockwise until we reach the desired vertex for this invocation. Corners with less
+ // than 3 corresponding hull vertices will result in redundant vertices and degenerate
+ // triangles.
+ v->codeAppendf("int bloatidx = (%s >> %i) & 3;",
+ proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_BloatIdxShift);
+ v->codeAppend ("switch (bloatidx) {");
+ if (RenderPass::kTriangles == proc.fRenderPass) { // Only triangles emit corner boxes.
+ v->codeAppend ( "case 3:");
+ // Only corners will have bloatidx=3, and corners always rotate.
+ v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);"); // 90 deg CW.
+ // fallthru.
+ }
+ v->codeAppend ( "case 2:");
+ v->codeAppendf( "if (all(left_right_notequal)) {");
+ v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);"); // 90 deg CW.
+ v->codeAppend ( "}");
+ // fallthru.
+ v->codeAppend ( "case 1:");
+ v->codeAppendf( "if (any(left_right_notequal)) {");
+ v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);"); // 90 deg CW.
+ v->codeAppend ( "}");
+ // fallthru.
+ v->codeAppend ("}");
+
+ v->codeAppend ("float2 vertex = corner + bloatdir * bloat;");
+ gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
+
+ // The hull has a coverage of +1 all around.
+ v->codeAppend ("half coverage = +1;");
+
+ if (RenderPass::kTriangles == proc.fRenderPass) {
+ v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge OR corner?
+ proc.getAttrib(kAttribIdx_VertexData).fName,
+ kVertexData_IsEdgeBit | kVertexData_IsCornerBit);
+ Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "coverage");
+ v->codeAppend ("}");
- gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
- return nullptr; // Corner vertices don't have an initial coverage value.
+ v->codeAppendf("if (0 != (%s & %i)) {", // Are we a corner?
+ proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsCornerBit);
+ // Corner boxes erase whatever coverage was written previously, and
+ // replace it with linearly-interpolated values that ramp to zero in the
+ // diagonal that points out of the triangle, and ramp from left-edge
+ // coverage to right-edge coverage in the other diagonal.
+ v->codeAppend ( "half left_coverage = coverage;");
+ v->codeAppend ( "half right_coverage;");
+ Shader::CalcEdgeCoverageAtBloatVertex(v, "corner", "right", "bloatdir",
+ "right_coverage");
+ v->codeAppend ( "coverage = (1 == bloatidx) ? -1 : 0;");
+ v->codeAppend ( "if (((bloatidx + 3) & 3) < 2) {");
+ v->codeAppend ( "coverage -= left_coverage;");
+ v->codeAppend ( "}");
+ v->codeAppend ( "if (bloatidx < 2) {");
+ v->codeAppend ( "coverage -= right_coverage;");
+ v->codeAppend ( "}");
+ v->codeAppend ("}");
+ } else {
+ v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge?
+ proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsEdgeBit);
+ v->codeAppend ( "coverage = -1;");
+ v->codeAppend ("}");
}
-};
+
+ v->codeAppendf("if (0 != (%s & %i)) {", // Invert coverage?
+ proc.getAttrib(kAttribIdx_VertexData).fName,
+ kVertexData_InvertNegativeCoverageBit);
+ v->codeAppend ( "coverage = -1 - coverage;");
+ v->codeAppend ("}");
+
+ return "coverage";
+}
void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) {
SkASSERT(Impl::kVertexShader == fImpl);
@@ -415,42 +442,24 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) {
switch (fRenderPass) {
case RenderPass::kTriangles: {
- GR_DEFINE_STATIC_UNIQUE_KEY(gHull3AndEdgeVertexBufferKey);
+ GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey);
fVertexBuffer = rp->findOrMakeStaticBuffer(kVertex_GrBufferType,
- sizeof(kHull3AndEdgeVertices),
- kHull3AndEdgeVertices,
- gHull3AndEdgeVertexBufferKey);
- GR_DEFINE_STATIC_UNIQUE_KEY(gHull3AndEdgeIndexBufferKey);
- if (caps.usePrimitiveRestart()) {
- fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType,
- sizeof(kHull3AndEdgeIndicesAsStrips),
- kHull3AndEdgeIndicesAsStrips,
- gHull3AndEdgeIndexBufferKey);
- fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull3AndEdgeIndicesAsStrips);
- } else {
- fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType,
- sizeof(kHull3AndEdgeIndicesAsTris),
- kHull3AndEdgeIndicesAsTris,
- gHull3AndEdgeIndexBufferKey);
- fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull3AndEdgeIndicesAsTris);
- }
- break;
- }
-
- case RenderPass::kTriangleCorners: {
- GR_DEFINE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey);
+ sizeof(kTriangleVertices),
+ kTriangleVertices,
+ gTriangleVertexBufferKey);
+ GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
if (caps.usePrimitiveRestart()) {
fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType,
- sizeof(kCornerIndicesAsStrips),
- kCornerIndicesAsStrips,
- gCornerIndexBufferKey);
- fNumIndicesPerInstance = SK_ARRAY_COUNT(kCornerIndicesAsStrips);
+ sizeof(kTriangleIndicesAsStrips),
+ kTriangleIndicesAsStrips,
+ gTriangleIndexBufferKey);
+ fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips);
} else {
fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType,
- sizeof(kCornerIndicesAsTris),
- kCornerIndicesAsTris,
- gCornerIndexBufferKey);
- fNumIndicesPerInstance = SK_ARRAY_COUNT(kCornerIndicesAsTris);
+ sizeof(kTriangleIndicesAsTris),
+ kTriangleIndicesAsTris,
+ gTriangleIndexBufferKey);
+ fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris);
}
break;
}
@@ -531,15 +540,5 @@ void GrCCCoverageProcessor::appendVSMesh(GrBuffer* instanceBuffer, int instanceC
}
GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createVSImpl(std::unique_ptr<Shader> shadr) const {
- switch (fRenderPass) {
- case RenderPass::kTriangles:
- return new VSHullAndEdgeImpl(std::move(shadr), 3);
- case RenderPass::kTriangleCorners:
- return new VSCornerImpl(std::move(shadr));
- case RenderPass::kQuadratics:
- case RenderPass::kCubics:
- return new VSHullAndEdgeImpl(std::move(shadr), 4);
- }
- SK_ABORT("Invalid RenderPass");
- return nullptr;
+ return new VSImpl(std::move(shadr));
}
diff --git a/src/gpu/ccpr/GrCCCubicShader.cpp b/src/gpu/ccpr/GrCCCubicShader.cpp
index 76d1646b65..7066fbdaed 100644
--- a/src/gpu/ccpr/GrCCCubicShader.cpp
+++ b/src/gpu/ccpr/GrCCCubicShader.cpp
@@ -12,9 +12,7 @@
using Shader = GrCCCoverageProcessor::Shader;
-void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* /*repetitionID*/, const char* /*wind*/,
- GeometryVars*) const {
+const char* GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts) const {
// Find the cubic's power basis coefficients.
s->codeAppendf("float2x4 C = float4x4(-1, 3, -3, 1, "
" 3, -6, 3, 0, "
@@ -64,24 +62,28 @@ void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
s->codeAppendf("%s *= float3x3(orientation[0] * orientation[1], 0, 0, "
"0, orientation[0], 0, "
"0, 0, orientation[1]);", fKLMMatrix.c_str());
+
+ return nullptr;
}
-void GrCCCubicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
- GrGLSLVarying::Scope scope, SkString* code,
- const char* position, const char* inputCoverage,
- const char* wind) {
+Shader::CoverageHandling GrCCCubicShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
+ GrGLSLVarying::Scope scope, SkString* code,
+ const char* position,
+ const char* coverageTimesWind) {
code->appendf("float3 klm = float3(%s, 1) * %s;", position, fKLMMatrix.c_str());
fKLMW.reset(kFloat4_GrSLType, scope);
varyingHandler->addVarying("klmw", &fKLMW);
code->appendf("%s.xyz = klm;", OutName(fKLMW));
- code->appendf("%s.w = %s * %s;", OutName(fKLMW), inputCoverage, wind);
+ code->appendf("%s.w = %s;", OutName(fKLMW), coverageTimesWind);
fGradMatrix.reset(kFloat2x2_GrSLType, scope);
varyingHandler->addVarying("grad_matrix", &fGradMatrix);
code->appendf("%s[0] = 3 * klm[0] * %s[0].xy;", OutName(fGradMatrix), fKLMMatrix.c_str());
code->appendf("%s[1] = -klm[1] * %s[2].xy - klm[2] * %s[1].xy;",
OutName(fGradMatrix), fKLMMatrix.c_str(), fKLMMatrix.c_str());
+
+ return CoverageHandling::kHandled;
}
void GrCCCubicShader::onEmitFragmentCode(const GrCCCoverageProcessor& proc,
diff --git a/src/gpu/ccpr/GrCCCubicShader.h b/src/gpu/ccpr/GrCCCubicShader.h
index 70d3300461..3ffce65042 100644
--- a/src/gpu/ccpr/GrCCCubicShader.h
+++ b/src/gpu/ccpr/GrCCCubicShader.h
@@ -23,11 +23,10 @@
*/
class GrCCCubicShader : public GrCCCoverageProcessor::Shader {
protected:
- void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID,
- const char* wind, GeometryVars*) const override;
+ const char* emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts) const override;
- void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
- const char* position, const char* inputCoverage, const char* wind) override;
+ CoverageHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
+ const char* position, const char* coverageTimesWind) override;
void onEmitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
const char* outputCoverage) const override;
diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp
index e625c43743..42f1010409 100644
--- a/src/gpu/ccpr/GrCCPathParser.cpp
+++ b/src/gpu/ccpr/GrCCPathParser.cpp
@@ -514,17 +514,12 @@ void GrCCPathParser::drawCoverageCount(GrOpFlushState* flushState, CoverageCount
if (batchTotalCounts.fTriangles) {
this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangles,
WindMethod::kCrossProduct, &PrimitiveTallies::fTriangles, drawBounds);
- this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleCorners,
- WindMethod::kCrossProduct, &PrimitiveTallies::fTriangles, drawBounds);
}
if (batchTotalCounts.fWoundTriangles) {
this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangles,
WindMethod::kInstanceData, &PrimitiveTallies::fWoundTriangles,
drawBounds);
- this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleCorners,
- WindMethod::kInstanceData, &PrimitiveTallies::fWoundTriangles,
- drawBounds);
}
if (batchTotalCounts.fQuadratics) {
@@ -592,9 +587,8 @@ void GrCCPathParser::drawRenderPass(GrOpFlushState* flushState, const GrPipeline
SkASSERT(totalInstanceCount == batch.fTotalPrimitiveCounts.*instanceType);
if (!fMeshesScratchBuffer.empty()) {
- SkASSERT(flushState->rtCommandBuffer());
- flushState->rtCommandBuffer()->draw(pipeline, proc, fMeshesScratchBuffer.begin(),
- fDynamicStatesScratchBuffer.begin(),
- fMeshesScratchBuffer.count(), SkRect::Make(drawBounds));
+ proc.draw(flushState, pipeline, fMeshesScratchBuffer.begin(),
+ fDynamicStatesScratchBuffer.begin(), fMeshesScratchBuffer.count(),
+ SkRect::Make(drawBounds));
}
}
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp
index baa10fd34e..e164cff862 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.cpp
+++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp
@@ -13,9 +13,7 @@
using Shader = GrCCCoverageProcessor::Shader;
-void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* /*repetitionID*/, const char* /*wind*/,
- GeometryVars* vars) const {
+const char* GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts) const {
s->declareGlobal(fCanonicalMatrix);
s->codeAppendf("%s = float3x3(0.0, 0, 1, "
"0.5, 0, 1, "
@@ -38,23 +36,20 @@ void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* p
"%s[0] + tan0 * t, "
"%s[1] + tan1 * t, "
"%s[2]);", pts, pts, pts, pts);
- vars->fHullVars.fAlternatePoints = "quadratic_hull";
+ return "quadratic_hull";
}
-void GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
- GrGLSLVarying::Scope scope, SkString* code,
- const char* position, const char* inputCoverage,
- const char* wind) {
+Shader::CoverageHandling GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
+ GrGLSLVarying::Scope scope,
+ SkString* code, const char* position,
+ const char* coverageTimesWind) {
fCoords.reset(kFloat4_GrSLType, scope);
varyingHandler->addVarying("coords", &fCoords);
code->appendf("%s.xy = (%s * float3(%s, 1)).xy;",
OutName(fCoords), fCanonicalMatrix.c_str(), position);
code->appendf("%s.zw = float2(2 * %s.x, -1) * float2x2(%s);",
OutName(fCoords), OutName(fCoords), fCanonicalMatrix.c_str());
-
- fCoverageTimesWind.reset(kHalf_GrSLType, scope);
- varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
- code->appendf("%s = %s * %s;", OutName(fCoverageTimesWind), inputCoverage, wind);
+ return CoverageHandling::kNotHandled;
}
void GrCCQuadraticShader::onEmitFragmentCode(const GrCCCoverageProcessor& proc,
@@ -67,5 +62,5 @@ void GrCCQuadraticShader::onEmitFragmentCode(const GrCCCoverageProcessor& proc,
f->codeAppendf("d /= %f;", proc.debugBloat());
}
#endif
- f->codeAppendf("%s = clamp(0.5 - d, 0, 1) * %s;", outputCoverage, fCoverageTimesWind.fsIn());
+ f->codeAppendf("%s = clamp(0.5 - d, 0, 1);", outputCoverage);
}
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.h b/src/gpu/ccpr/GrCCQuadraticShader.h
index d91f943471..a2ac5dab9f 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.h
+++ b/src/gpu/ccpr/GrCCQuadraticShader.h
@@ -22,18 +22,16 @@
*/
class GrCCQuadraticShader : public GrCCCoverageProcessor::Shader {
protected:
- void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID,
- const char* wind, GeometryVars*) const override;
+ const char* emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts) const override;
- void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
- const char* position, const char* inputCoverage, const char* wind) override;
+ CoverageHandling onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
+ const char* position, const char* coverageTimesWind) override;
void onEmitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
const char* outputCoverage) const override;
const GrShaderVar fCanonicalMatrix{"canonical_matrix", kFloat3x3_GrSLType};
GrGLSLVarying fCoords;
- GrGLSLVarying fCoverageTimesWind;
};
#endif
diff --git a/src/gpu/ccpr/GrCCTriangleShader.cpp b/src/gpu/ccpr/GrCCTriangleShader.cpp
deleted file mode 100644
index 8135313965..0000000000
--- a/src/gpu/ccpr/GrCCTriangleShader.cpp
+++ /dev/null
@@ -1,151 +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.
- */
-
-#include "GrCCTriangleShader.h"
-
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLVertexGeoBuilder.h"
-
-using Shader = GrCCCoverageProcessor::Shader;
-
-void GrCCTriangleShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
- GrGLSLVarying::Scope scope, SkString* code,
- const char* /*position*/, const char* inputCoverage,
- const char* wind) {
- SkASSERT(inputCoverage);
- fCoverageTimesWind.reset(kHalf_GrSLType, scope);
- varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
- code->appendf("%s = %s * %s;", OutName(fCoverageTimesWind), inputCoverage, wind);
-}
-
-void GrCCTriangleShader::onEmitFragmentCode(const GrCCCoverageProcessor&,
- GrGLSLFPFragmentBuilder* f,
- const char* outputCoverage) const {
- f->codeAppendf("%s = %s;", outputCoverage, fCoverageTimesWind.fsIn());
-}
-
-void GrCCTriangleCornerShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
- const char* repetitionID, const char* wind,
- GeometryVars* vars) const {
- s->codeAppendf("float2 corner = %s[%s];", pts, repetitionID);
- vars->fCornerVars.fPoint = "corner";
-
- s->codeAppendf("float2x2 vectors = float2x2(corner - %s[0 != %s ? %s - 1 : 2], "
- "corner - %s[2 != %s ? %s + 1 : 0]);",
- pts, repetitionID, repetitionID, pts, repetitionID,
- repetitionID);
-
- // Make sure neither vector is 0 to avoid a divide-by-zero. Wind will be zero anyway if this
- // is the case, so whatever we output won't have any effect as long it isn't NaN or Inf.
- s->codeAppend ("for (int i = 0; i < 2; ++i) {");
- s->codeAppend ( "vectors[i] = (vectors[i] != float2(0)) ? vectors[i] : float2(1);");
- s->codeAppend ("}");
-
- // Find the vector that bisects the region outside the incoming edges. Each edge is
- // responsible to subtract the outside region on its own the side of the bisector.
- s->codeAppendf("float2 leftdir = normalize(vectors[%s > 0 ? 0 : 1]);", wind);
- s->codeAppendf("float2 rightdir = normalize(vectors[%s > 0 ? 1 : 0]);", wind);
- s->codeAppend ("float2 bisect = dot(leftdir, rightdir) >= 0 ? "
- "leftdir + rightdir : "
- "float2(leftdir.y - rightdir.y, rightdir.x - leftdir.x);");
-
- // In ccpr we don't calculate exact geometric pixel coverage. What the distance-to-edge
- // method actually finds is coverage inside a logical "AA box", one that is rotated inline
- // with the edge, and in our case, up-scaled to circumscribe the actual pixel. Below we set
- // up transformations into normalized logical AA box space for both incoming edges. These
- // will tell the fragment shader where the corner is located within each edge's AA box.
- s->declareGlobal(fAABoxMatrices);
- s->declareGlobal(fAABoxTranslates);
- s->declareGlobal(fGeoShaderBisects);
- s->codeAppendf("for (int i = 0; i < 2; ++i) {");
- // The X component runs parallel to the edge (i.e. distance to the corner).
- s->codeAppendf( "float2 n = -vectors[%s > 0 ? i : 1 - i];", wind);
- s->codeAppend ( "float nwidth = (abs(n.x) + abs(n.y)) * (bloat * 2);");
- s->codeAppend ( "n /= nwidth;"); // nwidth != 0 because both vectors != 0.
- s->codeAppendf( "%s[i][0] = n;", fAABoxMatrices.c_str());
- s->codeAppendf( "%s[i][0] = -dot(n, corner) + .5;", fAABoxTranslates.c_str());
-
- // The Y component runs perpendicular to the edge (i.e. distance-to-edge).
- s->codeAppend ( "n = (i == 0) ? float2(-n.y, n.x) : float2(n.y, -n.x);");
- s->codeAppendf( "%s[i][1] = n;", fAABoxMatrices.c_str());
- s->codeAppendf( "%s[i][1] = -dot(n, corner) + .5;", fAABoxTranslates.c_str());
-
- // Translate the bisector into logical AA box space.
- // NOTE: Since the region outside two edges of a convex shape is in [180 deg, 360 deg], the
- // bisector will therefore be in [90 deg, 180 deg]. Or, x >= 0 and y <= 0 in AA box space.
- s->codeAppendf( "%s[i] = -bisect * %s[i];",
- fGeoShaderBisects.c_str(), fAABoxMatrices.c_str());
- s->codeAppend ("}");
-}
-
-void GrCCTriangleCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
- GrGLSLVarying::Scope scope, SkString* code,
- const char* position, const char* inputCoverage,
- const char* wind) {
- using Interpolation = GrGLSLVaryingHandler::Interpolation;
- SkASSERT(!inputCoverage);
-
- fCornerLocationInAABoxes.reset(kFloat2x2_GrSLType, scope);
- varyingHandler->addVarying("corner_location_in_aa_boxes", &fCornerLocationInAABoxes);
-
- fBisectInAABoxes.reset(kFloat2x2_GrSLType, scope);
- varyingHandler->addVarying("bisect_in_aa_boxes", &fBisectInAABoxes, Interpolation::kCanBeFlat);
-
- code->appendf("for (int i = 0; i < 2; ++i) {");
- code->appendf( "%s[i] = %s * %s[i] + %s[i];",
- OutName(fCornerLocationInAABoxes), position, fAABoxMatrices.c_str(),
- fAABoxTranslates.c_str());
- code->appendf( "%s[i] = %s[i];", OutName(fBisectInAABoxes), fGeoShaderBisects.c_str());
- code->appendf("}");
-
- fWindTimesHalf.reset(kHalf_GrSLType, scope);
- varyingHandler->addVarying("wind_times_half", &fWindTimesHalf, Interpolation::kCanBeFlat);
- code->appendf("%s = %s * .5;", OutName(fWindTimesHalf), wind);
-}
-
-void GrCCTriangleCornerShader::onEmitFragmentCode(const GrCCCoverageProcessor&,
- GrGLSLFPFragmentBuilder* f,
- const char* outputCoverage) const {
- // By the time we reach this shader, the pixel is in the following state:
- //
- // 1. The hull shader has emitted a coverage of 1.
- // 2. Both edges have subtracted the area on their outside.
- //
- // This generally works, but it is a problem for corner pixels. There is a region within
- // corner pixels that is outside both edges at the same time. This means the region has been
- // double subtracted (once by each edge). The purpose of this shader is to fix these corner
- // pixels.
- //
- // More specifically, each edge redoes its coverage analysis so that it only subtracts the
- // outside area that falls on its own side of the bisector line.
- //
- // NOTE: unless the edges fall on multiples of 90 deg from one another, they will have
- // different AA boxes. (For an explanation of AA boxes, see comments in
- // onEmitGeometryShader.) This means the coverage analysis will only be approximate. It
- // seems acceptable, but if we want exact coverage we will need to switch to a more
- // expensive model.
- f->codeAppendf("for (int i = 0; i < 2; ++i) {"); // Loop through both edges.
- f->codeAppendf( "half2 corner = %s[i];", fCornerLocationInAABoxes.fsIn());
- f->codeAppendf( "half2 bisect = %s[i];", fBisectInAABoxes.fsIn());
-
- // Find the point at which the bisector exits the logical AA box.
- // (The inequality works because bisect.x is known >= 0 and bisect.y is known <= 0.)
- f->codeAppendf( "half2 d = half2(1 - corner.x, -corner.y);");
- f->codeAppendf( "half T = d.y * bisect.x >= d.x * bisect.y ? d.y / bisect.y "
- ": d.x / bisect.x;");
- f->codeAppendf( "half2 exit = corner + bisect * T;");
-
- // These lines combined (and the final multiply by .5) accomplish the following:
- // 1. Add back the area beyond the corner that was subtracted out previously.
- // 2. Subtract out the area beyond the corner, but under the bisector.
- // The other edge will take care of the area on its own side of the bisector.
- f->codeAppendf( "%s += (2 - corner.x - exit.x) * corner.y;", outputCoverage);
- f->codeAppendf( "%s += (corner.x - 1) * exit.y;", outputCoverage);
- f->codeAppendf("}");
-
- f->codeAppendf("%s *= %s;", outputCoverage, fWindTimesHalf.fsIn());
-}
diff --git a/src/gpu/ccpr/GrCCTriangleShader.h b/src/gpu/ccpr/GrCCTriangleShader.h
deleted file mode 100644
index 6dae8df497..0000000000
--- a/src/gpu/ccpr/GrCCTriangleShader.h
+++ /dev/null
@@ -1,49 +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"
-
-/**
- * Steps 1 & 2: Draw the triangle's conservative raster hull with a coverage of +1, then smooth the
- * edges by drawing the conservative rasters of all 3 edges and interpolating from
- * coverage=-1 on the outside to coverage=0 on the inside. The Impl may choose to
- * implement these steps in either one or two actual render passes.
- */
-class GrCCTriangleShader : public GrCCCoverageProcessor::Shader {
- void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
- const char* position, const char* inputCoverage, const char* wind) override;
- void onEmitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
- const char* outputCoverage) const override;
-
- GrGLSLVarying fCoverageTimesWind;
-};
-
-/**
- * Step 3: Touch up the corner pixels. Here we fix the simple distance-to-edge coverage analysis
- * done previously so that it takes into account the region that is outside both edges at
- * the same time.
- */
-class GrCCTriangleCornerShader : public GrCCCoverageProcessor::Shader {
- void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* repetitionID,
- const char* wind, GeometryVars*) const override;
- void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
- const char* position, const char* inputCoverage, const char* wind) override;
- void onEmitFragmentCode(const GrCCCoverageProcessor&, GrGLSLFPFragmentBuilder*,
- const char* outputCoverage) const override;
-
- GrShaderVar fAABoxMatrices{"aa_box_matrices", kFloat2x2_GrSLType, 2};
- GrShaderVar fAABoxTranslates{"aa_box_translates", kFloat2_GrSLType, 2};
- GrShaderVar fGeoShaderBisects{"bisects", kFloat2_GrSLType, 2};
- GrGLSLVarying fCornerLocationInAABoxes;
- GrGLSLVarying fBisectInAABoxes;
- GrGLSLVarying fWindTimesHalf;
-};
-
-#endif