blob: feb2f7868ae4f3b681f11c302bdbe9520a79f175 [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/GrStrokeTessellateShader.h"
class GrRecordingContext;
// Prepares GPU data for, and then draws a stroke's tessellated geometry.
class GrStrokeTessellator {
using ShaderFlags = GrStrokeTessellateShader::ShaderFlags;
struct PathStrokeList {
PathStrokeList(const SkPath& path, const SkStrokeRec& stroke, const SkPMColor4f& color)
: fPath(path), fStroke(stroke), fColor(color) {}
SkPath fPath;
SkStrokeRec fStroke;
SkPMColor4f fColor;
PathStrokeList* fNext = nullptr;
GrStrokeTessellator(ShaderFlags shaderFlags, PathStrokeList* pathStrokeList)
: fShaderFlags(shaderFlags), fPathStrokeList(pathStrokeList) {}
// Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
virtual void prepare(GrMeshDrawOp::Target*, const SkMatrix&) = 0;
// Issues draw calls for the tessellated stroke. The caller is responsible for binding its
// desired pipeline ahead of time.
virtual void draw(GrOpFlushState*) const = 0;
virtual ~GrStrokeTessellator() {}
const ShaderFlags fShaderFlags;
PathStrokeList* fPathStrokeList;
// Renders strokes by linearizing them into sorted "parametric" and "radial" edges. See
// GrStrokeTessellateShader.
class GrStrokeTessellateOp : public GrDrawOp {
GrStrokeTessellateOp(GrAAType, const SkMatrix&, const SkPath&, const SkStrokeRec&, GrPaint&&);
using ShaderFlags = GrStrokeTessellateShader::ShaderFlags;
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
SkStrokeRec& headStroke() { return fPathStrokeList.fStroke; }
SkPMColor4f& headColor() { return fPathStrokeList.fColor; }
GrStrokeTessellateOp* nextInChain() const {
return static_cast<GrStrokeTessellateOp*>(this->GrDrawOp::nextInChain());
// 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(const GrCaps& caps) {
SkASSERT(!fStencilProgram && !fFillProgram); // Ensure we haven't std::moved fProcessors.
// Our back door for HW tessellation shaders isn't currently capable of passing varyings to
// the fragment shader, so if the processors have varyings we need to use indirect draws.
return caps.shaderCaps()->tessellationSupport() && !fProcessors.usesVaryingCoords();
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*,
bool hasMixedSampledCoverage, 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;