Rewrite the path tessellation sample
Use the GrPathTessellators directly instead of going through
GrPathStencilFillOp. Add keyboard shortcuts to toggle between the
different path tessellators.
Bug: skia:10419
Change-Id: I5d80731d26c9a77fb0eca07a7023c50848e29f7c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/409556
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Tyler Denniston <tdenniston@google.com>
diff --git a/gn/samples.gni b/gn/samples.gni
index a248613..2e7362f 100644
--- a/gn/samples.gni
+++ b/gn/samples.gni
@@ -54,6 +54,7 @@
"$_samplecode/SamplePathClip.cpp",
"$_samplecode/SamplePathEffects.cpp",
"$_samplecode/SamplePathOverstroke.cpp",
+ "$_samplecode/SamplePathTessellators.cpp",
"$_samplecode/SamplePathText.cpp",
"$_samplecode/SamplePolyToPoly.cpp",
"$_samplecode/SampleQuadStroker.cpp",
@@ -71,7 +72,6 @@
"$_samplecode/SampleStrokePath.cpp",
"$_samplecode/SampleStrokeRect.cpp",
"$_samplecode/SampleStrokeVerb.cpp",
- "$_samplecode/SampleTessellatedWedge.cpp",
"$_samplecode/SampleTextBox.cpp",
"$_samplecode/SampleTextEffects.cpp",
"$_samplecode/SampleTextureUpload.cpp",
diff --git a/samplecode/SamplePathTessellators.cpp b/samplecode/SamplePathTessellators.cpp
new file mode 100644
index 0000000..8a499a4
--- /dev/null
+++ b/samplecode/SamplePathTessellators.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkCanvas.h"
+#include "samplecode/Sample.h"
+#include "src/core/SkPathPriv.h"
+
+#if SK_SUPPORT_GPU
+
+#include "src/core/SkCanvasPriv.h"
+#include "src/gpu/GrRecordingContextPriv.h"
+#include "src/gpu/GrSurfaceDrawContext.h"
+#include "src/gpu/tessellate/GrPathTessellator.h"
+#include "src/gpu/tessellate/GrStencilPathShader.h"
+
+namespace {
+
+enum class Mode {
+ kCurveMiddleOut,
+ kWedgeTessellate,
+ kCurveTessellate
+};
+
+static const char* ModeName(Mode mode) {
+ switch (mode) {
+ case Mode::kCurveMiddleOut:
+ return "GrCurveMiddleOutShader";
+ case Mode::kWedgeTessellate:
+ return "GrWedgeTessellateShader";
+ case Mode::kCurveTessellate:
+ return "GrCurveTessellateShader";
+ }
+ SkUNREACHABLE;
+}
+
+// Draws a path directly to the screen using a specific tessellator.
+class SamplePathTessellatorOp : public GrDrawOp {
+private:
+ DEFINE_OP_CLASS_ID
+
+ SamplePathTessellatorOp(const SkRect& drawBounds, const SkPath& path, const SkMatrix& m,
+ GrPipeline::InputFlags pipelineFlags, Mode mode)
+ : GrDrawOp(ClassID())
+ , fPath(path)
+ , fMatrix(m)
+ , fPipelineFlags(pipelineFlags)
+ , fMode(mode) {
+ this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
+ }
+ const char* name() const override { return "SamplePathTessellatorOp"; }
+ void visitProxies(const VisitProxyFunc& fn) const override {}
+ FixedFunctionFlags fixedFunctionFlags() const override {
+ return FixedFunctionFlags::kUsesHWAA;
+ }
+ GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
+ GrClampType clampType) override {
+ SkPMColor4f color;
+ return fProcessors.finalize(SK_PMColor4fWHITE, GrProcessorAnalysisCoverage::kNone, clip,
+ nullptr, caps, clampType, &color);
+ }
+ void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
+ const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
+ GrLoadOp colorLoadOp) override {}
+ void onPrepare(GrOpFlushState* flushState) override {
+ auto alloc = flushState->allocator();
+ GrPathShader* shader;
+ switch (fMode) {
+ case Mode::kCurveMiddleOut:
+ fTessellator = alloc->make<GrPathIndirectTessellator>(
+ fMatrix, fPath, GrPathIndirectTessellator::DrawInnerFan::kYes);
+ shader = alloc->make<GrCurveMiddleOutShader>(fMatrix);
+ break;
+ case Mode::kWedgeTessellate:
+ fTessellator = alloc->make<GrPathWedgeTessellator>();
+ shader = alloc->make<GrWedgeTessellateShader>(fMatrix);
+ break;
+ case Mode::kCurveTessellate:
+ fTessellator = alloc->make<GrPathOuterCurveTessellator>();
+ shader = alloc->make<GrCurveTessellateShader>(fMatrix);
+ break;
+ }
+ fTessellator->prepare(flushState, fMatrix, fPath);
+ auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
+ fPipelineFlags);
+ fProgram = GrPathShader::MakeProgram({alloc, flushState->writeView(),
+ &flushState->dstProxyView(),
+ flushState->renderPassBarriers(), GrLoadOp::kClear,
+ &flushState->caps()}, shader, pipeline,
+ &GrUserStencilSettings::kUnused);
+ }
+ void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
+ flushState->bindPipeline(*fProgram, chainBounds);
+ fTessellator->draw(flushState);
+ }
+
+ const SkPath fPath;
+ const SkMatrix fMatrix;
+ const GrPipeline::InputFlags fPipelineFlags;
+ const Mode fMode;
+ GrPathTessellator* fTessellator = nullptr;
+ GrProgramInfo* fProgram;
+ GrProcessorSet fProcessors{SkBlendMode::kSrcOver};
+
+ friend class GrOp; // For ctor.
+};
+
+} // namespace
+
+// This sample enables wireframe and visualizes the triangles generated by path tessellators.
+class SamplePathTessellators : public Sample {
+public:
+ SamplePathTessellators() {
+#if 0
+ // For viewing middle-out triangulations of the inner fan.
+ fPath.moveTo(1, 0);
+ int numSides = 32 * 3;
+ for (int i = 1; i < numSides; ++i) {
+ float theta = 2*3.1415926535897932384626433832785 * i / numSides;
+ fPath.lineTo(std::cos(theta), std::sin(theta));
+ }
+ fPath.transform(SkMatrix::Scale(200, 200));
+ fPath.transform(SkMatrix::Translate(300, 300));
+#else
+ fPath.moveTo(100, 500);
+ fPath.cubicTo(300, 400, -100, 300, 100, 200);
+ fPath.quadTo(250, 0, 400, 200);
+ fPath.conicTo(600, 350, 400, 500, fConicWeight);
+ fPath.close();
+#endif
+ }
+
+private:
+ void onDrawContent(SkCanvas*) override;
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
+ bool onClick(Sample::Click*) override;
+ bool onChar(SkUnichar) override;
+
+ SkString name() override { return SkString("PathTessellators"); }
+
+ SkPath fPath;
+ GrPipeline::InputFlags fPipelineFlags = GrPipeline::InputFlags::kHWAntialias |
+ GrPipeline::InputFlags::kWireframe;
+ Mode fMode = Mode::kCurveMiddleOut;
+
+ float fConicWeight = .5;
+
+ class Click;
+};
+
+void SamplePathTessellators::onDrawContent(SkCanvas* canvas) {
+ canvas->clear(SK_ColorBLACK);
+
+ auto ctx = canvas->recordingContext();
+ GrSurfaceDrawContext* sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
+
+ SkString error;
+ if (!sdc || !ctx) {
+ error = "GPU Only.";
+ } else if (!GrTessellationPathRenderer::IsSupported(*ctx->priv().caps())) {
+ error = "GrTessellationPathRenderer not supported.";
+ } else if (fMode >= Mode::kWedgeTessellate &&
+ !ctx->priv().caps()->shaderCaps()->tessellationSupport()) {
+ error.printf("%s requires hardware tessellation support.", ModeName(fMode));
+ }
+ if (!error.isEmpty()) {
+ canvas->clear(SK_ColorRED);
+ SkFont font(nullptr, 20);
+ SkPaint captionPaint;
+ captionPaint.setColor(SK_ColorWHITE);
+ canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
+ return;
+ }
+
+ sdc->addDrawOp(GrOp::Make<SamplePathTessellatorOp>(ctx,
+ sdc->asRenderTargetProxy()->getBoundsRect(),
+ fPath, canvas->getTotalMatrix(),
+ fPipelineFlags, fMode));
+
+ // Draw the path points.
+ SkPaint pointsPaint;
+ pointsPaint.setColor(SK_ColorBLUE);
+ pointsPaint.setStrokeWidth(8);
+ SkPath devPath = fPath;
+ devPath.transform(canvas->getTotalMatrix());
+ {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->setMatrix(SkMatrix::I());
+ SkString caption(ModeName(fMode));
+ caption.appendf(" (w=%g)", fConicWeight);
+ SkFont font(nullptr, 20);
+ SkPaint captionPaint;
+ captionPaint.setColor(SK_ColorWHITE);
+ canvas->drawString(caption, 10, 30, font, captionPaint);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, devPath.countPoints(),
+ SkPathPriv::PointData(devPath), pointsPaint);
+ }
+}
+
+class SamplePathTessellators::Click : public Sample::Click {
+public:
+ Click(int ptIdx) : fPtIdx(ptIdx) {}
+
+ void doClick(SkPath* path) {
+ SkPoint pt = path->getPoint(fPtIdx);
+ SkPathPriv::UpdatePathPoint(path, fPtIdx, pt + fCurr - fPrev);
+ }
+
+private:
+ int fPtIdx;
+};
+
+Sample::Click* SamplePathTessellators::onFindClickHandler(SkScalar x, SkScalar y,
+ skui::ModifierKey) {
+ const SkPoint* pts = SkPathPriv::PointData(fPath);
+ float fuzz = 30;
+ for (int i = 0; i < fPath.countPoints(); ++i) {
+ if (fabs(x - pts[i].x()) < fuzz && fabsf(y - pts[i].y()) < fuzz) {
+ return new Click(i);
+ }
+ }
+ return nullptr;
+}
+
+bool SamplePathTessellators::onClick(Sample::Click* click) {
+ Click* myClick = (Click*)click;
+ myClick->doClick(&fPath);
+ return true;
+}
+
+static SkPath update_weight(const SkPath& path, float w) {
+ SkPath path_;
+ for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
+ switch (verb) {
+ case SkPathVerb::kMove:
+ path_.moveTo(pts[0]);
+ break;
+ case SkPathVerb::kLine:
+ path_.lineTo(pts[1]);
+ break;
+ case SkPathVerb::kQuad:
+ path_.quadTo(pts[1], pts[2]);
+ break;
+ case SkPathVerb::kCubic:
+ path_.cubicTo(pts[1], pts[2], pts[3]);
+ break;
+ case SkPathVerb::kConic:
+ path_.conicTo(pts[1], pts[2], (w != 1) ? w : .99f);
+ break;
+ case SkPathVerb::kClose:
+ break;
+ }
+ }
+ return path_;
+}
+
+bool SamplePathTessellators::onChar(SkUnichar unichar) {
+ switch (unichar) {
+ case 'w':
+ fPipelineFlags = (GrPipeline::InputFlags)(
+ (int)fPipelineFlags ^ (int)GrPipeline::InputFlags::kWireframe);
+ return true;
+ case 'D': {
+ fPath.dump();
+ return true;
+ }
+ case '+':
+ fConicWeight *= 2;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '=':
+ fConicWeight *= 5/4.f;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '_':
+ fConicWeight *= .5f;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '-':
+ fConicWeight *= 4/5.f;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '1':
+ case '2':
+ case '3':
+ fMode = (Mode)(unichar - '1');
+ return true;
+ }
+ return false;
+}
+
+Sample* MakeTessellatedPathSample() { return new SamplePathTessellators; }
+static SampleRegistry gTessellatedPathSample(MakeTessellatedPathSample);
+
+#endif // SK_SUPPORT_GPU
diff --git a/samplecode/SampleTessellatedWedge.cpp b/samplecode/SampleTessellatedWedge.cpp
deleted file mode 100644
index bb40896..0000000
--- a/samplecode/SampleTessellatedWedge.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2019 Google LLC.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "include/core/SkCanvas.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkGeometry.h"
-#include "src/core/SkPathPriv.h"
-#include "tools/ToolUtils.h"
-
-#if SK_SUPPORT_GPU
-
-#include "include/gpu/GrRecordingContext.h"
-#include "src/core/SkCanvasPriv.h"
-#include "src/gpu/GrClip.h"
-#include "src/gpu/GrMemoryPool.h"
-#include "src/gpu/GrRecordingContextPriv.h"
-#include "src/gpu/GrSurfaceDrawContext.h"
-#include "src/gpu/geometry/GrWangsFormula.h"
-#include "src/gpu/tessellate/GrPathStencilFillOp.h"
-
-static float kConicWeight = .5;
-
-// This sample enables wireframe and visualizes the triangulation generated by
-// GrTessellateWedgeShader.
-class TessellatedWedge : public Sample {
-public:
- TessellatedWedge() {
-#if 0
- fPath.moveTo(1, 0);
- int numSides = 32 * 3;
- for (int i = 1; i < numSides; ++i) {
- float theta = 2*3.1415926535897932384626433832785 * i / numSides;
- fPath.lineTo(std::cos(theta), std::sin(theta));
- }
- fPath.transform(SkMatrix::Scale(200, 200));
- fPath.transform(SkMatrix::Translate(300, 300));
-#else
- fPath.moveTo(100, 300);
- fPath.conicTo(300, 100, 500, 300, kConicWeight);
- fPath.cubicTo(433, 366, 366, 433, 300, 500);
-#endif
- }
-
-private:
- void onDrawContent(SkCanvas*) override;
- Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
- bool onClick(Sample::Click*) override;
- bool onChar(SkUnichar) override;
-
- SkString name() override { return SkString("TessellatedWedge"); }
-
- SkMatrix fLastViewMatrix = SkMatrix::I();
- SkPath fPath;
- GrTessellationPathRenderer::OpFlags fOpFlags = GrTessellationPathRenderer::OpFlags::kWireframe;
-
- class Click;
-};
-
-void TessellatedWedge::onDrawContent(SkCanvas* canvas) {
- canvas->clear(SK_ColorBLACK);
-
- auto ctx = canvas->recordingContext();
- GrSurfaceDrawContext* sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
-
- SkString error;
- if (!sdc || !ctx) {
- error = "GPU Only.";
- } else if (!ctx->priv().caps()->drawInstancedSupport()) {
- error = "Instanced rendering not supported.";
- }
- if (!error.isEmpty()) {
- SkFont font(nullptr, 20);
- SkPaint captionPaint;
- captionPaint.setColor(SK_ColorWHITE);
- canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
- return;
- }
-
- GrPaint paint;
- paint.setColor4f({1,0,1,1});
-
- GrAAType aa;
- if (sdc->numSamples() > 1) {
- aa = GrAAType::kMSAA;
- } else {
- aa = GrAAType::kNone;
- }
-
- sdc->addDrawOp(GrOp::Make<GrPathStencilFillOp>(ctx, canvas->getTotalMatrix(), fPath,
- std::move(paint), aa, fOpFlags));
-
- // Draw the path points.
- SkPaint pointsPaint;
- pointsPaint.setColor(SK_ColorBLUE);
- pointsPaint.setStrokeWidth(8);
- SkPath devPath = fPath;
- devPath.transform(canvas->getTotalMatrix());
- {
- SkAutoCanvasRestore acr(canvas, true);
- canvas->setMatrix(SkMatrix::I());
- canvas->drawPoints(SkCanvas::kPoints_PointMode, devPath.countPoints(),
- SkPathPriv::PointData(devPath), pointsPaint);
- }
-
- fLastViewMatrix = canvas->getTotalMatrix();
-
-
- SkString caption;
- caption.printf("w=%f (=/- and +/_ to change)", kConicWeight);
- SkFont font(nullptr, 20);
- SkPaint captionPaint;
- captionPaint.setColor(SK_ColorWHITE);
- canvas->drawString(caption, 10, 30, font, captionPaint);
-}
-
-class TessellatedWedge::Click : public Sample::Click {
-public:
- Click(int ptIdx) : fPtIdx(ptIdx) {}
-
- void doClick(SkPath* path) {
- if (fPtIdx >= 0) {
- SkPoint pt = path->getPoint(fPtIdx);
- SkPathPriv::UpdatePathPoint(path, fPtIdx, pt + fCurr - fPrev);
- } else {
- path->transform(
- SkMatrix::Translate(fCurr.x() - fPrev.x(), fCurr.y() - fPrev.y()), path);
- }
- }
-
-private:
- int fPtIdx;
-};
-
-Sample::Click* TessellatedWedge::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) {
- const SkPoint* pts = SkPathPriv::PointData(fPath);
- float fuzz = 20 / fLastViewMatrix.getMaxScale();
- for (int i = 0; i < fPath.countPoints(); ++i) {
- SkPoint screenPoint = pts[i];
- if (fabs(x - screenPoint.x()) < fuzz && fabsf(y - screenPoint.y()) < fuzz) {
- return new Click(i);
- }
- }
- return new Click(-1);
-}
-
-static float find_conic_max_error(const SkConic& conic, int numChops) {
- if (numChops > 1) {
- int leftChops = numChops / 2;
- SkConic halves[2];
- if (conic.chopAt((float)leftChops/numChops, halves)) {
- return std::max(find_conic_max_error(halves[0], leftChops),
- find_conic_max_error(halves[1], numChops - leftChops));
- }
- }
-
- const SkPoint* p = conic.fPts;
- float w = conic.fW;
- SkVector n = {p[2].fY - p[0].fY, p[0].fX - p[2].fX};
- float h1 = (p[1] - p[0]).dot(n) / n.length();
- float h = h1*w / (1 + w);
- return h;
-}
-
-static void dump_conic_max_errors(const SkPath& path) {
- SkPath path_;
- for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
- if (verb == SkPathVerb::kConic) {
- int n = GrWangsFormula::quadratic(4, pts);
- float err = find_conic_max_error(SkConic(pts, *w), n);
- SkDebugf("CONIC MAX ERROR: %f\n", err);
- }
- }
-}
-
-bool TessellatedWedge::onClick(Sample::Click* click) {
- Click* myClick = (Click*)click;
- myClick->doClick(&fPath);
- dump_conic_max_errors(fPath);
- return true;
-}
-
-static SkPath update_weight(const SkPath& path) {
- SkPath path_;
- for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
- switch (verb) {
- case SkPathVerb::kMove:
- path_.moveTo(pts[0]);
- break;
- case SkPathVerb::kLine:
- path_.lineTo(pts[1]);
- break;
- case SkPathVerb::kQuad:
- path_.quadTo(pts[1], pts[2]);
- break;
- case SkPathVerb::kCubic:
- path_.cubicTo(pts[1], pts[2], pts[3]);
- break;
- case SkPathVerb::kConic:
- path_.conicTo(pts[1], pts[2], (kConicWeight != 1) ? kConicWeight : .99f);
- break;
- default:
- SkUNREACHABLE;
- }
- }
- dump_conic_max_errors(path);
- return path_;
-}
-
-bool TessellatedWedge::onChar(SkUnichar unichar) {
- switch (unichar) {
- case 'w':
- fOpFlags = (GrTessellationPathRenderer::OpFlags)(
- (int)fOpFlags ^ (int)GrTessellationPathRenderer::OpFlags::kWireframe);
- return true;
- case 'D': {
- fPath.dump();
- return true;
- }
- case '+':
- kConicWeight *= 2;
- fPath = update_weight(fPath);
- return true;
- case '=':
- kConicWeight *= 5/4.f;
- fPath = update_weight(fPath);
- return true;
- case '_':
- kConicWeight *= .5f;
- fPath = update_weight(fPath);
- return true;
- case '-':
- kConicWeight *= 4/5.f;
- fPath = update_weight(fPath);
- return true;
- }
- return false;
-}
-
-Sample* MakeTessellatedWedgeSample() { return new TessellatedWedge; }
-static SampleRegistry gTessellatedWedgeSample(MakeTessellatedWedgeSample);
-
-#endif // SK_SUPPORT_GPU
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index ddf69ea..5e1f1f3 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -130,11 +130,11 @@
kStencilResolveProcessor_ClassID,
kFwidthSquircleTestProcessor_ClassID,
kSwizzleFragmentProcessor_ClassID,
- kTessellate_GrCubicTessellateShader_ClassID,
+ kTessellate_GrCurveMiddleOutShader_ClassID,
+ kTessellate_GrCurveTessellateShader_ClassID,
kTessellate_GrFillBoundingBoxShader_ClassID,
kTessellate_GrFillCubicHullShader_ClassID,
kTessellate_GrFillTriangleShader_ClassID,
- kTessellate_GrMiddleOutCubicShader_ClassID,
kTessellate_GrStencilTriangleShader_ClassID,
kTessellate_GrStrokeShader_ClassID,
kTessellate_GrWedgeTessellateShader_ClassID,
diff --git a/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp b/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
index 98074c7..c3924d8 100644
--- a/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
+++ b/src/gpu/tessellate/GrPathInnerTriangulateOp.cpp
@@ -102,7 +102,7 @@
using DrawInnerFan = GrPathIndirectTessellator::DrawInnerFan;
fTessellator = args.fArena->make<GrPathIndirectTessellator>(fViewMatrix, fPath,
DrawInnerFan::kNo);
- fStencilCurvesProgram = GrStencilPathShader::MakeStencilProgram<GrMiddleOutCubicShader>(
+ fStencilCurvesProgram = GrStencilPathShader::MakeStencilProgram<GrCurveMiddleOutShader>(
args, fViewMatrix, pipelineForStencils, fPath.getFillType());
}
diff --git a/src/gpu/tessellate/GrPathStencilFillOp.cpp b/src/gpu/tessellate/GrPathStencilFillOp.cpp
index 1e3d7cd..4544494 100644
--- a/src/gpu/tessellate/GrPathStencilFillOp.cpp
+++ b/src/gpu/tessellate/GrPathStencilFillOp.cpp
@@ -66,7 +66,7 @@
fStencilFanProgram = GrStencilPathShader::MakeStencilProgram<GrStencilTriangleShader>(
args, fViewMatrix, stencilPassPipeline, fPath.getFillType());
}
- fStencilPathProgram = GrStencilPathShader::MakeStencilProgram<GrMiddleOutCubicShader>(
+ fStencilPathProgram = GrStencilPathShader::MakeStencilProgram<GrCurveMiddleOutShader>(
args, fViewMatrix, stencilPassPipeline, fPath.getFillType());
} else {
// The caller should have sent Flags::kDisableHWTessellation if it was not supported.
@@ -85,7 +85,7 @@
fTessellator = args.fArena->make<GrPathOuterCurveTessellator>();
fStencilFanProgram = GrStencilPathShader::MakeStencilProgram<GrStencilTriangleShader>(
args, fViewMatrix, stencilPassPipeline, fPath.getFillType());
- fStencilPathProgram = GrStencilPathShader::MakeStencilProgram<GrCubicTessellateShader>(
+ fStencilPathProgram = GrStencilPathShader::MakeStencilProgram<GrCurveTessellateShader>(
args, fViewMatrix, stencilPassPipeline, fPath.getFillType());
} else {
// Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
diff --git a/src/gpu/tessellate/GrPathTessellator.cpp b/src/gpu/tessellate/GrPathTessellator.cpp
index 6c8a060..d511f62 100644
--- a/src/gpu/tessellate/GrPathTessellator.cpp
+++ b/src/gpu/tessellate/GrPathTessellator.cpp
@@ -128,7 +128,7 @@
}
instanceLocations[resolveLevel] = instanceWriter.makeOffset(0);
SkASSERT(fIndirectDrawCount < indirectLockCnt);
- GrMiddleOutCubicShader::WriteDrawIndirectCmd(&indirectWriter, resolveLevel,
+ GrCurveMiddleOutShader::WriteDrawIndirectCmd(&indirectWriter, resolveLevel,
instanceCountAtCurrLevel + numExtraInstances,
currentBaseInstance);
++fIndirectDrawCount;
diff --git a/src/gpu/tessellate/GrStencilPathShader.cpp b/src/gpu/tessellate/GrStencilPathShader.cpp
index b827b6c..0ff4619 100644
--- a/src/gpu/tessellate/GrStencilPathShader.cpp
+++ b/src/gpu/tessellate/GrStencilPathShader.cpp
@@ -90,7 +90,9 @@
v->codeAppendf("vsPt = %s;", vertexPos.c_str());
}
- // No fragment shader.
+ // The fragment shader is normally disabled, but output fully opaque white.
+ args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputColor);
+ args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
}
void setData(const GrGLSLProgramDataManager& pdman,
@@ -109,8 +111,8 @@
return new Impl;
}
-GrGLSLGeometryProcessor* GrCubicTessellateShader::createGLSLInstance(const GrShaderCaps&) const {
- class CubicImpl : public GrStencilPathShader::Impl {
+GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrShaderCaps&) const {
+ class Impl : public GrStencilPathShader::Impl {
SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
const char* versionAndExtensionDecls,
const GrGLSLUniformHandler&,
@@ -205,11 +207,11 @@
}
};
- return new CubicImpl;
+ return new Impl;
}
GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrShaderCaps&) const {
- class WedgeImpl : public GrStencilPathShader::Impl {
+ class Impl : public GrStencilPathShader::Impl {
SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
const char* versionAndExtensionDecls,
const GrGLSLUniformHandler&,
@@ -299,12 +301,12 @@
}
};
- return new WedgeImpl;
+ return new Impl;
}
-class GrMiddleOutCubicShader::Impl : public GrStencilPathShader::Impl {
+class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
- const auto& shader = args.fGeomProc.cast<GrMiddleOutCubicShader>();
+ const auto& shader = args.fGeomProc.cast<GrCurveMiddleOutShader>();
args.fVaryingHandler->emitAttributes(shader);
args.fVertBuilder->insertFunction(kUnpackRationalCubicFn);
args.fVertBuilder->insertFunction(kEvalRationalCubicFn);
@@ -352,10 +354,13 @@
pos = (%s * float3(pos, 1)).xy;)", viewMatrix);
}
gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos");
- // No fragment shader.
+
+ // The fragment shader is normally disabled, but output fully opaque white.
+ args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputColor);
+ args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
}
};
-GrGLSLGeometryProcessor* GrMiddleOutCubicShader::createGLSLInstance(const GrShaderCaps&) const {
+GrGLSLGeometryProcessor* GrCurveMiddleOutShader::createGLSLInstance(const GrShaderCaps&) const {
return new Impl;
}
diff --git a/src/gpu/tessellate/GrStencilPathShader.h b/src/gpu/tessellate/GrStencilPathShader.h
index ea12276..a938812 100644
--- a/src/gpu/tessellate/GrStencilPathShader.h
+++ b/src/gpu/tessellate/GrStencilPathShader.h
@@ -105,13 +105,13 @@
// Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics.
// TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
-class GrCubicTessellateShader : public GrStencilPathShader {
+class GrCurveTessellateShader : public GrStencilPathShader {
public:
- GrCubicTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
- kTessellate_GrCubicTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) {
+ GrCurveTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
+ kTessellate_GrCurveTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) {
this->setVertexAttributes(&kSinglePointAttrib, 1);
}
- const char* name() const override { return "tessellate_GrCubicTessellateShader"; }
+ const char* name() const override { return "tessellate_GrCurveTessellateShader"; }
private:
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
@@ -144,7 +144,7 @@
// The caller may compute each cubic's resolveLevel on the CPU (i.e., the log2 number of line
// segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2/conic_log2), and
// then sort the instance buffer by resolveLevel for efficient batching of indirect draws.
-class GrMiddleOutCubicShader : public GrStencilPathShader {
+class GrCurveMiddleOutShader : public GrStencilPathShader {
public:
// How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel
// line segments?
@@ -169,8 +169,8 @@
indirectWriter->write(instanceCount, baseInstance, vertexCount, 0);
}
- GrMiddleOutCubicShader(const SkMatrix& viewMatrix)
- : GrStencilPathShader(kTessellate_GrMiddleOutCubicShader_ClassID, viewMatrix,
+ GrCurveMiddleOutShader(const SkMatrix& viewMatrix)
+ : GrStencilPathShader(kTessellate_GrCurveMiddleOutShader_ClassID, viewMatrix,
GrPrimitiveType::kTriangles) {
constexpr static Attribute kInputPtsAttribs[] = {
{"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
@@ -178,7 +178,7 @@
this->setInstanceAttributes(kInputPtsAttribs, 2);
}
- const char* name() const override { return "tessellate_GrMiddleOutCubicShader"; }
+ const char* name() const override { return "tessellate_GrCurveMiddleOutShader"; }
private:
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;