blob: 8120136fad69c315c83b13086163fed0251a187f [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrCCPRCoverageProcessor_DEFINED
#define GrCCPRCoverageProcessor_DEFINED
#include "GrGeometryProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
class GrGLSLFragmentBuilder;
/**
* This is the geometry processor for the simple convex primitive shapes (triangles and closed curve
* segments) from which ccpr paths are composed. The output is a single-channel alpha value,
* positive for clockwise primitives and negative for counter-clockwise, that indicates coverage.
*
* The caller is responsible to render all modes for all applicable primitives into a cleared,
* floating point, alpha-only render target using SkBlendMode::kPlus. Once all of a path's
* primitives have been drawn, the render target contains a composite coverage count that can then
* be used to draw the path (see GrCCPRPathProcessor).
*
* Caller provides the primitives' (x,y) points in an fp32x2 (RG) texel buffer, and an instance
* buffer with a single int32x4 attrib (for triangles) or int32x2 (for curves) defined below. There
* are no vertex attribs.
*
* Draw calls are instanced, with one vertex per bezier point (3 for triangles). They use the
* corresponding GrPrimitiveType as defined below.
*/
class GrCCPRCoverageProcessor : public GrGeometryProcessor {
public:
// Use top-left to avoid a uniform access in the fragment shader.
static constexpr GrSurfaceOrigin kAtlasOrigin = kTopLeft_GrSurfaceOrigin;
static constexpr GrPrimitiveType kTrianglesGrPrimitiveType = GrPrimitiveType::kTriangles;
static constexpr GrPrimitiveType kQuadraticsGrPrimitiveType = GrPrimitiveType::kTriangles;
static constexpr GrPrimitiveType kCubicsGrPrimitiveType = GrPrimitiveType::kLinesAdjacency;
struct TriangleInstance {
int32_t fPt0Idx;
int32_t fPt1Idx;
int32_t fPt2Idx;
int32_t fPackedAtlasOffset; // (offsetY << 16) | (offsetX & 0xffff)
};
GR_STATIC_ASSERT(4 * 4 == sizeof(TriangleInstance));
struct CurveInstance {
int32_t fPtsIdx;
int32_t fPackedAtlasOffset; // (offsetY << 16) | (offsetX & 0xffff)
};
GR_STATIC_ASSERT(2 * 4 == sizeof(CurveInstance));
enum class Mode {
// Triangles.
kTriangleHulls,
kTriangleEdges,
kCombinedTriangleHullsAndEdges,
kTriangleCorners,
// Quadratics.
kQuadraticHulls,
kQuadraticCorners,
// Cubics.
kSerpentineHulls,
kLoopHulls,
kSerpentineCorners,
kLoopCorners
};
static constexpr GrVertexAttribType InstanceArrayFormat(Mode mode) {
return mode < Mode::kQuadraticHulls ? kVec4i_GrVertexAttribType : kVec2i_GrVertexAttribType;
}
static const char* GetProcessorName(Mode);
GrCCPRCoverageProcessor(Mode, GrBuffer* pointsBuffer);
const char* instanceAttrib() const { return fInstanceAttrib.fName; }
int atlasOffsetIdx() const {
return kVec4i_GrVertexAttribType == InstanceArrayFormat(fMode) ? 3 : 1;
}
const char* name() const override { return GetProcessorName(fMode); }
SkString dumpInfo() const override {
return SkStringPrintf("%s\n%s", this->name(), this->INHERITED::dumpInfo().c_str());
}
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
#ifdef SK_DEBUG
// Increases the 1/2 pixel AA bloat by a factor of debugBloat and outputs color instead of
// coverage (coverage=+1 -> green, coverage=0 -> black, coverage=-1 -> red).
void enableDebugVisualizations(float debugBloat) { fDebugBloat = debugBloat; }
bool debugVisualizationsEnabled() const { return fDebugBloat > 0; }
float debugBloat() const { SkASSERT(this->debugVisualizationsEnabled()); return fDebugBloat; }
static void Validate(GrRenderTargetProxy* atlasProxy);
#endif
class PrimitiveProcessor;
private:
const Mode fMode;
const Attribute& fInstanceAttrib;
BufferAccess fPointsBufferAccess;
SkDEBUGCODE(float fDebugBloat = false;)
typedef GrGeometryProcessor INHERITED;
};
/**
* This class represents the actual SKSL implementation for the various primitives and modes of
* GrCCPRCoverageProcessor.
*/
class GrCCPRCoverageProcessor::PrimitiveProcessor : public GrGLSLGeometryProcessor {
protected:
// Slightly undershoot a bloat radius of 0.5 so vertices that fall on integer boundaries don't
// accidentally bleed into neighbor pixels.
static constexpr float kAABloatRadius = 0.491111f;
// Specifies how the fragment shader should calculate sk_FragColor.a.
enum class CoverageType {
kOne, // Output +1 all around, modulated by wind.
kInterpolated, // Interpolate the coverage values that the geometry shader associates with
// each point, modulated by wind.
kShader // Call emitShaderCoverage and let the subclass decide, then a modulate by wind.
};
PrimitiveProcessor(CoverageType coverageType)
: fCoverageType(coverageType)
, fGeomWind("wind", kHalf_GrSLType, GrShaderVar::kNonArray, kLow_GrSLPrecision)
, fFragWind(kHalf_GrSLType)
, fFragCoverageTimesWind(kHalf_GrSLType) {}
// Called before generating shader code. Subclass should add its custom varyings to the handler
// and update its corresponding internal member variables.
virtual void resetVaryings(GrGLSLVaryingHandler*) {}
// Here the subclass fetches its vertex from the texel buffer, translates by atlasOffset, and
// sets "fPositionVar" in the GrGPArgs.
virtual void onEmitVertexShader(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*,
const TexelBufferHandle& pointsBuffer, const char* atlasOffset,
const char* rtAdjust, GrGPArgs*) const = 0;
// Here the subclass determines the winding direction of its primitive. It must write a value of
// either -1, 0, or +1 to "outputWind" (e.g. "sign(area)"). Fractional values are not valid.
virtual void emitWind(GrGLSLGeometryBuilder*, const char* rtAdjust,
const char* outputWind) const = 0;
// This is where the subclass generates the actual geometry to be rasterized by hardware:
//
// emitVertexFn(point1, coverage);
// emitVertexFn(point2, coverage);
// ...
// EndPrimitive();
//
// Generally a subclass will want to use emitHullGeometry and/or emitEdgeGeometry rather than
// calling emitVertexFn directly.
//
// Subclass must also call GrGLSLGeometryBuilder::configure.
virtual void onEmitGeometryShader(GrGLSLGeometryBuilder*, const char* emitVertexFn,
const char* wind, const char* rtAdjust) const = 0;
// This is a hook to inject code in the geometry shader's "emitVertex" function. Subclass
// should use this to write values to its custom varyings.
// NOTE: even flat varyings should be rewritten at each vertex.
virtual void emitPerVertexGeometryCode(SkString* fnBody, const char* position,
const char* coverage, const char* wind) const {}
// Called when the subclass has selected CoverageType::kShader. Primitives should produce
// coverage values between +0..1. Base class modulates the sign for wind.
// TODO: subclasses might have good spots to stuff the winding information without burning a
// whole new varying slot. Consider requiring them to generate the correct coverage sign.
virtual void emitShaderCoverage(GrGLSLFragmentBuilder*, const char* outputCoverage) const {
SK_ABORT("Shader coverage not implemented when using CoverageType::kShader.");
}
// Emits one wedge of the conservative raster hull of a convex polygon. The complete hull has
// one wedge for each side of the polygon (i.e. call this N times, generally from different
// geometry shader invocations). Coverage is +1 all around.
//
// Logically, the conservative raster hull is equivalent to the convex hull of pixel-size boxes
// centered on the vertices.
//
// Geometry shader must be configured to output triangle strips.
//
// Returns the maximum number of vertices that will be emitted.
int emitHullGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* polygonPts,
int numSides, const char* wedgeIdx, const char* midpoint = nullptr) const;
// Emits the conservative raster of an edge (i.e. convex hull of two pixel-size boxes centered
// on the endpoints). Coverage is -1 on the outside border of the edge geometry and 0 on the
// inside. This effectively converts a jagged conservative raster edge into a smooth antialiased
// edge when using CoverageType::kInterpolated.
//
// If the subclass has already called emitEdgeDistanceEquation, then provide the distance
// equation. Otherwise this function will call emitEdgeDistanceEquation implicitly.
//
// Geometry shader must be configured to output triangle strips.
//
// Returns the maximum number of vertices that will be emitted.
int emitEdgeGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* leftPt,
const char* rightPt, const char* distanceEquation = nullptr) const;
// Defines an equation ("dot(float3(pt, 1), distance_equation)") that is -1 on the outside
// border of a conservative raster edge and 0 on the inside (see emitEdgeGeometry).
void emitEdgeDistanceEquation(GrGLSLGeometryBuilder*, const char* leftPt, const char* rightPt,
const char* outputDistanceEquation) const;
// Emits the conservative raster of a single point (i.e. pixel-size box centered on the point).
// Coverage is +1 all around.
//
// Geometry shader must be configured to output triangle strips.
//
// Returns the number of vertices that were emitted.
int emitCornerGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* pt) const;
// Defines a global float2 array that contains MSAA sample locations as offsets from pixel
// center. Subclasses can use this for software multisampling.
//
// Returns the number of samples.
int defineSoftSampleLocations(GrGLSLFragmentBuilder*, const char* samplesName) const;
private:
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
FPCoordTransformIter&& transformIter) final {
this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
}
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final;
void emitVertexShader(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*,
const TexelBufferHandle& pointsBuffer, const char* rtAdjust,
GrGPArgs* gpArgs) const;
void emitGeometryShader(const GrCCPRCoverageProcessor&, GrGLSLGeometryBuilder*,
const char* rtAdjust) const;
void emitCoverage(const GrCCPRCoverageProcessor&, GrGLSLFragmentBuilder*,
const char* outputColor, const char* outputCoverage) const;
const CoverageType fCoverageType;
GrShaderVar fGeomWind;
GrGLSLGeoToFrag fFragWind;
GrGLSLGeoToFrag fFragCoverageTimesWind;
typedef GrGLSLGeometryProcessor INHERITED;
};
#endif