blob: 305b4030061db25221341785d4231ec034da5805 [file] [log] [blame]
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPathTessellationShader_DEFINED
#define GrPathTessellationShader_DEFINED
#include "src/gpu/tessellate/Tessellation.h"
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
// This is the base class for shaders in the GPU tessellator that fill paths.
class GrPathTessellationShader : public GrTessellationShader {
public:
// Draws a simple array of triangles.
static GrPathTessellationShader* MakeSimpleTriangleShader(SkArenaAlloc*,
const SkMatrix& viewMatrix,
const SkPMColor4f&);
// Creates either a hardware tessellation or middle-out instanced shader, depending on support
// and which is expected to perform better.
static GrPathTessellationShader* Make(SkArenaAlloc*,
const SkMatrix& viewMatrix,
const SkPMColor4f&,
int totalCombinedPathVerbCnt,
const GrPipeline&,
skgpu::PatchAttribs,
const GrCaps&);
// Uses instanced draws to triangulate curves with a "middle-out" topology. Middle-out draws a
// triangle with vertices at T=[0, 1/2, 1] and then recurses breadth first:
//
// depth=0: T=[0, 1/2, 1]
// depth=1: T=[0, 1/4, 2/4], T=[2/4, 3/4, 1]
// depth=2: T=[0, 1/8, 2/8], T=[2/8, 3/8, 4/8], T=[4/8, 5/8, 6/8], T=[6/8, 7/8, 1]
// ...
//
// The shader determines how many segments are required to render each individual curve
// smoothly, and emits empty triangles at any vertices whose sk_VertexIDs are higher than
// necessary. It is the caller's responsibility to draw enough vertices per instance for the
// most complex curve in the batch to render smoothly (i.e., NumTrianglesAtResolveLevel() * 3).
//
// If PatchAttribs::kFanPoint is set, an additional triangle is added, connecting the base of
// the curve to the fan point.
static GrPathTessellationShader* MakeMiddleOutFixedCountShader(const GrShaderCaps&,
SkArenaAlloc*,
const SkMatrix& viewMatrix,
const SkPMColor4f&,
skgpu::PatchAttribs);
// Uses GPU tessellation shaders to linearize, triangulate, and render curves.
//
// If PatchAttribs::kFanPoint is set, an additional triangle is added, connecting the base of
// the curve to the fan point.
static GrPathTessellationShader* MakeHardwareTessellationShader(SkArenaAlloc*,
const SkMatrix& viewMatrix,
const SkPMColor4f&,
skgpu::PatchAttribs);
// Returns the stencil settings to use for a standard Redbook "stencil" pass.
static const GrUserStencilSettings* StencilPathSettings(GrFillRule fillRule) {
// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
constexpr static GrUserStencilSettings kIncrDecrStencil(
GrUserStencilSettings::StaticInitSeparate<
0x0000, 0x0000,
GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip,
0xffff, 0xffff,
GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
0xffff, 0xffff>());
// Inverts the bottom stencil bit. Used for "even/odd" fill.
constexpr static GrUserStencilSettings kInvertStencil(
GrUserStencilSettings::StaticInit<
0x0000,
GrUserStencilTest::kAlwaysIfInClip,
0xffff,
GrUserStencilOp::kInvert,
GrUserStencilOp::kKeep,
0x0001>());
return (fillRule == GrFillRule::kNonzero) ? &kIncrDecrStencil : &kInvertStencil;
}
// Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero
// stencil values to pass and write a color, and resets the stencil value back to zero; discards
// immediately on stencil values of zero.
static const GrUserStencilSettings* TestAndResetStencilSettings(bool isInverseFill = false) {
constexpr static GrUserStencilSettings kTestAndResetStencil(
GrUserStencilSettings::StaticInit<
0x0000,
// No need to check the clip because the previous stencil pass will have only
// written to samples already inside the clip.
GrUserStencilTest::kNotEqual,
0xffff,
GrUserStencilOp::kZero,
GrUserStencilOp::kKeep,
0xffff>());
constexpr static GrUserStencilSettings kTestAndResetStencilInverted(
GrUserStencilSettings::StaticInit<
0x0000,
// No need to check the clip because the previous stencil pass will have only
// written to samples already inside the clip.
GrUserStencilTest::kEqual,
0xffff,
GrUserStencilOp::kKeep,
GrUserStencilOp::kZero,
0xffff>());
return isInverseFill ? &kTestAndResetStencilInverted : &kTestAndResetStencil;
}
// Creates a pipeline that does not write to the color buffer.
static const GrPipeline* MakeStencilOnlyPipeline(
const ProgramArgs&,
GrAAType,
const GrAppliedHardClip&,
GrPipeline::InputFlags = GrPipeline::InputFlags::kNone);
virtual int maxTessellationSegments(const GrShaderCaps&) const = 0;
protected:
constexpr static size_t kMiddleOutVertexStride = 2 * sizeof(float);
GrPathTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
const SkPMColor4f& color, skgpu::PatchAttribs attribs)
: GrTessellationShader(classID, primitiveType, tessellationPatchVertexCount, viewMatrix,
color)
, fAttribs(attribs) {
}
// Default path tessellation shader implementation that manages a uniform matrix and color.
class Impl : public ProgramImpl {
public:
void onEmitCode(EmitArgs&, GrGPArgs*) final;
void setData(const GrGLSLProgramDataManager&, const GrShaderCaps&,
const GrGeometryProcessor&) override;
protected:
// float4x3 unpack_rational_cubic(float2 p0, float2 p1, float2 p2, float2 p3) { ...
//
// Evaluate our point of interest using numerically stable linear interpolations. We add our
// own "safe_mix" method to guarantee we get exactly "b" when T=1. The builtin mix()
// function seems spec'd to behave this way, but empirical results results have shown it
// does not always.
static const char* kEvalRationalCubicFn;
virtual void emitVertexCode(const GrShaderCaps&,
const GrPathTessellationShader&,
GrGLSLVertexBuilder*,
GrGLSLVaryingHandler*,
GrGPArgs*) = 0;
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
GrGLSLUniformHandler::UniformHandle fColorUniform;
SkString fVaryingColorName;
};
const skgpu::PatchAttribs fAttribs;
};
#endif