| /* |
| * 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 |