blob: 7cfa216a059b9c10868190e11d771dac177aa3df [file] [log] [blame]
Chris Dalton0e543092020-11-03 14:09:16 -07001/*
2 * Copyright 2020 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#ifndef GrStrokeOp_DEFINED
9#define GrStrokeOp_DEFINED
10
11#include "include/core/SkStrokeRec.h"
12#include "include/gpu/GrRecordingContext.h"
13#include "src/gpu/GrSTArenaList.h"
14#include "src/gpu/ops/GrDrawOp.h"
Chris Dalton06b52ad2020-12-15 10:01:35 -070015#include "src/gpu/tessellate/GrStrokeTessellateShader.h"
16#include <array>
Chris Dalton0e543092020-11-03 14:09:16 -070017
18class GrStrokeTessellateShader;
19
20// Base class for ops that render opaque, constant-color strokes by linearizing them into sorted
21// "parametric" and "radial" edges. See GrStrokeTessellateShader.
22class GrStrokeOp : public GrDrawOp {
23protected:
24 // The provided matrix must be a similarity matrix for the time being. This is so we can
25 // bootstrap this Op on top of GrStrokeGeometry with minimal modifications.
26 //
27 // Patches can overlap, so until a stencil technique is implemented, the provided paint must be
28 // a constant blended color.
29 GrStrokeOp(uint32_t classID, GrAAType, const SkMatrix&, const SkStrokeRec&, const SkPath&,
30 GrPaint&&);
31
32 const char* name() const override { return "GrStrokeTessellateOp"; }
33 void visitProxies(const VisitProxyFunc& fn) const override { fProcessors.visitProxies(fn); }
34 FixedFunctionFlags fixedFunctionFlags() const override;
35 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
36 bool hasMixedSampledCoverage, GrClampType) override;
37 CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
38
Chris Dalton06b52ad2020-12-15 10:01:35 -070039 void prePreparePrograms(GrStrokeTessellateShader::Mode, SkArenaAlloc*,
Chris Dalton55abaf52020-12-08 10:25:13 -070040 const GrSurfaceProxyView&, GrAppliedClip&&,
41 const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
42 GrLoadOp colorLoadOp, const GrCaps&);
Chris Dalton0e543092020-11-03 14:09:16 -070043
44 static float NumCombinedSegments(float numParametricSegments, float numRadialSegments) {
45 // The first and last edges are shared by both the parametric and radial sets of edges, so
46 // the total number of edges is:
47 //
48 // numCombinedEdges = numParametricEdges + numRadialEdges - 2
49 //
50 // It's also important to differentiate between the number of edges and segments in a strip:
51 //
52 // numCombinedSegments = numCombinedEdges - 1
53 //
54 // So the total number of segments in the combined strip is:
55 //
56 // numCombinedSegments = numParametricEdges + numRadialEdges - 2 - 1
57 // = numParametricSegments + 1 + numRadialSegments + 1 - 2 - 1
58 // = numParametricSegments + numRadialSegments - 1
59 //
60 return numParametricSegments + numRadialSegments - 1;
61 }
62
63 static float NumParametricSegments(float numCombinedSegments, float numRadialSegments) {
64 // numCombinedSegments = numParametricSegments + numRadialSegments - 1.
65 // (See num_combined_segments()).
66 return std::max(numCombinedSegments + 1 - numRadialSegments, 0.f);
67 }
68
Chris Dalton06b52ad2020-12-15 10:01:35 -070069 // Returns the equivalent tolerances in (pre-viewMatrix) local path space that the tessellator
70 // will use when rendering this stroke.
71 GrStrokeTessellateShader::Tolerances preTransformTolerances() const {
72 std::array<float,2> matrixScales;
73 if (!fViewMatrix.getMinMaxScales(matrixScales.data())) {
74 matrixScales.fill(1);
75 }
76 auto [matrixMinScale, matrixMaxScale] = matrixScales;
77 float localStrokeWidth = fStroke.getWidth();
78 if (fStroke.isHairlineStyle()) {
79 // If the stroke is hairline then the tessellator will operate in post-transform space
80 // instead. But for the sake of CPU methods that need to conservatively approximate the
81 // number of segments to emit, we use localStrokeWidth ~= 1/matrixMinScale.
82 float approxScale = matrixMinScale;
83 // If the matrix has strong skew, don't let the scale shoot off to infinity. (This does
84 // not affect the tessellator; only the CPU methods that approximate the number of
85 // segments to emit.)
86 approxScale = std::max(matrixMinScale, matrixMaxScale * .25f);
87 localStrokeWidth = 1/approxScale;
88 }
89 return GrStrokeTessellateShader::Tolerances(matrixMaxScale, localStrokeWidth);
90 }
91
Chris Dalton0e543092020-11-03 14:09:16 -070092 const GrAAType fAAType;
93 const SkMatrix fViewMatrix;
94 const SkStrokeRec fStroke;
Chris Dalton0e543092020-11-03 14:09:16 -070095 SkPMColor4f fColor;
Chris Dalton55abaf52020-12-08 10:25:13 -070096 bool fNeedsStencil = false;
Chris Dalton0e543092020-11-03 14:09:16 -070097 GrProcessorSet fProcessors;
98
99 GrSTArenaList<SkPath> fPathList;
Chris Dalton7b807262020-12-10 10:22:50 -0700100 int fTotalCombinedVerbCnt = 0;
101 int fTotalConicWeightCnt = 0;
Chris Dalton0e543092020-11-03 14:09:16 -0700102
Chris Dalton55abaf52020-12-08 10:25:13 -0700103 const GrProgramInfo* fStencilProgram = nullptr;
104 const GrProgramInfo* fFillProgram = nullptr;
Chris Dalton0e543092020-11-03 14:09:16 -0700105};
106
107#endif