Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / gpu / ganesh / ops / AALinearizingConvexPathRenderer.cpp
1 /*
2  * Copyright 2015 Google Inc.
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 "src/gpu/ganesh/ops/AALinearizingConvexPathRenderer.h"
9
10 #include "include/core/SkString.h"
11 #include "src/core/SkGeometry.h"
12 #include "src/core/SkPathPriv.h"
13 #include "src/core/SkTraceEvent.h"
14 #include "src/gpu/BufferWriter.h"
15 #include "src/gpu/ganesh/GrAuditTrail.h"
16 #include "src/gpu/ganesh/GrCaps.h"
17 #include "src/gpu/ganesh/GrDefaultGeoProcFactory.h"
18 #include "src/gpu/ganesh/GrDrawOpTest.h"
19 #include "src/gpu/ganesh/GrGeometryProcessor.h"
20 #include "src/gpu/ganesh/GrOpFlushState.h"
21 #include "src/gpu/ganesh/GrProcessor.h"
22 #include "src/gpu/ganesh/GrProgramInfo.h"
23 #include "src/gpu/ganesh/GrStyle.h"
24 #include "src/gpu/ganesh/geometry/GrAAConvexTessellator.h"
25 #include "src/gpu/ganesh/geometry/GrPathUtils.h"
26 #include "src/gpu/ganesh/geometry/GrStyledShape.h"
27 #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
28 #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
29 #include "src/gpu/ganesh/v1/SurfaceDrawContext_v1.h"
30
31 ///////////////////////////////////////////////////////////////////////////////
32 namespace skgpu::v1 {
33
34 namespace {
35
36 static const int DEFAULT_BUFFER_SIZE = 100;
37
38 // The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
39 // the time being, we simply drop back to software rendering above this stroke width.
40 static const SkScalar kMaxStrokeWidth = 20.0;
41
42 // extract the result vertices and indices from the GrAAConvexTessellator
43 void extract_verts(const GrAAConvexTessellator& tess,
44                    const SkMatrix* localCoordsMatrix,
45                    void* vertData,
46                    const VertexColor& color,
47                    uint16_t firstIndex,
48                    uint16_t* idxs) {
49     VertexWriter verts{vertData};
50     for (int i = 0; i < tess.numPts(); ++i) {
51         SkPoint lc;
52         if (localCoordsMatrix) {
53             localCoordsMatrix->mapPoints(&lc, &tess.point(i), 1);
54         }
55         verts << tess.point(i) << color << VertexWriter::If(localCoordsMatrix, lc)
56               << tess.coverage(i);
57     }
58
59     for (int i = 0; i < tess.numIndices(); ++i) {
60         idxs[i] = tess.index(i) + firstIndex;
61     }
62 }
63
64 GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
65                                           bool tweakAlphaForCoverage,
66                                           bool usesLocalCoords,
67                                           bool wideColor) {
68     using namespace GrDefaultGeoProcFactory;
69
70     Coverage::Type coverageType =
71         tweakAlphaForCoverage ? Coverage::kAttributeTweakAlpha_Type : Coverage::kAttribute_Type;
72     LocalCoords::Type localCoordsType =
73             usesLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUnused_Type;
74     Color::Type colorType =
75         wideColor ? Color::kPremulWideColorAttribute_Type : Color::kPremulGrColorAttribute_Type;
76
77     return Make(arena, colorType, coverageType, localCoordsType, SkMatrix::I());
78 }
79
80 class AAFlatteningConvexPathOp final : public GrMeshDrawOp {
81 private:
82     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
83
84 public:
85     DEFINE_OP_CLASS_ID
86
87     static GrOp::Owner Make(GrRecordingContext* context,
88                             GrPaint&& paint,
89                             const SkMatrix& viewMatrix,
90                             const SkPath& path,
91                             SkScalar strokeWidth,
92                             SkStrokeRec::Style style,
93                             SkPaint::Join join,
94                             SkScalar miterLimit,
95                             const GrUserStencilSettings* stencilSettings) {
96         return Helper::FactoryHelper<AAFlatteningConvexPathOp>(context, std::move(paint),
97                                                                viewMatrix, path,
98                                                                strokeWidth, style, join, miterLimit,
99                                                                stencilSettings);
100     }
101
102     AAFlatteningConvexPathOp(GrProcessorSet* processorSet,
103                              const SkPMColor4f& color,
104                              const SkMatrix& viewMatrix,
105                              const SkPath& path,
106                              SkScalar strokeWidth,
107                              SkStrokeRec::Style style,
108                              SkPaint::Join join,
109                              SkScalar miterLimit,
110                              const GrUserStencilSettings* stencilSettings)
111             : INHERITED(ClassID()), fHelper(processorSet, GrAAType::kCoverage, stencilSettings) {
112         fPaths.emplace_back(
113                 PathData{viewMatrix, path, color, strokeWidth, miterLimit, style, join});
114
115         // compute bounds
116         SkRect bounds = path.getBounds();
117         SkScalar w = strokeWidth;
118         if (w > 0) {
119             w /= 2;
120             SkScalar maxScale = viewMatrix.getMaxScale();
121             // We should not have a perspective matrix, thus we should have a valid scale.
122             SkASSERT(maxScale != -1);
123             if (SkPaint::kMiter_Join == join && w * maxScale > 1.f) {
124                 w *= miterLimit;
125             }
126             bounds.outset(w, w);
127         }
128         this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsHairline::kNo);
129     }
130
131     const char* name() const override { return "AAFlatteningConvexPathOp"; }
132
133     void visitProxies(const GrVisitProxyFunc& func) const override {
134         if (fProgramInfo) {
135             fProgramInfo->visitFPProxies(func);
136         } else {
137             fHelper.visitProxies(func);
138         }
139     }
140
141     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
142
143     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
144                                       GrClampType clampType) override {
145         return fHelper.finalizeProcessors(caps, clip, clampType,
146                                           GrProcessorAnalysisCoverage::kSingleChannel,
147                                           &fPaths.back().fColor, &fWideColor);
148     }
149
150 private:
151     GrProgramInfo* programInfo() override { return fProgramInfo; }
152
153     void onCreateProgramInfo(const GrCaps* caps,
154                              SkArenaAlloc* arena,
155                              const GrSurfaceProxyView& writeView,
156                              bool usesMSAASurface,
157                              GrAppliedClip&& appliedClip,
158                              const GrDstProxyView& dstProxyView,
159                              GrXferBarrierFlags renderPassXferBarriers,
160                              GrLoadOp colorLoadOp) override {
161         GrGeometryProcessor* gp = create_lines_only_gp(arena,
162                                                        fHelper.compatibleWithCoverageAsAlpha(),
163                                                        fHelper.usesLocalCoords(),
164                                                        fWideColor);
165         if (!gp) {
166             SkDebugf("Couldn't create a GrGeometryProcessor\n");
167             return;
168         }
169
170         fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface,
171                                                             std::move(appliedClip), dstProxyView,
172                                                             gp, GrPrimitiveType::kTriangles,
173                                                             renderPassXferBarriers, colorLoadOp);
174     }
175
176     void recordDraw(GrMeshDrawTarget* target,
177                     int vertexCount, size_t vertexStride, void* vertices,
178                     int indexCount, uint16_t* indices) {
179         if (vertexCount == 0 || indexCount == 0) {
180             return;
181         }
182         sk_sp<const GrBuffer> vertexBuffer;
183         int firstVertex;
184         void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
185                                               &firstVertex);
186         if (!verts) {
187             SkDebugf("Could not allocate vertices\n");
188             return;
189         }
190         memcpy(verts, vertices, vertexCount * vertexStride);
191
192         sk_sp<const GrBuffer> indexBuffer;
193         int firstIndex;
194         uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
195         if (!idxs) {
196             SkDebugf("Could not allocate indices\n");
197             return;
198         }
199         memcpy(idxs, indices, indexCount * sizeof(uint16_t));
200         GrSimpleMesh* mesh = target->allocMesh();
201         mesh->setIndexed(std::move(indexBuffer), indexCount, firstIndex, 0, vertexCount - 1,
202                          GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
203         fMeshes.push_back(mesh);
204     }
205
206     void onPrepareDraws(GrMeshDrawTarget* target) override {
207         if (!fProgramInfo) {
208             this->createProgramInfo(target);
209             if (!fProgramInfo) {
210                 return;
211             }
212         }
213
214         size_t vertexStride =  fProgramInfo->geomProc().vertexStride();
215         int instanceCount = fPaths.count();
216
217         int64_t vertexCount = 0;
218         int64_t indexCount = 0;
219         int64_t maxVertices = DEFAULT_BUFFER_SIZE;
220         int64_t maxIndices = DEFAULT_BUFFER_SIZE;
221         uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
222         uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
223         for (int i = 0; i < instanceCount; i++) {
224             const PathData& args = fPaths[i];
225             GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
226                                        args.fJoin, args.fMiterLimit);
227
228             if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
229                 continue;
230             }
231
232             int currentVertices = tess.numPts();
233             if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
234                 // if we added the current instance, we would overflow the indices we can store in a
235                 // uint16_t. Draw what we've got so far and reset.
236                 this->recordDraw(target, vertexCount, vertexStride, vertices, indexCount, indices);
237                 vertexCount = 0;
238                 indexCount = 0;
239             }
240             if (vertexCount + currentVertices > maxVertices) {
241                 maxVertices = std::max(vertexCount + currentVertices, maxVertices * 2);
242                 if (maxVertices * vertexStride > SK_MaxS32) {
243                     sk_free(vertices);
244                     sk_free(indices);
245                     return;
246                 }
247                 vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
248             }
249             int currentIndices = tess.numIndices();
250             if (indexCount + currentIndices > maxIndices) {
251                 maxIndices = std::max(indexCount + currentIndices, maxIndices * 2);
252                 if (maxIndices * sizeof(uint16_t) > SK_MaxS32) {
253                     sk_free(vertices);
254                     sk_free(indices);
255                     return;
256                 }
257                 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
258             }
259
260             const SkMatrix* localCoordsMatrix = nullptr;
261             SkMatrix ivm;
262             if (fHelper.usesLocalCoords()) {
263                 if (!args.fViewMatrix.invert(&ivm)) {
264                     ivm = SkMatrix::I();
265                 }
266                 localCoordsMatrix = &ivm;
267             }
268
269             extract_verts(tess, localCoordsMatrix, vertices + vertexStride * vertexCount,
270                           VertexColor(args.fColor, fWideColor), vertexCount, indices + indexCount);
271             vertexCount += currentVertices;
272             indexCount += currentIndices;
273         }
274         if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
275             this->recordDraw(target, vertexCount, vertexStride, vertices, indexCount, indices);
276         }
277         sk_free(vertices);
278         sk_free(indices);
279     }
280
281     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
282         if (!fProgramInfo || fMeshes.isEmpty()) {
283             return;
284         }
285
286         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
287         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
288         for (int i = 0; i < fMeshes.count(); ++i) {
289             flushState->drawMesh(*fMeshes[i]);
290         }
291     }
292
293     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
294         AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
295         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
296             return CombineResult::kCannotCombine;
297         }
298
299         fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
300         fWideColor |= that->fWideColor;
301         return CombineResult::kMerged;
302     }
303
304 #if GR_TEST_UTILS
305     SkString onDumpInfo() const override {
306         SkString string;
307         for (const auto& path : fPaths) {
308             string.appendf(
309                     "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
310                     "MiterLimit: %.2f\n",
311                     path.fColor.toBytes_RGBA(), path.fStrokeWidth, path.fStyle, path.fJoin,
312                     path.fMiterLimit);
313         }
314         string += fHelper.dumpInfo();
315         return string;
316     }
317 #endif
318
319     struct PathData {
320         SkMatrix fViewMatrix;
321         SkPath fPath;
322         SkPMColor4f fColor;
323         SkScalar fStrokeWidth;
324         SkScalar fMiterLimit;
325         SkStrokeRec::Style fStyle;
326         SkPaint::Join fJoin;
327     };
328
329     SkSTArray<1, PathData, true> fPaths;
330     Helper fHelper;
331     bool fWideColor;
332
333     SkTDArray<GrSimpleMesh*> fMeshes;
334     GrProgramInfo*           fProgramInfo = nullptr;
335
336     using INHERITED = GrMeshDrawOp;
337 };
338
339 }  // anonymous namespace
340
341 ///////////////////////////////////////////////////////////////////////////////////////////////////
342
343 PathRenderer::CanDrawPath
344 AALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
345     if (GrAAType::kCoverage != args.fAAType) {
346         return CanDrawPath::kNo;
347     }
348     if (!args.fShape->knownToBeConvex()) {
349         return CanDrawPath::kNo;
350     }
351     if (args.fShape->style().pathEffect()) {
352         return CanDrawPath::kNo;
353     }
354     if (args.fShape->inverseFilled()) {
355         return CanDrawPath::kNo;
356     }
357     if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
358         // Stroked zero length lines should draw, but this PR doesn't handle that case
359         return CanDrawPath::kNo;
360     }
361     const SkStrokeRec& stroke = args.fShape->style().strokeRec();
362
363     if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
364         stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
365         if (!args.fViewMatrix->isSimilarity()) {
366             return CanDrawPath::kNo;
367         }
368         SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
369         if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
370             return CanDrawPath::kNo;
371         }
372         if (strokeWidth > kMaxStrokeWidth ||
373             !args.fShape->knownToBeClosed() ||
374             stroke.getJoin() == SkPaint::Join::kRound_Join) {
375             return CanDrawPath::kNo;
376         }
377         return CanDrawPath::kYes;
378     }
379     if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
380         return CanDrawPath::kNo;
381     }
382     // This can almost handle perspective. It would need to use 3 component explicit local coords
383     // when there are FPs that require them. This is difficult to test because AAConvexPathRenderer
384     // takes almost all filled paths that could get here. So just avoid perspective fills.
385     if (args.fViewMatrix->hasPerspective()) {
386         return CanDrawPath::kNo;
387     }
388     return CanDrawPath::kYes;
389 }
390
391 bool AALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
392     GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
393                               "AALinearizingConvexPathRenderer::onDrawPath");
394     SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
395     SkASSERT(!args.fShape->isEmpty());
396     SkASSERT(!args.fShape->style().pathEffect());
397
398     SkPath path;
399     args.fShape->asPath(&path);
400     bool fill = args.fShape->style().isSimpleFill();
401     const SkStrokeRec& stroke = args.fShape->style().strokeRec();
402     SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
403     SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
404     SkScalar miterLimit = stroke.getMiter();
405
406     GrOp::Owner op = AAFlatteningConvexPathOp::Make(
407             args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth,
408             stroke.getStyle(), join, miterLimit, args.fUserStencilSettings);
409     args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
410     return true;
411 }
412
413 } // namespace skgpu::v1
414
415 #if GR_TEST_UTILS
416
417 GR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
418     SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
419     const SkPath& path = GrTest::TestPathConvex(random);
420
421     SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
422                                      SkStrokeRec::kStroke_Style,
423                                      SkStrokeRec::kStrokeAndFill_Style };
424
425     SkStrokeRec::Style style = styles[random->nextU() % 3];
426
427     SkScalar strokeWidth = -1.f;
428     SkPaint::Join join = SkPaint::kMiter_Join;
429     SkScalar miterLimit = 0.5f;
430
431     if (SkStrokeRec::kFill_Style != style) {
432         strokeWidth = random->nextRangeF(1.0f, 10.0f);
433         if (random->nextBool()) {
434             join = SkPaint::kMiter_Join;
435         } else {
436             join = SkPaint::kBevel_Join;
437         }
438         miterLimit = random->nextRangeF(0.5f, 2.0f);
439     }
440     const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
441     return skgpu::v1::AAFlatteningConvexPathOp::Make(context, std::move(paint), viewMatrix, path,
442                                                      strokeWidth, style, join, miterLimit,
443                                                      stencilSettings);
444 }
445
446 #endif