aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/gpu.gni1
-rw-r--r--samplecode/SampleCCPRGeometry.cpp51
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.cpp25
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor.h46
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp68
-rw-r--r--src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp214
-rw-r--r--src/gpu/ccpr/GrCCPathParser.cpp9
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.cpp149
-rw-r--r--src/gpu/ccpr/GrCCTriangleShader.h43
9 files changed, 311 insertions, 295 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 457b4057cc..ac52fe2bc1 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -318,7 +318,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 a90ece09a1..4b521dea48 100644
--- a/samplecode/SampleCCPRGeometry.cpp
+++ b/samplecode/SampleCCPRGeometry.cpp
@@ -32,10 +32,6 @@ using RenderPass = GrCCCoverageProcessor::RenderPass;
static constexpr float kDebugBloat = 40;
-static int is_quadratic(RenderPass pass) {
- return pass == RenderPass::kQuadratics || pass == RenderPass::kQuadraticCorners;
-}
-
/**
* This sample visualizes the AA bloat geometry generated by the ccpr geometry shaders. It
* increases the AA bloat by 50x and outputs color instead of coverage (coverage=+1 -> green,
@@ -91,6 +87,7 @@ private:
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState*) override;
+ void drawRenderPass(GrOpFlushState*, RenderPass);
CCPRGeometryView* fView;
@@ -119,14 +116,13 @@ static void draw_klm_line(int w, int h, SkCanvas* canvas, const SkScalar line[3]
}
void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
- SkAutoCanvasRestore acr(canvas, true);
- canvas->setMatrix(SkMatrix::I());
+ canvas->clear(SK_ColorBLACK);
SkPath outline;
outline.moveTo(fPoints[0]);
- if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
+ if (RenderPass::kCubics == fRenderPass) {
outline.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
- } else if (is_quadratic(fRenderPass)) {
+ } else if (RenderPass::kQuadratics == fRenderPass) {
outline.quadTo(fPoints[1], fPoints[3]);
} else {
outline.lineTo(fPoints[1]);
@@ -135,7 +131,7 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
}
SkPaint outlinePaint;
- outlinePaint.setColor(0x30000000);
+ outlinePaint.setColor(0x80ffffff);
outlinePaint.setStyle(SkPaint::kStroke_Style);
outlinePaint.setStrokeWidth(0);
outlinePaint.setAntiAlias(true);
@@ -159,7 +155,7 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
if (GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext()) {
rtc->priv().testingOnly_addDrawOp(skstd::make_unique<Op>(this));
caption.appendf("RenderPass_%s", GrCCCoverageProcessor::RenderPassName(fRenderPass));
- if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
+ if (RenderPass::kCubics == fRenderPass) {
caption.appendf(" (%s)", SkCubicTypeName(fCubicType));
}
} else {
@@ -171,7 +167,7 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
pointsPaint.setStrokeWidth(8);
pointsPaint.setAntiAlias(true);
- if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
+ if (RenderPass::kCubics == fRenderPass) {
int w = this->width(), h = this->height();
canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint);
draw_klm_line(w, h, canvas, &fCubicKLM[0], SK_ColorYELLOW);
@@ -184,7 +180,7 @@ void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
SkPaint captionPaint;
captionPaint.setTextSize(20);
- captionPaint.setColor(SK_ColorBLACK);
+ captionPaint.setColor(SK_ColorWHITE);
captionPaint.setAntiAlias(true);
canvas->drawText(caption.c_str(), caption.size(), 10, 30, captionPaint);
}
@@ -193,7 +189,7 @@ void CCPRGeometryView::updateGpuData() {
fTriPointInstances.reset();
fQuadPointInstances.reset();
- if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
+ if (RenderPass::kCubics == fRenderPass) {
double t[2], s[2];
fCubicType = GrPathUtils::getCubicKLM(fPoints, &fCubicKLM, t, s);
GrCCGeometry geometry;
@@ -217,7 +213,7 @@ void CCPRGeometryView::updateGpuData() {
continue;
}
}
- } else if (is_quadratic(fRenderPass)) {
+ } else if (RenderPass::kQuadratics == fRenderPass) {
GrCCGeometry geometry;
geometry.beginContour(fPoints[0]);
geometry.quadraticTo(fPoints[1], fPoints[3]);
@@ -243,18 +239,26 @@ void CCPRGeometryView::updateGpuData() {
}
void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) {
+ this->drawRenderPass(state, fView->fRenderPass);
+
+ RenderPass cornerPass = RenderPass((int)fView->fRenderPass + 1);
+ if (GrCCCoverageProcessor::DoesRenderPass(cornerPass, state->caps())) {
+ this->drawRenderPass(state, cornerPass);
+ }
+}
+
+void CCPRGeometryView::Op::drawRenderPass(GrOpFlushState* state, RenderPass renderPass) {
GrResourceProvider* rp = state->resourceProvider();
GrContext* context = state->gpu()->getContext();
GrGLGpu* glGpu = kOpenGL_GrBackend == context->contextPriv().getBackend()
? static_cast<GrGLGpu*>(state->gpu())
: nullptr;
- GrCCCoverageProcessor proc(rp, fView->fRenderPass,
- GrCCCoverageProcessor::WindMethod::kCrossProduct);
+ GrCCCoverageProcessor proc(rp, renderPass, GrCCCoverageProcessor::WindMethod::kCrossProduct);
SkDEBUGCODE(proc.enableDebugVisualizations(kDebugBloat));
SkSTArray<1, GrMesh> mesh;
- if (GrCCCoverageProcessor::RenderPassIsCubic(fView->fRenderPass)) {
+ if (RenderPass::kCubics == renderPass) {
sk_sp<GrBuffer> instBuff(rp->createBuffer(
fView->fQuadPointInstances.count() * sizeof(QuadPointInstance),
kVertex_GrBufferType, kDynamic_GrAccessPattern,
@@ -275,17 +279,18 @@ void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) {
}
GrPipeline pipeline(state->drawOpArgs().fProxy, GrPipeline::ScissorState::kDisabled,
- SkBlendMode::kSrcOver);
+ SkBlendMode::kPlus);
if (glGpu) {
glGpu->handleDirtyContext();
- GR_GL_CALL(glGpu->glInterface(), PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_LINE));
+ // GR_GL_CALL(glGpu->glInterface(), PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_LINE));
GR_GL_CALL(glGpu->glInterface(), Enable(GR_GL_LINE_SMOOTH));
}
if (!mesh.empty()) {
SkASSERT(1 == mesh.count());
- state->rtCommandBuffer()->draw(pipeline, proc, mesh.begin(), nullptr, 1, this->bounds());
+ GrGpuRTCommandBuffer* cmdBuff = state->rtCommandBuffer();
+ cmdBuff->draw(pipeline, proc, mesh.begin(), nullptr, 1, this->bounds());
}
if (glGpu) {
@@ -318,7 +323,7 @@ private:
SkView::Click* CCPRGeometryView::onFindClickHandler(SkScalar x, SkScalar y, unsigned) {
for (int i = 0; i < 4; ++i) {
- if (!GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass) && 2 == i) {
+ if (RenderPass::kCubics != fRenderPass && 2 == i) {
continue;
}
if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
@@ -342,8 +347,8 @@ bool CCPRGeometryView::onQuery(SkEvent* evt) {
}
SkUnichar unichar;
if (SampleCode::CharQ(*evt, &unichar)) {
- if (unichar >= '1' && unichar <= '6') {
- fRenderPass = RenderPass(unichar - '1');
+ if (unichar >= '1' && unichar <= '3') {
+ fRenderPass = RenderPass((unichar - '1') * 2);
this->updateAndInval();
return true;
}
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index 686ab5514d..efe003dd60 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -25,8 +25,8 @@ void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor
f->codeAppendf("%s = half4(1);", skOutputCoverage);
#ifdef SK_DEBUG
if (proc.debugVisualizationsEnabled()) {
- f->codeAppendf("%s = half4(-%s.a, %s.a, 0, 1);",
- skOutputColor, skOutputColor, skOutputColor);
+ f->codeAppendf("%s = half4(-%s.a, %s.a, 0, abs(%s.a));",
+ skOutputColor, skOutputColor, skOutputColor, skOutputColor);
}
#endif
}
@@ -79,6 +79,23 @@ void GrCCCoverageProcessor::Shader::CalcEdgeCoverageAtBloatVertex(GrGLSLVertexGe
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("}");
+}
+
int GrCCCoverageProcessor::Shader::DefineSoftSampleLocations(GrGLSLFPFragmentBuilder* f,
const char* samplesName) {
// Standard DX11 sample locations.
@@ -120,10 +137,8 @@ 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<GrCCTriangleShader>();
break;
case RenderPass::kQuadratics:
shader = skstd::make_unique<GrCCQuadraticHullShader>();
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index c1f85993a1..5c10630f49 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -54,10 +54,11 @@ public:
void set(const SkPoint&, const SkPoint&, const SkPoint&, const Sk2f& trans, float w);
};
- // All primitive shapes (triangles and closed, convex bezier curves) require two
- // render passes: One to draw a rough outline of the shape, and a second pass to touch up the
- // corners. Here we enumerate every render pass needed in order to produce a complete
- // coverage count mask. This is an exhaustive list of all ccpr coverage shaders.
+ // All primitive shapes (triangles and closed, convex bezier curves) may require two render
+ // passes: One to draw a rough outline of the shape, and a second pass to touch up the corners.
+ // Check DoesRenderPass() before attempting to draw a given RenderPass. Here we enumerate every
+ // possible render pass needed in order to produce a complete coverage count mask. This is an
+ // exhaustive list of all ccpr coverage shaders.
enum class RenderPass {
kTriangles,
kTriangleCorners,
@@ -69,6 +70,11 @@ public:
static bool RenderPassIsCubic(RenderPass);
static const char* RenderPassName(RenderPass);
+ constexpr static bool DoesRenderPass(RenderPass renderPass, const GrCaps& caps) {
+ return RenderPass::kTriangleCorners != renderPass ||
+ caps.shaderCaps()->geometryShaderSupport();
+ }
+
enum class WindMethod : bool {
kCrossProduct, // Calculate wind = +/-1 by sign of the cross product.
kInstanceData // Instance data provides custom, signed wind values of any magnitude.
@@ -81,6 +87,7 @@ public:
, fWindMethod(windMethod)
, fImpl(rp->caps()->shaderCaps()->geometryShaderSupport() ? Impl::kGeometryShader
: Impl::kVertexShader) {
+ SkASSERT(DoesRenderPass(pass, *rp->caps()));
if (Impl::kGeometryShader == fImpl) {
this->initGS();
} else {
@@ -88,18 +95,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 {
@@ -116,6 +111,18 @@ public:
float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }
#endif
+ // 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);
+ }
+ }
+
// The Shader provides code to calculate each pixel's coverage in a RenderPass. It also
// provides details about shape-specific geometry.
class Shader {
@@ -169,6 +176,13 @@ 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:
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
index d9febc0e66..b210aa1615 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
@@ -76,7 +76,8 @@ protected:
SkSTArray<2, GrShaderVar> emitArgs;
const char* position = emitArgs.emplace_back("position", kFloat2_GrSLType).c_str();
const char* coverage = nullptr;
- if (RenderPass::kTriangles == proc.fRenderPass) {
+ if (RenderPass::kTriangles == proc.fRenderPass ||
+ RenderPass::kTriangleCorners == proc.fRenderPass) {
coverage = emitArgs.emplace_back("coverage", kHalf_GrSLType).c_str();
}
g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() {
@@ -116,7 +117,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 +125,10 @@ public:
void onEmitGeometryShader(GrGLSLGeometryBuilder* g, const GrShaderVar& wind,
const char* emitVertexFn) const override {
+ Shader::GeometryVars vars;
+ fShader->emitSetupCode(g, "pts", nullptr, wind.c_str(), &vars);
+ SkASSERT(!vars.fHullVars.fAlternatePoints);
+
// 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,6 +217,61 @@ 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 {
+ Shader::GeometryVars vars;
+ fShader->emitSetupCode(g, "pts", nullptr, wind.c_str(), &vars);
+ SkASSERT(!vars.fHullVars.fAlternatePoints);
+
+ 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 around a convex quadrilateral that encloses a cubic or quadratic.
*/
class GSHull4Impl : public GrCCCoverageProcessor::GSImpl {
@@ -317,12 +377,10 @@ void GrCCCoverageProcessor::initGS() {
this->addVertexAttrib("x_or_y_values", kFloat4_GrVertexAttribType);
SkASSERT(sizeof(QuadPointInstance) == this->getVertexStride() * 2);
SkASSERT(offsetof(QuadPointInstance, fY) == this->getVertexStride());
- GR_STATIC_ASSERT(0 == offsetof(QuadPointInstance, fX));
} else {
this->addVertexAttrib("x_or_y_values", kFloat3_GrVertexAttribType);
SkASSERT(sizeof(TriPointInstance) == this->getVertexStride() * 2);
SkASSERT(offsetof(TriPointInstance, fY) == this->getVertexStride());
- GR_STATIC_ASSERT(0 == offsetof(TriPointInstance, fX));
}
this->setWillUseGeoShader();
}
@@ -344,7 +402,7 @@ GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGSImpl(std::unique_ptr<Sh
case RenderPass::kTriangles:
return new GSTriangleImpl(std::move(shadr));
case RenderPass::kTriangleCorners:
- return new GSCornerImpl(std::move(shadr), 3);
+ return new GSTriangleCornerImpl(std::move(shadr));
case RenderPass::kQuadratics:
case RenderPass::kCubics:
return new GSHull4Impl(std::move(shadr));
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
index 144a4a5d58..28ed6fc319 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
@@ -89,10 +89,11 @@ protected:
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_InvertCoverageBit = 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;
@@ -120,10 +121,15 @@ static constexpr int32_t edge_vertex_data(int32_t edgeID, int32_t endptIdx, int3
0 == endptIdx ? (edgeID + 1) % n : edgeID,
bloatIdx, 0 == endptIdx ? edgeID : (edgeID + 1) % n,
kVertexData_IsEdgeBit |
- (!endptIdx ? kVertexData_InvertCoverageBit : 0));
+ (!endptIdx ? kVertexData_InvertNegativeCoverageBit : 0));
}
-static constexpr int32_t kHull3AndEdgeVertices[] = {
+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 kTriangleVertices[] = {
hull_vertex_data(0, 0, 3),
hull_vertex_data(0, 1, 3),
hull_vertex_data(0, 2, 3),
@@ -154,21 +160,39 @@ static constexpr int32_t kHull3AndEdgeVertices[] = {
edge_vertex_data(2, 1, 0, 3),
edge_vertex_data(2, 1, 1, 3),
edge_vertex_data(2, 1, 2, 3),
+
+ 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,
@@ -197,9 +221,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 kHull4Vertices[] = {
hull_vertex_data(0, 0, 4),
@@ -243,19 +279,21 @@ static constexpr uint16_t kHull4IndicesAsTris[] = {
GR_DECLARE_STATIC_UNIQUE_KEY(gHull4IndexBufferKey);
+
/**
- * Generates a conservative raster hull around a convex polygon. For triangles we generate
- * additional conservative rasters around the edges and calculate coverage ramps.
- *
- * Triangle rough outlines are drawn in two steps: (1) draw a conservative raster of the entire
- * triangle, with a coverage of +1, and (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.
+ * Generates a conservative raster hull around a triangle or curve. For triangles we generate
+ * additional conservative rasters with coverage ramps around the edges and corners.
*
- * Curve rough outlines are just the conservative raster of a convex quadrilateral that encloses the
- * curve. The Shader takes care of everything else for now.
+ * 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.
*
- * The final corners get touched up in a later step by VSCornerImpl.
+ * Curves are drawn in two separate passes. Here we just draw a conservative raster around the input
+ * points. The Shader takes care of everything else for now. The final curve corners get touched up
+ * in a later step by VSCornerImpl.
*/
class VSHullAndEdgeImpl : public GrCCCoverageProcessor::VSImpl {
public:
@@ -284,10 +322,9 @@ public:
// 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. For more details on conservative raster, see:
+ // to offset each vertex. Triangle edges and corners are also handled here using the same
+ // concept. For more details on conservative raster, see:
// https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html
- //
- // Triangle edges are also handled here using the same concept (see kHull3AndEdgeVertices).
v->codeAppendf("float2 corner = %s[clockwise_indices & 3];", hullPts);
v->codeAppendf("float2 left = %s[clockwise_indices >> %i];",
hullPts, kVertexData_LeftNeighborIdShift);
@@ -304,48 +341,97 @@ public:
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;");
+
+ if (3 == fNumSides) { // 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 ("}");
+ }
+
+ // 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 this corner's first raster vertex (leftbloat), then
+ // continue rotating 90 degrees clockwise until we reach the desired raster vertex for this
+ // invocation. Corners with less than 3 corresponding raster 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 (3 == fNumSides) { // 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);");
+ 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);");
+ 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");
+
// For triangles, we also emit coverage in order to handle edges and corners.
const char* coverage = nullptr;
if (3 == fNumSides) {
- v->codeAppend ("half coverage;");
- Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "coverage");
- v->codeAppendf("if (0 != (%s & %i)) {", // Are we the opposite endpoint of an edge?
+ // The hull has a coverage of +1 all around.
+ v->codeAppend ("half coverage = +1;");
+
+ v->codeAppendf("if (0 != (%s & %i)) {", // Are we an edge OR corner?
proc.getAttrib(kAttribIdx_VertexData).fName,
- kVertexData_InvertCoverageBit);
- v->codeAppend ( "coverage = -1 - coverage;");
+ kVertexData_IsEdgeBit | kVertexData_IsCornerBit);
+ Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "coverage");
v->codeAppend ("}");
- v->codeAppendf("if (0 != (%s & %i)) {", // Are we a hull vertex?
- proc.getAttrib(kAttribIdx_VertexData).fName, kVertexData_IsHullBit);
- v->codeAppend ( "coverage = +1;"); // Hull coverage is +1 all around.
+ 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 ("}");
+
+ v->codeAppendf("if (0 != (%s & %i)) {", // Invert coverage?
+ proc.getAttrib(kAttribIdx_VertexData).fName,
+ kVertexData_InvertNegativeCoverageBit);
+ v->codeAppend ( "coverage = -1 - coverage;");
v->codeAppend ("}");
coverage = "coverage";
}
- v->codeAppend ("float2 vertex = corner + bloatdir * bloat;");
- gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
-
return coverage;
}
@@ -355,8 +441,7 @@ private:
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.
+ 4, 5, 6, 7 // Second corner.
};
static constexpr uint16_t kCornerIndicesAsTris[] = {
@@ -367,10 +452,6 @@ static constexpr uint16_t kCornerIndicesAsTris[] = {
// Second corner.
4, 5, 6,
5, 7, 6,
-
- // Third corner.
- 8, 9, 10,
- 9, 11, 10,
};
GR_DECLARE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey);
@@ -403,28 +484,31 @@ 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);
+ sizeof(kTriangleVertices),
+ kTriangleVertices,
+ gTriangleVertexBufferKey);
+ GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
if (caps.usePrimitiveRestart()) {
fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType,
- sizeof(kHull3AndEdgeIndicesAsStrips),
- kHull3AndEdgeIndicesAsStrips,
- gHull3AndEdgeIndexBufferKey);
- fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull3AndEdgeIndicesAsStrips);
+ sizeof(kTriangleIndicesAsStrips),
+ kTriangleIndicesAsStrips,
+ gTriangleIndexBufferKey);
+ fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips);
} else {
fIndexBuffer = rp->findOrMakeStaticBuffer(kIndex_GrBufferType,
- sizeof(kHull3AndEdgeIndicesAsTris),
- kHull3AndEdgeIndicesAsTris,
- gHull3AndEdgeIndexBufferKey);
- fNumIndicesPerInstance = SK_ARRAY_COUNT(kHull3AndEdgeIndicesAsTris);
+ sizeof(kTriangleIndicesAsTris),
+ kTriangleIndicesAsTris,
+ gTriangleIndexBufferKey);
+ fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris);
}
break;
}
+ case RenderPass::kTriangleCorners:
+ SK_ABORT("RenderPass::kTriangleCorners is unused by VSImpl.");
+
case RenderPass::kQuadratics:
case RenderPass::kCubics: {
GR_DEFINE_STATIC_UNIQUE_KEY(gHull4VertexBufferKey);
@@ -447,7 +531,6 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) {
break;
}
- case RenderPass::kTriangleCorners:
case RenderPass::kQuadraticCorners:
case RenderPass::kCubicCorners: {
GR_DEFINE_STATIC_UNIQUE_KEY(gCornerIndexBufferKey);
@@ -463,12 +546,9 @@ void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) {
kCornerIndicesAsTris,
gCornerIndexBufferKey);
fNumIndicesPerInstance = SK_ARRAY_COUNT(kCornerIndicesAsTris);
- }
- if (RenderPass::kTriangleCorners != fRenderPass) {
- fNumIndicesPerInstance = fNumIndicesPerInstance * 2/3;
- }
- break;
- }
+ }
+ break;
+ }
}
if (RenderPassIsCubic(fRenderPass) || WindMethod::kInstanceData == fWindMethod) {
diff --git a/src/gpu/ccpr/GrCCPathParser.cpp b/src/gpu/ccpr/GrCCPathParser.cpp
index cb5311f3a1..1114367ac7 100644
--- a/src/gpu/ccpr/GrCCPathParser.cpp
+++ b/src/gpu/ccpr/GrCCPathParser.cpp
@@ -514,7 +514,8 @@ void GrCCPathParser::drawCoverageCount(GrOpFlushState* flushState, CoverageCount
this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangles,
WindMethod::kCrossProduct, &PrimitiveTallies::fTriangles, drawBounds);
this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleCorners,
- WindMethod::kCrossProduct, &PrimitiveTallies::fTriangles, drawBounds);
+ WindMethod::kCrossProduct, &PrimitiveTallies::fTriangles,
+ drawBounds); // Might get skipped.
}
if (batchTotalCounts.fWoundTriangles) {
@@ -523,7 +524,7 @@ void GrCCPathParser::drawCoverageCount(GrOpFlushState* flushState, CoverageCount
drawBounds);
this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleCorners,
WindMethod::kInstanceData, &PrimitiveTallies::fWoundTriangles,
- drawBounds);
+ drawBounds); // Might get skipped.
}
if (batchTotalCounts.fQuadratics) {
@@ -549,6 +550,10 @@ void GrCCPathParser::drawRenderPass(GrOpFlushState* flushState, const GrPipeline
const SkIRect& drawBounds) const {
SkASSERT(pipeline.getScissorState().enabled());
+ if (!GrCCCoverageProcessor::DoesRenderPass(renderPass, flushState->caps())) {
+ return;
+ }
+
// Don't call reset(), as that also resets the reserve count.
fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count());
fDynamicStatesScratchBuffer.pop_back_n(fDynamicStatesScratchBuffer.count());
diff --git a/src/gpu/ccpr/GrCCTriangleShader.cpp b/src/gpu/ccpr/GrCCTriangleShader.cpp
deleted file mode 100644
index e086201b42..0000000000
--- a/src/gpu/ccpr/GrCCTriangleShader.cpp
+++ /dev/null
@@ -1,149 +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(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(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
index 5f33b077cd..c7fbefd3b4 100644
--- a/src/gpu/ccpr/GrCCTriangleShader.h
+++ b/src/gpu/ccpr/GrCCTriangleShader.h
@@ -9,39 +9,28 @@
#define GrCCTriangleShader_DEFINED
#include "ccpr/GrCCCoverageProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.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.
+ * 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*, GrGLSLVarying::Scope, SkString* code,
- const char* position, const char* inputCoverage, const char* wind) override;
- void onEmitFragmentCode(GrGLSLFPFragmentBuilder*, const char* outputCoverage) const override;
+ void onEmitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
+ SkString* code, const char* /*position*/, const char* inputCoverage,
+ const char* wind) override {
+ SkASSERT(inputCoverage);
+ fCoverageTimesWind.reset(kHalf_GrSLType, scope);
+ varyingHandler->addVarying("coverage_times_wind", &fCoverageTimesWind);
+ code->appendf("%s = %s * %s;", OutName(fCoverageTimesWind), inputCoverage, wind);
+ }
- 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(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const override;
+ void onEmitFragmentCode(GrGLSLFPFragmentBuilder* f, const char* outputCoverage) const override {
+ f->codeAppendf("%s = %s;", outputCoverage, fCoverageTimesWind.fsIn());
+ }
- 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;
+ GrGLSLVarying fCoverageTimesWind;
};
#endif