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 #ifndef StrokeTessellateOp_DEFINED 9 #define StrokeTessellateOp_DEFINED 10 11 #include "include/core/SkStrokeRec.h" 12 #include "src/gpu/ganesh/ops/GrDrawOp.h" 13 #include "src/gpu/ganesh/tessellate/GrTessellationShader.h" 14 #include "src/gpu/ganesh/tessellate/StrokeTessellator.h" 15 16 class GrRecordingContext; 17 class GrStrokeTessellationShader; 18 19 namespace skgpu::v1 { 20 21 // Renders strokes by linearizing them into sorted "parametric" and "radial" edges. See 22 // GrStrokeTessellationShader. 23 class StrokeTessellateOp final : public GrDrawOp { 24 public: 25 StrokeTessellateOp(GrAAType, const SkMatrix&, const SkPath&, const SkStrokeRec&, GrPaint&&); 26 27 private: 28 using PatchAttribs = StrokeTessellator::PatchAttribs; 29 using PathStrokeList = StrokeTessellator::PathStrokeList; 30 31 DEFINE_OP_CLASS_ID 32 headStroke()33 SkStrokeRec& headStroke() { return fPathStrokeList.fStroke; } headColor()34 SkPMColor4f& headColor() { return fPathStrokeList.fColor; } 35 36 // Returns whether it is a good tradeoff to use the dynamic states flagged in the given 37 // bitfield. Dynamic states improve batching, but if they aren't already enabled, they come at 38 // the cost of having to write out more data with each patch or instance. shouldUseDynamicStates(PatchAttribs neededDynamicStates)39 bool shouldUseDynamicStates(PatchAttribs neededDynamicStates) const { 40 // Use the dynamic states if either (1) they are all already enabled anyway, or (2) we don't 41 // have many verbs. 42 constexpr static int kMaxVerbsToEnableDynamicState = 50; 43 bool anyStateDisabled = (bool)(~fPatchAttribs & neededDynamicStates); 44 bool allStatesEnabled = !anyStateDisabled; 45 return allStatesEnabled || (fTotalCombinedVerbCnt <= kMaxVerbsToEnableDynamicState); 46 } 47 name()48 const char* name() const override { return "StrokeTessellateOp"; } 49 void visitProxies(const GrVisitProxyFunc&) const override; usesMSAA()50 bool usesMSAA() const override { return fAAType == GrAAType::kMSAA; } 51 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override; usesStencil()52 bool usesStencil() const override { 53 // This must be called after finalize(). fNeedsStencil can change in finalize(). 54 SkASSERT(fProcessors.isFinalized()); 55 return fNeedsStencil; 56 } 57 CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override; 58 59 // Creates the tessellator and the stencil/fill program(s) we will use with it. 60 void prePrepareTessellator(GrTessellationShader::ProgramArgs&&, GrAppliedClip&&); 61 62 void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*, 63 const GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override; 64 65 void onPrepare(GrOpFlushState*) override; 66 67 void onExecute(GrOpFlushState*, const SkRect& chainBounds) override; 68 69 const GrAAType fAAType; 70 const SkMatrix fViewMatrix; 71 PatchAttribs fPatchAttribs = PatchAttribs::kNone; 72 PathStrokeList fPathStrokeList; 73 PathStrokeList** fPathStrokeTail = &fPathStrokeList.fNext; 74 int fTotalCombinedVerbCnt = 0; 75 GrProcessorSet fProcessors; 76 bool fNeedsStencil; 77 78 StrokeTessellator* fTessellator = nullptr; 79 GrStrokeTessellationShader* fTessellationShader; 80 const GrProgramInfo* fStencilProgram = nullptr; // Only used if the stroke has transparency. 81 const GrProgramInfo* fFillProgram = nullptr; 82 }; 83 84 } // namespace skgpu::v1 85 86 #endif // StrokeTessellateOp_DEFINED 87