Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / samplecode / SamplePathTessellators.cpp
1 /*
2  * Copyright 2019 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "include/core/SkCanvas.h"
9 #include "samplecode/Sample.h"
10 #include "src/core/SkPathPriv.h"
11
12 #if SK_SUPPORT_GPU
13
14 #include "src/core/SkCanvasPriv.h"
15 #include "src/gpu/ganesh/GrOpFlushState.h"
16 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
17 #include "src/gpu/ganesh/ops/GrDrawOp.h"
18 #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
19 #include "src/gpu/ganesh/ops/TessellationPathRenderer.h"
20 #include "src/gpu/ganesh/tessellate/GrPathTessellationShader.h"
21 #include "src/gpu/ganesh/tessellate/PathTessellator.h"
22 #include "src/gpu/ganesh/v1/SurfaceDrawContext_v1.h"
23 #include "src/gpu/tessellate/AffineMatrix.h"
24 #include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
25
26 namespace skgpu::v1 {
27
28 namespace {
29
30 enum class Mode {
31     kWedgeMiddleOut,
32     kCurveMiddleOut
33 };
34
35 static const char* ModeName(Mode mode) {
36     switch (mode) {
37         case Mode::kWedgeMiddleOut:
38             return "MiddleOutShader (kWedges)";
39         case Mode::kCurveMiddleOut:
40             return "MiddleOutShader (kCurves)";
41     }
42     SkUNREACHABLE;
43 }
44
45 // Draws a path directly to the screen using a specific tessellator.
46 class SamplePathTessellatorOp : public GrDrawOp {
47 private:
48     DEFINE_OP_CLASS_ID
49
50     SamplePathTessellatorOp(const SkRect& drawBounds, const SkPath& path, const SkMatrix& m,
51                             GrPipeline::InputFlags pipelineFlags, Mode mode)
52             : GrDrawOp(ClassID())
53             , fPath(path)
54             , fMatrix(m)
55             , fPipelineFlags(pipelineFlags)
56             , fMode(mode) {
57         this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
58     }
59     const char* name() const override { return "SamplePathTessellatorOp"; }
60     void visitProxies(const GrVisitProxyFunc&) const override {}
61     FixedFunctionFlags fixedFunctionFlags() const override {
62         return FixedFunctionFlags::kUsesHWAA;
63     }
64     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
65                                       GrClampType clampType) override {
66         SkPMColor4f color;
67         return fProcessors.finalize(SK_PMColor4fWHITE, GrProcessorAnalysisCoverage::kNone, clip,
68                                     nullptr, caps, clampType, &color);
69     }
70     void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
71                       const GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override {}
72     void onPrepare(GrOpFlushState* flushState) override {
73         constexpr static SkPMColor4f kCyan = {0,1,1,1};
74         auto alloc = flushState->allocator();
75         const SkMatrix& shaderMatrix = SkMatrix::I();
76         const SkMatrix& pathMatrix = fMatrix;
77         const GrCaps& caps = flushState->caps();
78         const GrShaderCaps& shaderCaps = *caps.shaderCaps();
79
80         PathTessellator::PathDrawList pathList{pathMatrix, fPath, kCyan};
81         if (fMode == Mode::kCurveMiddleOut) {
82             // This emulates what PathStencilCoverOp does when using curves, except we include the
83             // middle-out triangles directly in the written patches for convenience (normally they
84             // use a simple triangle pipeline). But PathCurveTessellator only knows how to read
85             // extra triangles from BreadcrumbTriangleList, so build on from the middle-out stack.
86             SkArenaAlloc storage{256};
87             GrInnerFanTriangulator::BreadcrumbTriangleList triangles;
88             for (tess::PathMiddleOutFanIter it(fPath); !it.done();) {
89                 for (auto [p0, p1, p2] : it.nextStack()) {
90                     triangles.append(&storage,
91                                      pathMatrix.mapPoint(p0),
92                                      pathMatrix.mapPoint(p1),
93                                      pathMatrix.mapPoint(p2),
94                                      /*winding=*/1);
95                 }
96             }
97
98             auto* tess = PathCurveTessellator::Make(alloc, shaderCaps.infinitySupport());
99             tess->prepareWithTriangles(flushState, shaderMatrix, &triangles, pathList,
100                                        fPath.countVerbs());
101             fTessellator = tess;
102         } else {
103             // This emulates what PathStencilCoverOp does when using wedges.
104             fTessellator = PathWedgeTessellator::Make(alloc, shaderCaps.infinitySupport());
105             fTessellator->prepare(flushState, shaderMatrix, pathList, fPath.countVerbs());
106         }
107
108         auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
109                                                                  fPipelineFlags);
110         auto* tessShader = GrPathTessellationShader::Make(*caps.shaderCaps(),
111                                                           alloc,
112                                                           shaderMatrix,
113                                                           kCyan,
114                                                           fTessellator->patchAttribs());
115         fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
116                                                      flushState->usesMSAASurface(),
117                                                      &flushState->dstProxyView(),
118                                                      flushState->renderPassBarriers(),
119                                                      GrLoadOp::kClear, &flushState->caps()},
120                                                      tessShader,
121                                                      pipeline,
122                                                      &GrUserStencilSettings::kUnused);
123     }
124
125     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
126         flushState->bindPipeline(*fProgram, chainBounds);
127         fTessellator->draw(flushState);
128     }
129
130     const SkPath fPath;
131     const SkMatrix fMatrix;
132     const GrPipeline::InputFlags fPipelineFlags;
133     const Mode fMode;
134     PathTessellator* fTessellator = nullptr;
135     GrProgramInfo* fProgram;
136     GrProcessorSet fProcessors{SkBlendMode::kSrcOver};
137
138     friend class GrOp;  // For ctor.
139 };
140
141 }  // namespace
142
143 // This sample enables wireframe and visualizes the triangles generated by path tessellators.
144 class SamplePathTessellators : public Sample {
145 public:
146     SamplePathTessellators() {
147 #if 0
148         // For viewing middle-out triangulations of the inner fan.
149         fPath.moveTo(1, 0);
150         int numSides = 32 * 3;
151         for (int i = 1; i < numSides; ++i) {
152             float theta = 2*3.1415926535897932384626433832785 * i / numSides;
153             fPath.lineTo(std::cos(theta), std::sin(theta));
154         }
155         fPath.transform(SkMatrix::Scale(200, 200));
156         fPath.transform(SkMatrix::Translate(300, 300));
157 #else
158         fPath.moveTo(100, 500);
159         fPath.cubicTo(300, 400, -100, 300, 100, 200);
160         fPath.quadTo(250, 0, 400, 200);
161         fPath.conicTo(600, 350, 400, 500, fConicWeight);
162         fPath.close();
163 #endif
164     }
165
166 private:
167     void onDrawContent(SkCanvas*) override;
168     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
169     bool onClick(Sample::Click*) override;
170     bool onChar(SkUnichar) override;
171
172     SkString name() override { return SkString("PathTessellators"); }
173
174     SkPath fPath;
175     GrPipeline::InputFlags fPipelineFlags = GrPipeline::InputFlags::kWireframe;
176     Mode fMode = Mode::kWedgeMiddleOut;
177
178     float fConicWeight = .5;
179
180     class Click;
181 };
182
183 void SamplePathTessellators::onDrawContent(SkCanvas* canvas) {
184     canvas->clear(SK_ColorBLACK);
185
186     auto ctx = canvas->recordingContext();
187     auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
188
189     SkString error;
190     if (!sdc || !ctx) {
191         error = "GPU Only.";
192     } else if (!skgpu::v1::TessellationPathRenderer::IsSupported(*ctx->priv().caps())) {
193         error = "TessellationPathRenderer not supported.";
194     }
195     if (!error.isEmpty()) {
196         canvas->clear(SK_ColorRED);
197         SkFont font(nullptr, 20);
198         SkPaint captionPaint;
199         captionPaint.setColor(SK_ColorWHITE);
200         canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
201         return;
202     }
203
204     sdc->addDrawOp(GrOp::Make<SamplePathTessellatorOp>(ctx,
205                                                        sdc->asRenderTargetProxy()->getBoundsRect(),
206                                                        fPath, canvas->getTotalMatrix(),
207                                                        fPipelineFlags, fMode));
208
209     // Draw the path points.
210     SkPaint pointsPaint;
211     pointsPaint.setColor(SK_ColorBLUE);
212     pointsPaint.setStrokeWidth(8);
213     SkPath devPath = fPath;
214     devPath.transform(canvas->getTotalMatrix());
215     {
216         SkAutoCanvasRestore acr(canvas, true);
217         canvas->setMatrix(SkMatrix::I());
218         SkString caption(ModeName(fMode));
219         caption.appendf(" (w=%g)", fConicWeight);
220         SkFont font(nullptr, 20);
221         SkPaint captionPaint;
222         captionPaint.setColor(SK_ColorWHITE);
223         canvas->drawString(caption, 10, 30, font, captionPaint);
224         canvas->drawPoints(SkCanvas::kPoints_PointMode, devPath.countPoints(),
225                            SkPathPriv::PointData(devPath), pointsPaint);
226     }
227 }
228
229 class SamplePathTessellators::Click : public Sample::Click {
230 public:
231     Click(int ptIdx) : fPtIdx(ptIdx) {}
232
233     void doClick(SkPath* path) {
234         SkPoint pt = path->getPoint(fPtIdx);
235         SkPathPriv::UpdatePathPoint(path, fPtIdx, pt + fCurr - fPrev);
236     }
237
238 private:
239     int fPtIdx;
240 };
241
242 Sample::Click* SamplePathTessellators::onFindClickHandler(SkScalar x, SkScalar y,
243                                                           skui::ModifierKey) {
244     const SkPoint* pts = SkPathPriv::PointData(fPath);
245     float fuzz = 30;
246     for (int i = 0; i < fPath.countPoints(); ++i) {
247         if (fabs(x - pts[i].x()) < fuzz && fabsf(y - pts[i].y()) < fuzz) {
248             return new Click(i);
249         }
250     }
251     return nullptr;
252 }
253
254 bool SamplePathTessellators::onClick(Sample::Click* click) {
255     Click* myClick = (Click*)click;
256     myClick->doClick(&fPath);
257     return true;
258 }
259
260 static SkPath update_weight(const SkPath& path, float w) {
261     SkPath path_;
262     for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
263         switch (verb) {
264             case SkPathVerb::kMove:
265                 path_.moveTo(pts[0]);
266                 break;
267             case SkPathVerb::kLine:
268                 path_.lineTo(pts[1]);
269                 break;
270             case SkPathVerb::kQuad:
271                 path_.quadTo(pts[1], pts[2]);
272                 break;
273             case SkPathVerb::kCubic:
274                 path_.cubicTo(pts[1], pts[2], pts[3]);
275                 break;
276             case SkPathVerb::kConic:
277                 path_.conicTo(pts[1], pts[2], (w != 1) ? w : .99f);
278                 break;
279             case SkPathVerb::kClose:
280                 break;
281         }
282     }
283     return path_;
284 }
285
286 bool SamplePathTessellators::onChar(SkUnichar unichar) {
287     switch (unichar) {
288         case 'w':
289             fPipelineFlags = (GrPipeline::InputFlags)(
290                     (int)fPipelineFlags ^ (int)GrPipeline::InputFlags::kWireframe);
291             return true;
292         case 'D': {
293             fPath.dump();
294             return true;
295         }
296         case '+':
297             fConicWeight *= 2;
298             fPath = update_weight(fPath, fConicWeight);
299             return true;
300         case '=':
301             fConicWeight *= 5/4.f;
302             fPath = update_weight(fPath, fConicWeight);
303             return true;
304         case '_':
305             fConicWeight *= .5f;
306             fPath = update_weight(fPath, fConicWeight);
307             return true;
308         case '-':
309             fConicWeight *= 4/5.f;
310             fPath = update_weight(fPath, fConicWeight);
311             return true;
312         case '1':
313         case '2':
314             fMode = (Mode)(unichar - '1');
315             return true;
316     }
317     return false;
318 }
319
320 Sample* MakeTessellatedPathSample() { return new SamplePathTessellators; }
321 static SampleRegistry gTessellatedPathSample(MakeTessellatedPathSample);
322
323 }  // namespace skgpu::v1
324
325 #endif  // SK_SUPPORT_GPU