1 | /* |
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 | #include "src/gpu/tessellate/GrStrokeTessellateOp.h" |
9 | |
10 | #include "src/core/SkPathPriv.h" |
11 | #include "src/gpu/tessellate/GrStrokePatchBuilder.h" |
12 | #include "src/gpu/tessellate/GrStrokeTessellateShader.h" |
13 | |
14 | static SkPMColor4f get_paint_constant_blended_color(const GrPaint& paint) { |
15 | SkPMColor4f constantColor; |
16 | // Patches can overlap, so until a stencil technique is implemented, the provided paints must be |
17 | // constant blended colors. |
18 | SkAssertResult(paint.isConstantBlendedColor(&constantColor)); |
19 | return constantColor; |
20 | } |
21 | |
22 | GrStrokeTessellateOp::GrStrokeTessellateOp(GrAAType aaType, const SkMatrix& viewMatrix, |
23 | const SkPath& path, const SkStrokeRec& stroke, |
24 | GrPaint&& paint) |
25 | : GrDrawOp(ClassID()) |
26 | , fPathStrokes(path, stroke) |
27 | , fTotalCombinedVerbCnt(path.countVerbs()) |
28 | , fAAType(aaType) |
29 | , fColor(get_paint_constant_blended_color(paint)) |
30 | , fProcessors(std::move(paint)) { |
31 | SkASSERT(fAAType != GrAAType::kCoverage); // No mixed samples support yet. |
32 | if (stroke.getJoin() == SkPaint::kMiter_Join) { |
33 | float miter = stroke.getMiter(); |
34 | if (miter <= 0) { |
35 | fPathStrokes.head().fStroke.setStrokeParams(stroke.getCap(), SkPaint::kBevel_Join, 0); |
36 | } else { |
37 | fMiterLimitOrZero = miter; |
38 | } |
39 | } |
40 | if (!(viewMatrix.getType() & ~SkMatrix::kScale_Mask) && |
41 | viewMatrix.getScaleX() == viewMatrix.getScaleY()) { |
42 | fMatrixScale = viewMatrix.getScaleX(); |
43 | fSkewMatrix = SkMatrix::I(); |
44 | } else { |
45 | SkASSERT(!viewMatrix.hasPerspective()); // getMaxScale() doesn't work with perspective. |
46 | fMatrixScale = viewMatrix.getMaxScale(); |
47 | float invScale = SkScalarInvert(fMatrixScale); |
48 | fSkewMatrix = viewMatrix; |
49 | fSkewMatrix.preScale(invScale, invScale); |
50 | } |
51 | SkASSERT(fMatrixScale >= 0); |
52 | SkRect devBounds = fPathStrokes.head().fPath.getBounds(); |
53 | float inflationRadius = fPathStrokes.head().fStroke.getInflationRadius(); |
54 | devBounds.outset(inflationRadius, inflationRadius); |
55 | viewMatrix.mapRect(&devBounds, devBounds); |
56 | this->setBounds(devBounds, HasAABloat(GrAAType::kCoverage == fAAType), IsHairline::kNo); |
57 | } |
58 | |
59 | GrDrawOp::FixedFunctionFlags GrStrokeTessellateOp::fixedFunctionFlags() const { |
60 | auto flags = FixedFunctionFlags::kNone; |
61 | if (GrAAType::kNone != fAAType) { |
62 | flags |= FixedFunctionFlags::kUsesHWAA; |
63 | } |
64 | return flags; |
65 | } |
66 | |
67 | GrProcessorSet::Analysis GrStrokeTessellateOp::finalize(const GrCaps& caps, |
68 | const GrAppliedClip* clip, |
69 | bool hasMixedSampledCoverage, |
70 | GrClampType clampType) { |
71 | return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, |
72 | &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, |
73 | clampType, &fColor); |
74 | } |
75 | |
76 | GrOp::CombineResult GrStrokeTessellateOp::onCombineIfPossible(GrOp* grOp, |
77 | GrRecordingContext::Arenas* arenas, |
78 | const GrCaps&) { |
79 | auto* op = grOp->cast<GrStrokeTessellateOp>(); |
80 | if (fColor != op->fColor || |
81 | // TODO: When stroking is finished, we may want to consider whether a unique matrix scale |
82 | // can be stored with each PathStroke instead. This might improve batching. |
83 | fMatrixScale != op->fMatrixScale || |
84 | fSkewMatrix != op->fSkewMatrix || |
85 | fAAType != op->fAAType || |
86 | ((fMiterLimitOrZero * op->fMiterLimitOrZero != 0) && // Are both non-zero? |
87 | fMiterLimitOrZero != op->fMiterLimitOrZero) || |
88 | fProcessors != op->fProcessors) { |
89 | return CombineResult::kCannotCombine; |
90 | } |
91 | |
92 | fPathStrokes.concat(std::move(op->fPathStrokes), arenas->recordTimeAllocator()); |
93 | if (op->fMiterLimitOrZero != 0) { |
94 | SkASSERT(fMiterLimitOrZero == 0 || fMiterLimitOrZero == op->fMiterLimitOrZero); |
95 | fMiterLimitOrZero = op->fMiterLimitOrZero; |
96 | } |
97 | fTotalCombinedVerbCnt += op->fTotalCombinedVerbCnt; |
98 | |
99 | return CombineResult::kMerged; |
100 | } |
101 | |
102 | void GrStrokeTessellateOp::onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView* writeView, |
103 | GrAppliedClip*, const GrXferProcessor::DstProxyView&) { |
104 | } |
105 | |
106 | void GrStrokeTessellateOp::onPrepare(GrOpFlushState* flushState) { |
107 | GrStrokePatchBuilder builder(flushState, &fVertexChunks, fMatrixScale, fTotalCombinedVerbCnt); |
108 | for (auto& [path, stroke] : fPathStrokes) { |
109 | builder.addPath(path, stroke); |
110 | } |
111 | } |
112 | |
113 | void GrStrokeTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) { |
114 | GrPipeline::InitArgs initArgs; |
115 | if (GrAAType::kNone != fAAType) { |
116 | initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias; |
117 | SkASSERT(flushState->proxy()->numSamples() > 1); // No mixed samples yet. |
118 | SkASSERT(fAAType != GrAAType::kCoverage); // No mixed samples yet. |
119 | } |
120 | initArgs.fCaps = &flushState->caps(); |
121 | initArgs.fDstProxyView = flushState->drawOpArgs().dstProxyView(); |
122 | initArgs.fWriteSwizzle = flushState->drawOpArgs().writeSwizzle(); |
123 | GrPipeline pipeline(initArgs, std::move(fProcessors), flushState->detachAppliedClip()); |
124 | |
125 | GrStrokeTessellateShader strokeShader(fSkewMatrix, fColor, fMiterLimitOrZero); |
126 | GrPathShader::ProgramInfo programInfo(flushState->writeView(), &pipeline, &strokeShader); |
127 | |
128 | SkASSERT(chainBounds == this->bounds()); |
129 | flushState->bindPipelineAndScissorClip(programInfo, this->bounds()); |
130 | flushState->bindTextures(strokeShader, nullptr, pipeline); |
131 | |
132 | for (const auto& chunk : fVertexChunks) { |
133 | if (chunk.fVertexBuffer) { |
134 | flushState->bindBuffers(nullptr, nullptr, std::move(chunk.fVertexBuffer)); |
135 | flushState->draw(chunk.fVertexCount, chunk.fBaseVertex); |
136 | } |
137 | } |
138 | } |
139 | |