blob: 73b399e448cbf748fa71c0515ca497fffcd7a205 [file] [log] [blame]
/*
* Copyright 2021 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef PathStencilCoverOp_DEFINED
#define PathStencilCoverOp_DEFINED
#include "src/gpu/ganesh/ops/FillPathFlags.h"
#include "src/gpu/ganesh/ops/GrDrawOp.h"
#include "src/gpu/ganesh/tessellate/GrTessellationShader.h"
#include "src/gpu/ganesh/tessellate/PathTessellator.h"
namespace skgpu::ganesh {
// Draws paths using a standard Redbook "stencil then cover" method. Curves get linearized by either
// GPU tessellation shaders or indirect draws. This Op doesn't apply analytic AA, so it requires
// MSAA if AA is desired.
class PathStencilCoverOp final : public GrDrawOp {
private:
DEFINE_OP_CLASS_ID
using PathDrawList = PathTessellator::PathDrawList;
// If the path is inverse filled, drawBounds must be the entire backing store dimensions of the
// render target.
PathStencilCoverOp(SkArenaAlloc* arena,
const SkMatrix& viewMatrix,
const SkPath& path,
GrPaint&& paint,
GrAAType aaType,
FillPathFlags pathFlags,
const SkRect& drawBounds)
: GrDrawOp(ClassID())
, fPathDrawList(arena->make<PathDrawList>(viewMatrix, path, SK_PMColor4fTRANSPARENT))
, fTotalCombinedPathVerbCnt(path.countVerbs())
, fPathCount(1)
, fPathFlags(pathFlags)
, fAAType(aaType)
, fColor(paint.getColor4f())
, fProcessors(std::move(paint)) {
this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
SkDEBUGCODE(fOriginalDrawBounds = drawBounds;)
}
// Constructs a PathStencilCoverOp from an existing draw list.
// FIXME: The only user of this method is the atlas. We should move the GrProgramInfos into
// PathTessellator so the atlas can use that directly instead of going through this class.
PathStencilCoverOp(const PathDrawList* pathDrawList,
int totalCombinedVerbCnt,
int pathCount,
GrPaint&& paint,
GrAAType aaType,
FillPathFlags pathFlags,
const SkRect& drawBounds)
: GrDrawOp(ClassID())
, fPathDrawList(pathDrawList)
, fTotalCombinedPathVerbCnt(totalCombinedVerbCnt)
, fPathCount(pathCount)
, fPathFlags(pathFlags)
, fAAType(aaType)
, fColor(paint.getColor4f())
, fProcessors(std::move(paint)) {
this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
SkDEBUGCODE(fOriginalDrawBounds = drawBounds;)
}
const char* name() const override { return "PathStencilCoverOp"; }
void visitProxies(const GrVisitProxyFunc&) const override;
FixedFunctionFlags fixedFunctionFlags() const override;
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
// All paths in fPathDrawList are required to have the same fill type.
SkPathFillType pathFillType() const {
return fPathDrawList->fPath.getFillType();
}
// Chooses the rendering method we will use and creates the corresponding tessellator and
// stencil/cover programs.
void prePreparePrograms(const GrTessellationShader::ProgramArgs&, GrAppliedClip&& clip);
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
const GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override;
void onPrepare(GrOpFlushState*) override;
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
const PathDrawList* fPathDrawList;
const int fTotalCombinedPathVerbCnt;
const int fPathCount;
const FillPathFlags fPathFlags;
const GrAAType fAAType;
SkPMColor4f fColor;
GrProcessorSet fProcessors;
SkDEBUGCODE(SkRect fOriginalDrawBounds;)
// Decided during prePreparePrograms.
PathTessellator* fTessellator = nullptr;
const GrProgramInfo* fStencilFanProgram = nullptr;
const GrProgramInfo* fStencilPathProgram = nullptr;
const GrProgramInfo* fCoverBBoxProgram = nullptr;
// Filled during onPrepare.
sk_sp<const GrBuffer> fFanBuffer;
int fFanBaseVertex = 0;
int fFanVertexCount = 0;
sk_sp<const GrBuffer> fBBoxBuffer;
int fBBoxBaseInstance = 0;
// Only used if sk_VertexID is not supported.
sk_sp<const GrGpuBuffer> fBBoxVertexBufferIfNoIDSupport;
friend class GrOp; // For ctor.
};
} // namespace skgpu::ganesh
#endif // PathStencilCoverOp_DEFINED