blob: fb7d631a9c50bb0895e12519faef85b1487648d0 [file] [log] [blame]
/*
* Copyright 2020 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrStrokeTessellateOp_DEFINED
#define GrStrokeTessellateOp_DEFINED
#include "include/core/SkStrokeRec.h"
#include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/tessellate/GrPathShader.h"
#include "src/gpu/tessellate/GrStrokeTessellator.h"
class GrRecordingContext;
// Renders strokes by linearizing them into sorted "parametric" and "radial" edges. See
// GrStrokeTessellateShader.
class GrStrokeTessellateOp : public GrDrawOp {
public:
GrStrokeTessellateOp(GrAAType, const SkMatrix&, const SkPath&, const SkStrokeRec&, GrPaint&&);
private:
using ShaderFlags = GrStrokeTessellateShader::ShaderFlags;
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
DEFINE_OP_CLASS_ID
SkStrokeRec& headStroke() { return fPathStrokeList.fStroke; }
SkPMColor4f& headColor() { return fPathStrokeList.fColor; }
// Returns whether it is a good tradeoff to use the dynamic states flagged in the given
// bitfield. Dynamic states improve batching, but if they aren't already enabled, they come at
// the cost of having to write out more data with each patch or instance.
bool shouldUseDynamicStates(ShaderFlags neededDynamicStates) const {
// Use the dynamic states if either (1) they are all already enabled anyway, or (2) we don't
// have many verbs.
constexpr static int kMaxVerbsToEnableDynamicState = 50;
bool anyStateDisabled = (bool)(~fShaderFlags & neededDynamicStates);
bool allStatesEnabled = !anyStateDisabled;
return allStatesEnabled || (fTotalCombinedVerbCnt <= kMaxVerbsToEnableDynamicState);
}
bool canUseHardwareTessellation(int numVerbs, const GrCaps& caps);
const char* name() const override { return "GrStrokeTessellateOp"; }
void visitProxies(const VisitProxyFunc& fn) const override;
FixedFunctionFlags fixedFunctionFlags() const override;
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
// Creates the tessellator and the stencil/fill program(s) we will use with it.
void prePrepareTessellator(GrPathShader::ProgramArgs&&, GrAppliedClip&&);
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
GrLoadOp colorLoadOp) override;
void onPrepare(GrOpFlushState*) override;
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
const GrAAType fAAType;
const SkMatrix fViewMatrix;
ShaderFlags fShaderFlags = ShaderFlags::kNone;
PathStrokeList fPathStrokeList;
PathStrokeList** fPathStrokeTail = &fPathStrokeList.fNext;
int fTotalCombinedVerbCnt = 0;
GrProcessorSet fProcessors;
bool fNeedsStencil = false;
GrStrokeTessellator* fTessellator = nullptr;
const GrProgramInfo* fStencilProgram = nullptr; // Only used if the stroke has transparency.
const GrProgramInfo* fFillProgram = nullptr;
};
#endif