skia2/samplecode/SamplePathTessellators.cpp

326 lines
12 KiB
C++
Raw Normal View History

/*
* 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/ganesh/GrOpFlushState.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/ops/GrDrawOp.h"
#include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
#include "src/gpu/ganesh/ops/TessellationPathRenderer.h"
#include "src/gpu/ganesh/tessellate/GrPathTessellationShader.h"
#include "src/gpu/ganesh/tessellate/PathTessellator.h"
#include "src/gpu/ganesh/v1/SurfaceDrawContext_v1.h"
#include "src/gpu/tessellate/AffineMatrix.h"
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
namespace skgpu::v1 {
namespace {
enum class Mode {
kWedgeMiddleOut,
Reland "Delete HW tessellation shaders for curve/wedge tessellation" This reverts commit 7d9f07c108172bf6c5c86818dbaf1a0794093f59. Reason for revert: fixing public.bzl Original change's description: > Revert "Delete HW tessellation shaders for curve/wedge tessellation" > > This reverts commit 038818ba8e53c9b839611cb8b24e5f039e4fa262. > > Reason for revert: breaking g3 roll, need to update public bzl file I think > > Original change's description: > > Delete HW tessellation shaders for curve/wedge tessellation > > > > GrPathTessellationShader_MiddleOut.cpp is just moved into > > GrPathTessellationShader.cpp, and a few factories are cleaned up since > > we don't have to differentiate between middle-out or hardware. > > > > Bug: skia:13263 > > Change-Id: I420faa614a89ef1a2c0f1075d1f8a067d15e9a81 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534200 > > Reviewed-by: Greg Daniel <egdaniel@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Bug: skia:13263 > Change-Id: I42367a21c2bf1a4283e5d9b8d0e00961f9dea2e7 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536039 > Auto-Submit: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bug: skia:13263 Change-Id: I76101f1dbfee454053c8d7502e83d3b04a768b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536096 Auto-Submit: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
2022-05-02 18:06:25 +00:00
kCurveMiddleOut
};
static const char* ModeName(Mode mode) {
switch (mode) {
case Mode::kWedgeMiddleOut:
return "MiddleOutShader (kWedges)";
case Mode::kCurveMiddleOut:
return "MiddleOutShader (kCurves)";
}
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 GrVisitProxyFunc&) 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 GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override {}
void onPrepare(GrOpFlushState* flushState) override {
constexpr static SkPMColor4f kCyan = {0,1,1,1};
auto alloc = flushState->allocator();
const SkMatrix& shaderMatrix = SkMatrix::I();
const SkMatrix& pathMatrix = fMatrix;
const GrCaps& caps = flushState->caps();
const GrShaderCaps& shaderCaps = *caps.shaderCaps();
PathTessellator::PathDrawList pathList{pathMatrix, fPath, kCyan};
Reland "Delete HW tessellation shaders for curve/wedge tessellation" This reverts commit 7d9f07c108172bf6c5c86818dbaf1a0794093f59. Reason for revert: fixing public.bzl Original change's description: > Revert "Delete HW tessellation shaders for curve/wedge tessellation" > > This reverts commit 038818ba8e53c9b839611cb8b24e5f039e4fa262. > > Reason for revert: breaking g3 roll, need to update public bzl file I think > > Original change's description: > > Delete HW tessellation shaders for curve/wedge tessellation > > > > GrPathTessellationShader_MiddleOut.cpp is just moved into > > GrPathTessellationShader.cpp, and a few factories are cleaned up since > > we don't have to differentiate between middle-out or hardware. > > > > Bug: skia:13263 > > Change-Id: I420faa614a89ef1a2c0f1075d1f8a067d15e9a81 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534200 > > Reviewed-by: Greg Daniel <egdaniel@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Bug: skia:13263 > Change-Id: I42367a21c2bf1a4283e5d9b8d0e00961f9dea2e7 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536039 > Auto-Submit: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bug: skia:13263 Change-Id: I76101f1dbfee454053c8d7502e83d3b04a768b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536096 Auto-Submit: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
2022-05-02 18:06:25 +00:00
if (fMode == Mode::kCurveMiddleOut) {
// This emulates what PathStencilCoverOp does when using curves, except we include the
// middle-out triangles directly in the written patches for convenience (normally they
// use a simple triangle pipeline). But PathCurveTessellator only knows how to read
// extra triangles from BreadcrumbTriangleList, so build on from the middle-out stack.
SkArenaAlloc storage{256};
GrInnerFanTriangulator::BreadcrumbTriangleList triangles;
for (tess::PathMiddleOutFanIter it(fPath); !it.done();) {
for (auto [p0, p1, p2] : it.nextStack()) {
triangles.append(&storage,
pathMatrix.mapPoint(p0),
pathMatrix.mapPoint(p1),
pathMatrix.mapPoint(p2),
/*winding=*/1);
}
}
auto* tess = PathCurveTessellator::Make(alloc, shaderCaps.fInfinitySupport);
Reland "Delete HW tessellation shaders for curve/wedge tessellation" This reverts commit 7d9f07c108172bf6c5c86818dbaf1a0794093f59. Reason for revert: fixing public.bzl Original change's description: > Revert "Delete HW tessellation shaders for curve/wedge tessellation" > > This reverts commit 038818ba8e53c9b839611cb8b24e5f039e4fa262. > > Reason for revert: breaking g3 roll, need to update public bzl file I think > > Original change's description: > > Delete HW tessellation shaders for curve/wedge tessellation > > > > GrPathTessellationShader_MiddleOut.cpp is just moved into > > GrPathTessellationShader.cpp, and a few factories are cleaned up since > > we don't have to differentiate between middle-out or hardware. > > > > Bug: skia:13263 > > Change-Id: I420faa614a89ef1a2c0f1075d1f8a067d15e9a81 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534200 > > Reviewed-by: Greg Daniel <egdaniel@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Bug: skia:13263 > Change-Id: I42367a21c2bf1a4283e5d9b8d0e00961f9dea2e7 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536039 > Auto-Submit: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bug: skia:13263 Change-Id: I76101f1dbfee454053c8d7502e83d3b04a768b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536096 Auto-Submit: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
2022-05-02 18:06:25 +00:00
tess->prepareWithTriangles(flushState, shaderMatrix, &triangles, pathList,
fPath.countVerbs());
fTessellator = tess;
} else {
// This emulates what PathStencilCoverOp does when using wedges.
fTessellator = PathWedgeTessellator::Make(alloc, shaderCaps.fInfinitySupport);
Reland "Delete HW tessellation shaders for curve/wedge tessellation" This reverts commit 7d9f07c108172bf6c5c86818dbaf1a0794093f59. Reason for revert: fixing public.bzl Original change's description: > Revert "Delete HW tessellation shaders for curve/wedge tessellation" > > This reverts commit 038818ba8e53c9b839611cb8b24e5f039e4fa262. > > Reason for revert: breaking g3 roll, need to update public bzl file I think > > Original change's description: > > Delete HW tessellation shaders for curve/wedge tessellation > > > > GrPathTessellationShader_MiddleOut.cpp is just moved into > > GrPathTessellationShader.cpp, and a few factories are cleaned up since > > we don't have to differentiate between middle-out or hardware. > > > > Bug: skia:13263 > > Change-Id: I420faa614a89ef1a2c0f1075d1f8a067d15e9a81 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534200 > > Reviewed-by: Greg Daniel <egdaniel@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Bug: skia:13263 > Change-Id: I42367a21c2bf1a4283e5d9b8d0e00961f9dea2e7 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536039 > Auto-Submit: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bug: skia:13263 Change-Id: I76101f1dbfee454053c8d7502e83d3b04a768b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536096 Auto-Submit: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
2022-05-02 18:06:25 +00:00
fTessellator->prepare(flushState, shaderMatrix, pathList, fPath.countVerbs());
}
Reland "Delete HW tessellation shaders for curve/wedge tessellation" This reverts commit 7d9f07c108172bf6c5c86818dbaf1a0794093f59. Reason for revert: fixing public.bzl Original change's description: > Revert "Delete HW tessellation shaders for curve/wedge tessellation" > > This reverts commit 038818ba8e53c9b839611cb8b24e5f039e4fa262. > > Reason for revert: breaking g3 roll, need to update public bzl file I think > > Original change's description: > > Delete HW tessellation shaders for curve/wedge tessellation > > > > GrPathTessellationShader_MiddleOut.cpp is just moved into > > GrPathTessellationShader.cpp, and a few factories are cleaned up since > > we don't have to differentiate between middle-out or hardware. > > > > Bug: skia:13263 > > Change-Id: I420faa614a89ef1a2c0f1075d1f8a067d15e9a81 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534200 > > Reviewed-by: Greg Daniel <egdaniel@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Bug: skia:13263 > Change-Id: I42367a21c2bf1a4283e5d9b8d0e00961f9dea2e7 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536039 > Auto-Submit: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bug: skia:13263 Change-Id: I76101f1dbfee454053c8d7502e83d3b04a768b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536096 Auto-Submit: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
2022-05-02 18:06:25 +00:00
auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
fPipelineFlags);
auto* tessShader = GrPathTessellationShader::Make(*caps.shaderCaps(),
alloc,
shaderMatrix,
kCyan,
fTessellator->patchAttribs());
fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
flushState->usesMSAASurface(),
&flushState->dstProxyView(),
flushState->renderPassBarriers(),
GrLoadOp::kClear, &flushState->caps()},
tessShader,
pipeline,
&GrUserStencilSettings::kUnused);
}
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
flushState->bindPipeline(*fProgram, chainBounds);
Reland "Delete HW tessellation shaders for curve/wedge tessellation" This reverts commit 7d9f07c108172bf6c5c86818dbaf1a0794093f59. Reason for revert: fixing public.bzl Original change's description: > Revert "Delete HW tessellation shaders for curve/wedge tessellation" > > This reverts commit 038818ba8e53c9b839611cb8b24e5f039e4fa262. > > Reason for revert: breaking g3 roll, need to update public bzl file I think > > Original change's description: > > Delete HW tessellation shaders for curve/wedge tessellation > > > > GrPathTessellationShader_MiddleOut.cpp is just moved into > > GrPathTessellationShader.cpp, and a few factories are cleaned up since > > we don't have to differentiate between middle-out or hardware. > > > > Bug: skia:13263 > > Change-Id: I420faa614a89ef1a2c0f1075d1f8a067d15e9a81 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/534200 > > Reviewed-by: Greg Daniel <egdaniel@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Bug: skia:13263 > Change-Id: I42367a21c2bf1a4283e5d9b8d0e00961f9dea2e7 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536039 > Auto-Submit: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Bug: skia:13263 Change-Id: I76101f1dbfee454053c8d7502e83d3b04a768b34 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/536096 Auto-Submit: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
2022-05-02 18:06:25 +00:00
fTessellator->draw(flushState);
}
const SkPath fPath;
const SkMatrix fMatrix;
const GrPipeline::InputFlags fPipelineFlags;
const Mode fMode;
PathTessellator* 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::kWireframe;
Mode fMode = Mode::kWedgeMiddleOut;
float fConicWeight = .5;
class Click;
};
void SamplePathTessellators::onDrawContent(SkCanvas* canvas) {
canvas->clear(SK_ColorBLACK);
auto ctx = canvas->recordingContext();
auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
SkString error;
if (!sdc || !ctx) {
error = "GPU Only.";
} else if (!skgpu::v1::TessellationPathRenderer::IsSupported(*ctx->priv().caps())) {
error = "TessellationPathRenderer not supported.";
}
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':
fMode = (Mode)(unichar - '1');
return true;
}
return false;
}
Sample* MakeTessellatedPathSample() { return new SamplePathTessellators; }
static SampleRegistry gTessellatedPathSample(MakeTessellatedPathSample);
} // namespace skgpu::v1
#endif // SK_SUPPORT_GPU