blob: c6eeacd9f4c87ca5003f3fe58df6a98521daaacc [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 GrFillPathShader_DEFINED
#define GrFillPathShader_DEFINED
#include "src/gpu/tessellate/GrPathShader.h"
class GrGLSLUniformHandler;
class GrGLSLVertexBuilder;
// This is the base class for shaders that fill a path's pixels in the final render target.
class GrFillPathShader : public GrPathShader {
public:
GrFillPathShader(ClassID classID, const SkMatrix& viewMatrix, SkPMColor4f color,
GrPrimitiveType primitiveType)
: GrPathShader(classID, viewMatrix, primitiveType, 0)
, fColor(color) {
}
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
static const GrPipeline* MakeFillPassPipeline(const GrPathShader::ProgramArgs& args,
GrAAType aaType, GrAppliedClip&& appliedClip,
GrProcessorSet&& processors) {
auto pipelineFlags = GrPipeline::InputFlags::kNone;
if (aaType != GrAAType::kNone) {
if (args.fWriteView.asRenderTargetProxy()->numSamples() == 1) {
// We are mixed sampled. We need to either enable conservative raster (preferred) or
// disable MSAA in order to avoid double blend artifacts. (Even if we disable MSAA for
// the cover geometry, the stencil test is still multisampled and will still produce
// smooth results.)
SkASSERT(aaType == GrAAType::kCoverage);
if (args.fCaps->conservativeRasterSupport()) {
pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
pipelineFlags |= GrPipeline::InputFlags::kConservativeRaster;
}
} else {
// We are standard MSAA. Leave MSAA enabled for the cover geometry.
pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
}
}
return GrSimpleMeshDrawOpHelper::CreatePipeline(
args.fCaps, args.fArena, args.fWriteView.swizzle(), std::move(appliedClip),
*args.fDstProxyView, std::move(processors), pipelineFlags);
}
// 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() {
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>());
return &kTestAndResetStencil;
}
protected:
class Impl;
virtual void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const = 0;
private:
const SkPMColor4f fColor;
};
// Fills a simple array of triangles.
class GrFillTriangleShader : public GrFillPathShader {
public:
GrFillTriangleShader(const SkMatrix& viewMatrix, SkPMColor4f color)
: GrFillPathShader(kTessellate_GrFillTriangleShader_ClassID, viewMatrix, color,
GrPrimitiveType::kTriangles) {
static constexpr Attribute kPtAttrib = {
"input_point", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
this->setVertexAttributes(&kPtAttrib, 1);
}
private:
const char* name() const override { return "GrFillTriangleShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const override;
};
// Fills an array of convex hulls surrounding 4-point cubic instances.
class GrFillCubicHullShader : public GrFillPathShader {
public:
GrFillCubicHullShader(const SkMatrix& viewMatrix, SkPMColor4f color)
: GrFillPathShader(kTessellate_GrFillCubicHullShader_ClassID, viewMatrix, color,
GrPrimitiveType::kTriangleStrip) {
static constexpr Attribute kPtsAttribs[] = {
{"input_points_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
{"input_points_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
this->setInstanceAttributes(kPtsAttribs, SK_ARRAY_COUNT(kPtsAttribs));
}
private:
const char* name() const override { return "GrFillCubicHullShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const override;
};
// Fills a path's bounding box, with subpixel outset to avoid possible T-junctions with extreme
// edges of the path.
// NOTE: The emitted geometry may not be axis-aligned, depending on the view matrix.
class GrFillBoundingBoxShader : public GrFillPathShader {
public:
GrFillBoundingBoxShader(const SkMatrix& viewMatrix, SkPMColor4f color, const SkRect& pathBounds)
: GrFillPathShader(kTessellate_GrFillBoundingBoxShader_ClassID, viewMatrix, color,
GrPrimitiveType::kTriangleStrip)
, fPathBounds(pathBounds) {
}
const SkRect& pathBounds() const { return fPathBounds; }
private:
const char* name() const override { return "GrFillBoundingBoxShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const override;
const SkRect fPathBounds;
};
#endif