Restructure path tessellation shaders

Merges the GrStrokePathShader and GrFillPathShader classes together.
Creates a new base class called GrPathTessellationShader. Now they all
have a uniform color and can all be draw to stencil and color both.
This is necessary cleanup in general, but will also allow us to create
a convex tessellation op that bypasses the stencil buffer.

Bug: skia:10419
Change-Id: Ifc492c94d3de044a36bd9ea95b1d5aa22e007905
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/413696
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Chris Dalton 2021-06-01 12:11:57 -06:00 committed by Skia Commit-Bot
parent 8f73edeaf6
commit 2f733ec2dd
22 changed files with 493 additions and 574 deletions

View File

@ -113,21 +113,21 @@ protected:
DEF_PATH_TESS_BENCH(GrPathIndirectTessellator, make_cubic_path(18), SkMatrix::I()) { DEF_PATH_TESS_BENCH(GrPathIndirectTessellator, make_cubic_path(18), SkMatrix::I()) {
SkArenaAlloc arena(1024); SkArenaAlloc arena(1024);
auto tess = GrPathIndirectTessellator::Make(&arena, fMatrix, fPath, auto tess = GrPathIndirectTessellator::Make(&arena, fPath, fMatrix, SK_PMColor4fTRANSPARENT,
GrPathIndirectTessellator::DrawInnerFan::kNo); GrPathIndirectTessellator::DrawInnerFan::kNo);
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr); tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr);
} }
DEF_PATH_TESS_BENCH(GrPathOuterCurveTessellator, make_cubic_path(8), SkMatrix::I()) { DEF_PATH_TESS_BENCH(GrPathOuterCurveTessellator, make_cubic_path(8), SkMatrix::I()) {
SkArenaAlloc arena(1024); SkArenaAlloc arena(1024);
auto tess = GrPathOuterCurveTessellator::Make(&arena, fMatrix, auto tess = GrPathOuterCurveTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT,
GrPathTessellator::DrawInnerFan::kNo); GrPathTessellator::DrawInnerFan::kNo);
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr); tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr);
} }
DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) { DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
SkArenaAlloc arena(1024); SkArenaAlloc arena(1024);
auto tess = GrPathWedgeTessellator::Make(&arena, fMatrix); auto tess = GrPathWedgeTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT);
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr); tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr);
} }

View File

@ -452,19 +452,16 @@ skia_gpu_sources = [
"$_src/gpu/tessellate/GrCullTest.h", "$_src/gpu/tessellate/GrCullTest.h",
"$_src/gpu/tessellate/GrDrawAtlasPathOp.cpp", "$_src/gpu/tessellate/GrDrawAtlasPathOp.cpp",
"$_src/gpu/tessellate/GrDrawAtlasPathOp.h", "$_src/gpu/tessellate/GrDrawAtlasPathOp.h",
"$_src/gpu/tessellate/GrFillPathShader.cpp",
"$_src/gpu/tessellate/GrFillPathShader.h",
"$_src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h", "$_src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h",
"$_src/gpu/tessellate/GrMidpointContourParser.h", "$_src/gpu/tessellate/GrMidpointContourParser.h",
"$_src/gpu/tessellate/GrPathInnerTriangulateOp.cpp", "$_src/gpu/tessellate/GrPathInnerTriangulateOp.cpp",
"$_src/gpu/tessellate/GrPathInnerTriangulateOp.h", "$_src/gpu/tessellate/GrPathInnerTriangulateOp.h",
"$_src/gpu/tessellate/GrPathShader.h",
"$_src/gpu/tessellate/GrPathStencilFillOp.cpp", "$_src/gpu/tessellate/GrPathStencilFillOp.cpp",
"$_src/gpu/tessellate/GrPathStencilFillOp.h", "$_src/gpu/tessellate/GrPathStencilFillOp.h",
"$_src/gpu/tessellate/GrPathTessellationShader.cpp",
"$_src/gpu/tessellate/GrPathTessellationShader.h",
"$_src/gpu/tessellate/GrPathTessellator.cpp", "$_src/gpu/tessellate/GrPathTessellator.cpp",
"$_src/gpu/tessellate/GrPathTessellator.h", "$_src/gpu/tessellate/GrPathTessellator.h",
"$_src/gpu/tessellate/GrStencilPathShader.cpp",
"$_src/gpu/tessellate/GrStencilPathShader.h",
"$_src/gpu/tessellate/GrStrokeFixedCountTessellator.cpp", "$_src/gpu/tessellate/GrStrokeFixedCountTessellator.cpp",
"$_src/gpu/tessellate/GrStrokeFixedCountTessellator.h", "$_src/gpu/tessellate/GrStrokeFixedCountTessellator.h",
"$_src/gpu/tessellate/GrStrokeHardwareTessellator.cpp", "$_src/gpu/tessellate/GrStrokeHardwareTessellator.cpp",
@ -483,6 +480,7 @@ skia_gpu_sources = [
"$_src/gpu/tessellate/GrStrokeTessellator.h", "$_src/gpu/tessellate/GrStrokeTessellator.h",
"$_src/gpu/tessellate/GrTessellationPathRenderer.cpp", "$_src/gpu/tessellate/GrTessellationPathRenderer.cpp",
"$_src/gpu/tessellate/GrTessellationPathRenderer.h", "$_src/gpu/tessellate/GrTessellationPathRenderer.h",
"$_src/gpu/tessellate/GrTessellationShader.h",
"$_src/gpu/tessellate/GrVectorXform.h", "$_src/gpu/tessellate/GrVectorXform.h",
# text # text

View File

@ -14,8 +14,8 @@
#include "src/core/SkCanvasPriv.h" #include "src/core/SkCanvasPriv.h"
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrSurfaceDrawContext.h" #include "src/gpu/GrSurfaceDrawContext.h"
#include "src/gpu/tessellate/GrPathTessellationShader.h"
#include "src/gpu/tessellate/GrPathTessellator.h" #include "src/gpu/tessellate/GrPathTessellator.h"
#include "src/gpu/tessellate/GrStencilPathShader.h"
namespace { namespace {
@ -66,28 +66,30 @@ private:
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags, const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
GrLoadOp colorLoadOp) override {} GrLoadOp colorLoadOp) override {}
void onPrepare(GrOpFlushState* flushState) override { void onPrepare(GrOpFlushState* flushState) override {
constexpr static SkPMColor4f kCyan = {0,1,1,1};
auto alloc = flushState->allocator(); auto alloc = flushState->allocator();
switch (fMode) { switch (fMode) {
case Mode::kCurveMiddleOut: case Mode::kCurveMiddleOut:
fTessellator = GrPathIndirectTessellator::Make( fTessellator = GrPathIndirectTessellator::Make(
alloc, fMatrix, fPath, GrPathTessellator::DrawInnerFan::kYes); alloc, fPath, fMatrix, kCyan, GrPathTessellator::DrawInnerFan::kYes);
break; break;
case Mode::kWedgeTessellate: case Mode::kWedgeTessellate:
fTessellator = GrPathWedgeTessellator::Make(alloc, fMatrix); fTessellator = GrPathWedgeTessellator::Make(alloc, fMatrix, kCyan);
break; break;
case Mode::kCurveTessellate: case Mode::kCurveTessellate:
fTessellator = GrPathOuterCurveTessellator::Make( fTessellator = GrPathOuterCurveTessellator::Make(
alloc, fMatrix, GrPathTessellator::DrawInnerFan::kYes); alloc, fMatrix, kCyan, GrPathTessellator::DrawInnerFan::kYes);
break; break;
} }
fTessellator->prepare(flushState, this->bounds(), fPath); fTessellator->prepare(flushState, this->bounds(), fPath);
auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors), auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
fPipelineFlags); fPipelineFlags);
fProgram = GrPathShader::MakeProgram({alloc, flushState->writeView(), fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
&flushState->dstProxyView(), &flushState->dstProxyView(),
flushState->renderPassBarriers(), GrLoadOp::kClear, flushState->renderPassBarriers(),
&flushState->caps()}, fTessellator->shader(), pipeline, GrLoadOp::kClear, &flushState->caps()},
&GrUserStencilSettings::kUnused); fTessellator->shader(), pipeline,
&GrUserStencilSettings::kUnused);
} }
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
flushState->bindPipeline(*fProgram, chainBounds); flushState->bindPipeline(*fProgram, chainBounds);

View File

@ -128,14 +128,13 @@ public:
kStencilResolveProcessor_ClassID, kStencilResolveProcessor_ClassID,
kFwidthSquircleTestProcessor_ClassID, kFwidthSquircleTestProcessor_ClassID,
kSwizzleFragmentProcessor_ClassID, kSwizzleFragmentProcessor_ClassID,
kTessellate_BoundingBoxShader_ClassID,
kTessellate_GrCurveMiddleOutShader_ClassID, kTessellate_GrCurveMiddleOutShader_ClassID,
kTessellate_GrCurveTessellateShader_ClassID, kTessellate_GrCurveTessellateShader_ClassID,
kTessellate_GrFillBoundingBoxShader_ClassID,
kTessellate_GrFillCubicHullShader_ClassID,
kTessellate_GrFillTriangleShader_ClassID,
kTessellate_GrStencilTriangleShader_ClassID,
kTessellate_GrStrokeShader_ClassID, kTessellate_GrStrokeShader_ClassID,
kTessellate_GrTriangleShader_ClassID,
kTessellate_GrWedgeTessellateShader_ClassID, kTessellate_GrWedgeTessellateShader_ClassID,
kTessellate_HullShader_ClassID,
kTessellationTestTriShader_ClassID, kTessellationTestTriShader_ClassID,
kTessellationTestRectShader_ClassID, kTessellationTestRectShader_ClassID,
kTestFP_ClassID, kTestFP_ClassID,

View File

@ -1,143 +0,0 @@
/*
* Copyright 2020 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/tessellate/GrFillPathShader.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
#include "src/gpu/glsl/GrGLSLVarying.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
class GrFillPathShader::Impl : public GrGLSLGeometryProcessor {
public:
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
auto& shader = args.fGeomProc.cast<GrFillPathShader>();
args.fVaryingHandler->emitAttributes(shader);
const char* affineMatrix, *translate;
fAffineMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix", &affineMatrix);
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translate);
args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);", affineMatrix);
args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;", translate);
args.fVertBuilder->codeAppend("float2 localcoord, vertexpos;");
shader.emitVertexCode(this, args.fVertBuilder, args.fUniformHandler);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
const char* color;
fColorUniform = args.fUniformHandler->addUniform(
nullptr, kFragment_GrShaderFlag, kHalf4_GrSLType, "color", &color);
args.fFragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, color);
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
}
void setData(const GrGLSLProgramDataManager& pdman,
const GrShaderCaps&,
const GrGeometryProcessor& geomProc) override {
const GrFillPathShader& shader = geomProc.cast<GrFillPathShader>();
const SkMatrix& m = shader.viewMatrix();
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY());
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
const SkPMColor4f& color = shader.fColor;
pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
}
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
GrGLSLUniformHandler::UniformHandle fColorUniform;
};
GrGLSLGeometryProcessor* GrFillPathShader::createGLSLInstance(const GrShaderCaps&) const {
return new Impl;
}
void GrFillTriangleShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v,
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppend(R"(
localcoord = input_point;
vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
}
void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v,
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppend(R"(
float4x2 P = float4x2(input_points_0_1, input_points_2_3);
if (isinf(P[3].y)) { // Is the curve a conic?
float w = P[3].x;
if (isinf(w)) {
// A conic with w=Inf is an exact triangle.
P = float4x2(P[0], P[1], P[2], P[2]);
} else {
// Convert the control points to a trapeziodal hull that circumcscribes the conic.
float2 p1w = P[1] * w;
float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
float2 c1 = mix(P[0], p1w, T);
float2 c2 = mix(P[2], p1w, T);
float iw = 1 / mix(1, w, T);
P = float4x2(P[0], c1 * iw, c2 * iw, P[2]);
}
}
// Translate the points to v0..3 where v0=0.
float2 v1 = P[1] - P[0], v2 = P[2] - P[0], v3 = P[3] - P[0];
// Reorder the points so v2 bisects v1 and v3.
if (sign(determinant(float2x2(v2,v1))) == sign(determinant(float2x2(v2,v3)))) {
float2 tmp = P[2];
if (sign(determinant(float2x2(v1,v2))) != sign(determinant(float2x2(v1,v3)))) {
P[2] = P[1]; // swap(P2, P1)
P[1] = tmp;
} else {
P[2] = P[3]; // swap(P2, P3)
P[3] = tmp;
}
}
// sk_VertexID comes in fan order. Convert to strip order.
int vertexidx = sk_VertexID;
vertexidx ^= vertexidx >> 1;
// Find the "turn direction" of each corner and net turn direction.
float vertexdir = 0;
float netdir = 0;
for (int i = 0; i < 4; ++i) {
float2 prev = P[i] - P[(i + 3) & 3], next = P[(i + 1) & 3] - P[i];
float dir = sign(determinant(float2x2(prev, next)));
if (i == vertexidx) {
vertexdir = dir;
}
netdir += dir;
}
// Remove the non-convex vertex, if any.
if (vertexdir != sign(netdir)) {
vertexidx = (vertexidx + 1) & 3;
}
localcoord = P[vertexidx];
vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
}
void GrFillBoundingBoxShader::emitVertexCode(Impl* impl, GrGLSLVertexBuilder* v,
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppendf(R"(
// Bloat the bounding box by 1/4px to avoid potential T-junctions at the edges.
float2x2 M_ = inverse(AFFINE_MATRIX);
float2 bloat = float2(abs(M_[0]) + abs(M_[1])) * .25;
// Find the vertex position.
float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
localcoord = mix(pathBounds.xy - bloat, pathBounds.zw + bloat, T);
vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
}

View File

@ -1,117 +0,0 @@
/*
* 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 {}
GrGLSLGeometryProcessor* 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) {
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*, 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*, 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*, 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) {
constexpr static Attribute kPathBoundsAttrib = {"pathBounds", kFloat4_GrVertexAttribType,
kFloat4_GrSLType};
this->setInstanceAttributes(&kPathBoundsAttrib, 1);
}
private:
const char* name() const override { return "GrFillBoundingBoxShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, GrGLSLUniformHandler*) const override;
};
#endif

View File

@ -11,13 +11,102 @@
#include "src/gpu/GrInnerFanTriangulator.h" #include "src/gpu/GrInnerFanTriangulator.h"
#include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/tessellate/GrFillPathShader.h" #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/tessellate/GrPathTessellationShader.h"
#include "src/gpu/tessellate/GrPathTessellator.h" #include "src/gpu/tessellate/GrPathTessellator.h"
#include "src/gpu/tessellate/GrStencilPathShader.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
using OpFlags = GrTessellationPathRenderer::OpFlags; using OpFlags = GrTessellationPathRenderer::OpFlags;
namespace {
// Fills an array of convex hulls surrounding 4-point cubic or conic instances. This shader is used
// for the "fill" pass after the curves have been fully stencilled.
class HullShader : public GrPathTessellationShader {
public:
HullShader(const SkMatrix& viewMatrix, SkPMColor4f color)
: GrPathTessellationShader(kTessellate_HullShader_ClassID,
GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
constexpr static 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 final { return "HullShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
};
GrGLSLGeometryProcessor* HullShader::createGLSLInstance(const GrShaderCaps&) const {
class Impl : public GrPathTessellationShader::Impl {
void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
v->codeAppend(R"(
float4x2 P = float4x2(input_points_0_1, input_points_2_3);
if (isinf(P[3].y)) { // Is the curve a conic?
float w = P[3].x;
if (isinf(w)) {
// A conic with w=Inf is an exact triangle.
P = float4x2(P[0], P[1], P[2], P[2]);
} else {
// Convert the points to a trapeziodal hull that circumcscribes the conic.
float2 p1w = P[1] * w;
float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
float2 c1 = mix(P[0], p1w, T);
float2 c2 = mix(P[2], p1w, T);
float iw = 1 / mix(1, w, T);
P = float4x2(P[0], c1 * iw, c2 * iw, P[2]);
}
}
// Translate the points to v0..3 where v0=0.
float2 v1 = P[1] - P[0], v2 = P[2] - P[0], v3 = P[3] - P[0];
// Reorder the points so v2 bisects v1 and v3.
if (sign(determinant(float2x2(v2,v1))) == sign(determinant(float2x2(v2,v3)))) {
float2 tmp = P[2];
if (sign(determinant(float2x2(v1,v2))) != sign(determinant(float2x2(v1,v3)))) {
P[2] = P[1]; // swap(P2, P1)
P[1] = tmp;
} else {
P[2] = P[3]; // swap(P2, P3)
P[3] = tmp;
}
}
// sk_VertexID comes in fan order. Convert to strip order.
int vertexidx = sk_VertexID;
vertexidx ^= vertexidx >> 1;
// Find the "turn direction" of each corner and net turn direction.
float vertexdir = 0;
float netdir = 0;
for (int i = 0; i < 4; ++i) {
float2 prev = P[i] - P[(i + 3) & 3], next = P[(i + 1) & 3] - P[i];
float dir = sign(determinant(float2x2(prev, next)));
if (i == vertexidx) {
vertexdir = dir;
}
netdir += dir;
}
// Remove the non-convex vertex, if any.
if (vertexdir != sign(netdir)) {
vertexidx = (vertexidx + 1) & 3;
}
float2 localcoord = P[vertexidx];
float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
}
};
return new Impl;
}
} // namespace
void GrPathInnerTriangulateOp::visitProxies(const VisitProxyFunc& fn) const { void GrPathInnerTriangulateOp::visitProxies(const VisitProxyFunc& fn) const {
if (fPipelineForFills) { if (fPipelineForFills) {
fPipelineForFills->visitProxies(fn); fPipelineForFills->visitProxies(fn);
@ -41,22 +130,23 @@ GrProcessorSet::Analysis GrPathInnerTriangulateOp::finalize(const GrCaps& caps,
clampType, &fColor); clampType, &fColor);
} }
void GrPathInnerTriangulateOp::pushFanStencilProgram(const GrPathShader::ProgramArgs& args, void GrPathInnerTriangulateOp::pushFanStencilProgram(const GrTessellationShader::ProgramArgs& args,
const GrPipeline* pipelineForStencils, const GrPipeline* pipelineForStencils,
const GrUserStencilSettings* stencil) { const GrUserStencilSettings* stencil) {
SkASSERT(pipelineForStencils); SkASSERT(pipelineForStencils);
fFanPrograms.push_back(GrStencilPathShader::MakeStencilProgram<GrStencilTriangleShader>( auto shader = args.fArena->make<GrTriangleShader>(fViewMatrix, SK_PMColor4fTRANSPARENT);
args, fViewMatrix, pipelineForStencils, stencil)); fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, pipelineForStencils,
} stencil)); }
void GrPathInnerTriangulateOp::pushFanFillProgram(const GrPathShader::ProgramArgs& args, void GrPathInnerTriangulateOp::pushFanFillProgram(const GrTessellationShader::ProgramArgs& args,
const GrUserStencilSettings* stencil) { const GrUserStencilSettings* stencil) {
SkASSERT(fPipelineForFills); SkASSERT(fPipelineForFills);
auto* shader = args.fArena->make<GrFillTriangleShader>(fViewMatrix, fColor); auto* shader = args.fArena->make<GrTriangleShader>(fViewMatrix, fColor);
fFanPrograms.push_back(GrPathShader::MakeProgram(args, shader, fPipelineForFills, stencil)); fFanPrograms.push_back(GrTessellationShader::MakeProgram(args, shader, fPipelineForFills,
stencil));
} }
void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArgs& args, void GrPathInnerTriangulateOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
GrAppliedClip&& appliedClip) { GrAppliedClip&& appliedClip) {
SkASSERT(!fFanTriangulator); SkASSERT(!fFanTriangulator);
SkASSERT(!fFanPolys); SkASSERT(!fFanPolys);
@ -82,15 +172,15 @@ void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArg
// Create a pipeline for stencil passes if needed. // Create a pipeline for stencil passes if needed.
const GrPipeline* pipelineForStencils = nullptr; const GrPipeline* pipelineForStencils = nullptr;
if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled. if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled.
pipelineForStencils = GrStencilPathShader::MakeStencilPassPipeline(args, fAAType, fOpFlags, pipelineForStencils = GrPathTessellationShader::MakeStencilOnlyPipeline(
appliedClip.hardClip()); args, fAAType, fOpFlags, appliedClip.hardClip());
} }
// Create a pipeline for fill passes if needed. // Create a pipeline for fill passes if needed.
if (doFill) { if (doFill) {
fPipelineForFills = GrFillPathShader::MakeFillPassPipeline(args, fAAType, fPipelineForFills = GrTessellationShader::MakePipeline(args, fAAType,
std::move(appliedClip), std::move(appliedClip),
std::move(fProcessors)); std::move(fProcessors));
} }
// Pass 1: Tessellate the outer curves into the stencil buffer. // Pass 1: Tessellate the outer curves into the stencil buffer.
@ -99,11 +189,14 @@ void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArg
// and the middle-out topology used by indirect draws is easier on the rasterizer than what // and the middle-out topology used by indirect draws is easier on the rasterizer than what
// we can do with hw tessellation. So far we haven't found any platforms where trying to use // we can do with hw tessellation. So far we haven't found any platforms where trying to use
// hw tessellation here is worth it. // hw tessellation here is worth it.
fTessellator = GrPathTessellator::Make(args.fArena, fViewMatrix, fPath, fTessellator = GrPathTessellator::Make(args.fArena, fPath, fViewMatrix,
SK_PMColor4fTRANSPARENT,
GrPathTessellator::DrawInnerFan::kNo, *args.fCaps); GrPathTessellator::DrawInnerFan::kNo, *args.fCaps);
fStencilCurvesProgram = GrPathShader::MakeProgram( const GrUserStencilSettings* stencilPathSettings =
args, fTessellator->shader(), pipelineForStencils, GrPathTessellationShader::StencilPathSettings(fPath.getFillType());
GrStencilPathShader::StencilPassSettings(fPath.getFillType())); fStencilCurvesProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
pipelineForStencils,
stencilPathSettings);
} }
// Pass 2: Fill the path's inner fan with a stencil test against the curves. // Pass 2: Fill the path's inner fan with a stencil test against the curves.
@ -111,11 +204,12 @@ void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArg
if (forceRedbookStencilPass) { if (forceRedbookStencilPass) {
// Use a standard Redbook "stencil then fill" algorithm instead of bypassing the stencil // Use a standard Redbook "stencil then fill" algorithm instead of bypassing the stencil
// buffer to fill the fan directly. // buffer to fill the fan directly.
this->pushFanStencilProgram( const GrUserStencilSettings* stencilPathSettings =
args, pipelineForStencils, GrPathTessellationShader::StencilPathSettings(fPath.getFillType());
GrStencilPathShader::StencilPassSettings(fPath.getFillType())); this->pushFanStencilProgram(args, pipelineForStencils, stencilPathSettings);
if (doFill) { if (doFill) {
this->pushFanFillProgram(args, GrFillPathShader::TestAndResetStencilSettings()); this->pushFanFillProgram(args,
GrPathTessellationShader::TestAndResetStencilSettings());
} }
} else if (isLinear) { } else if (isLinear) {
// There are no outer curves! Ignore stencil and fill the path directly. // There are no outer curves! Ignore stencil and fill the path directly.
@ -204,10 +298,10 @@ void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArg
// by curves. We issue a final cover pass over the curves by drawing their convex hulls. // by curves. We issue a final cover pass over the curves by drawing their convex hulls.
// This will fill in any remaining samples and reset the stencil values back to zero. // This will fill in any remaining samples and reset the stencil values back to zero.
SkASSERT(fTessellator); SkASSERT(fTessellator);
auto* hullShader = args.fArena->make<GrFillCubicHullShader>(fViewMatrix, fColor); auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor);
fFillHullsProgram = GrPathShader::MakeProgram( fFillHullsProgram = GrTessellationShader::MakeProgram(
args, hullShader, fPipelineForFills, args, hullShader, fPipelineForFills,
GrFillPathShader::TestAndResetStencilSettings()); GrPathTessellationShader::TestAndResetStencilSettings());
} }
} }

View File

@ -10,7 +10,8 @@
#include "src/gpu/GrInnerFanTriangulator.h" #include "src/gpu/GrInnerFanTriangulator.h"
#include "src/gpu/ops/GrDrawOp.h" #include "src/gpu/ops/GrDrawOp.h"
#include "src/gpu/tessellate/GrPathShader.h" #include "src/gpu/tessellate/GrTessellationShader.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
class GrPathTessellator; class GrPathTessellator;
@ -46,10 +47,10 @@ private:
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override; GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
// These calls set up the stencil & fill programs we will use prior to preparing and executing. // These calls set up the stencil & fill programs we will use prior to preparing and executing.
void pushFanStencilProgram(const GrPathShader::ProgramArgs&, void pushFanStencilProgram(const GrTessellationShader::ProgramArgs&,
const GrPipeline* pipelineForStencils, const GrUserStencilSettings*); const GrPipeline* pipelineForStencils, const GrUserStencilSettings*);
void pushFanFillProgram(const GrPathShader::ProgramArgs&, const GrUserStencilSettings*); void pushFanFillProgram(const GrTessellationShader::ProgramArgs&, const GrUserStencilSettings*);
void prePreparePrograms(const GrPathShader::ProgramArgs&, GrAppliedClip&&); void prePreparePrograms(const GrTessellationShader::ProgramArgs&, GrAppliedClip&&);
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*, void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags, const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,

View File

@ -10,14 +10,56 @@
#include "src/gpu/GrEagerVertexAllocator.h" #include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/tessellate/GrFillPathShader.h" #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h" #include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/GrPathTessellationShader.h"
#include "src/gpu/tessellate/GrPathTessellator.h" #include "src/gpu/tessellate/GrPathTessellator.h"
#include "src/gpu/tessellate/GrStencilPathShader.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
using OpFlags = GrTessellationPathRenderer::OpFlags; using OpFlags = GrTessellationPathRenderer::OpFlags;
namespace {
// 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 BoundingBoxShader : public GrPathTessellationShader {
public:
BoundingBoxShader(const SkMatrix& viewMatrix, SkPMColor4f color)
: GrPathTessellationShader(kTessellate_BoundingBoxShader_ClassID,
GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
constexpr static Attribute kPathBoundsAttrib = {"pathBounds", kFloat4_GrVertexAttribType,
kFloat4_GrSLType};
this->setInstanceAttributes(&kPathBoundsAttrib, 1);
}
private:
const char* name() const final { return "BoundingBoxShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
};
GrGLSLGeometryProcessor* BoundingBoxShader::createGLSLInstance(const GrShaderCaps&) const {
class Impl : public GrPathTessellationShader::Impl {
void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
v->codeAppend(R"(
// Bloat the bounding box by 1/4px to avoid potential T-junctions at the edges.
float2x2 M_ = inverse(AFFINE_MATRIX);
float2 bloat = float2(abs(M_[0]) + abs(M_[1])) * .25;
// Find the vertex position.
float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
float2 localcoord = mix(pathBounds.xy - bloat, pathBounds.zw + bloat, T);
float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
}
};
return new Impl;
}
} // namespace
void GrPathStencilFillOp::visitProxies(const VisitProxyFunc& fn) const { void GrPathStencilFillOp::visitProxies(const VisitProxyFunc& fn) const {
if (fFillBBoxProgram) { if (fFillBBoxProgram) {
fFillBBoxProgram->pipeline().visitProxies(fn); fFillBBoxProgram->pipeline().visitProxies(fn);
@ -41,7 +83,7 @@ GrProcessorSet::Analysis GrPathStencilFillOp::finalize(const GrCaps& caps,
clampType, &fColor); clampType, &fColor);
} }
void GrPathStencilFillOp::prePreparePrograms(const GrPathShader::ProgramArgs& args, void GrPathStencilFillOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
GrAppliedClip&& appliedClip) { GrAppliedClip&& appliedClip) {
SkASSERT(!fTessellator); SkASSERT(!fTessellator);
SkASSERT(!fStencilFanProgram); SkASSERT(!fStencilFanProgram);
@ -52,41 +94,45 @@ void GrPathStencilFillOp::prePreparePrograms(const GrPathShader::ProgramArgs& ar
return; return;
} }
const GrPipeline* stencilPassPipeline = GrStencilPathShader::MakeStencilPassPipeline( const GrPipeline* stencilPipeline = GrPathTessellationShader::MakeStencilOnlyPipeline(
args, fAAType, fOpFlags, appliedClip.hardClip()); args, fAAType, fOpFlags, appliedClip.hardClip());
const GrUserStencilSettings* stencilPathSettings =
GrPathTessellationShader::StencilPathSettings(fPath.getFillType());
if ((fOpFlags & OpFlags::kPreferWedges) && args.fCaps->shaderCaps()->tessellationSupport()) { if ((fOpFlags & OpFlags::kPreferWedges) && args.fCaps->shaderCaps()->tessellationSupport()) {
// The path is an atlas with relatively small contours, or something else that does best // The path is an atlas with relatively small contours, or something else that does best
// with wedges. // with wedges.
fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix); fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix,
SK_PMColor4fTRANSPARENT);
} else { } else {
auto drawFanWithTessellator = GrPathTessellator::DrawInnerFan::kYes; auto drawFanWithTessellator = GrPathTessellator::DrawInnerFan::kYes;
if (fPath.countVerbs() > 50 && this->bounds().height() * this->bounds().width() > 256*256) { if (fPath.countVerbs() > 50 && this->bounds().height() * this->bounds().width() > 256*256) {
// Large complex paths do better with a dedicated triangle shader for the inner fan. // Large complex paths do better with a dedicated triangle shader for the inner fan.
// This takes less PCI bus bandwidth (6 floats per triangle instead of 8) and allows us // This takes less PCI bus bandwidth (6 floats per triangle instead of 8) and allows us
// to make sure it has an efficient middle-out topology. // to make sure it has an efficient middle-out topology.
fStencilFanProgram = GrStencilPathShader::MakeStencilProgram<GrStencilTriangleShader>( auto shader = args.fArena->make<GrTriangleShader>(fViewMatrix, SK_PMColor4fTRANSPARENT);
args, fViewMatrix, stencilPassPipeline, fPath.getFillType()); fStencilFanProgram = GrTessellationShader::MakeProgram(args, shader, stencilPipeline,
stencilPathSettings);
drawFanWithTessellator = GrPathTessellator::DrawInnerFan::kNo; drawFanWithTessellator = GrPathTessellator::DrawInnerFan::kNo;
} }
fTessellator = GrPathTessellator::Make(args.fArena, fViewMatrix, fPath, fTessellator = GrPathTessellator::Make(args.fArena, fPath, fViewMatrix,
drawFanWithTessellator, *args.fCaps); SK_PMColor4fTRANSPARENT, drawFanWithTessellator,
*args.fCaps);
} }
fStencilPathProgram = GrPathShader::MakeProgram( fStencilPathProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
args, fTessellator->shader(), stencilPassPipeline, stencilPipeline, stencilPathSettings);
GrStencilPathShader::StencilPassSettings(fPath.getFillType()));
if (!(fOpFlags & OpFlags::kStencilOnly)) { if (!(fOpFlags & OpFlags::kStencilOnly)) {
// Create a program that draws a bounding box over the path and fills its stencil coverage // Create a program that draws a bounding box over the path and fills its stencil coverage
// into the color buffer. // into the color buffer.
auto* bboxShader = args.fArena->make<GrFillBoundingBoxShader>(fViewMatrix, fColor, auto* bboxShader = args.fArena->make<BoundingBoxShader>(fViewMatrix, fColor);
fPath.getBounds()); auto* bboxPipeline = GrTessellationShader::MakePipeline(args, fAAType,
auto* bboxPipeline = GrFillPathShader::MakeFillPassPipeline(args, fAAType, std::move(appliedClip),
std::move(appliedClip), std::move(fProcessors));
std::move(fProcessors)); auto* bboxStencil = GrPathTessellationShader::TestAndResetStencilSettings();
auto* bboxStencil = GrFillPathShader::TestAndResetStencilSettings(); fFillBBoxProgram = GrTessellationShader::MakeProgram(args, bboxShader, bboxPipeline,
fFillBBoxProgram = GrPathShader::MakeProgram(args, bboxShader, bboxPipeline, bboxStencil); bboxStencil);
} }
} }

View File

@ -9,8 +9,8 @@
#define GrPathStencilFillOp_DEFINED #define GrPathStencilFillOp_DEFINED
#include "src/gpu/ops/GrDrawOp.h" #include "src/gpu/ops/GrDrawOp.h"
#include "src/gpu/tessellate/GrPathShader.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
#include "src/gpu/tessellate/GrTessellationShader.h"
class GrPathTessellator; class GrPathTessellator;
@ -41,7 +41,7 @@ private:
// Chooses the rendering method we will use and creates the corresponding tessellator and // Chooses the rendering method we will use and creates the corresponding tessellator and
// stencil/fill programs. // stencil/fill programs.
void prePreparePrograms(const GrPathShader::ProgramArgs&, GrAppliedClip&& clip); void prePreparePrograms(const GrTessellationShader::ProgramArgs&, GrAppliedClip&& clip);
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*, void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags, const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,

View File

@ -5,13 +5,47 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "src/gpu/tessellate/GrStencilPathShader.h" #include "src/gpu/tessellate/GrPathTessellationShader.h"
#include "src/gpu/geometry/GrWangsFormula.h" #include "src/gpu/geometry/GrWangsFormula.h"
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h" #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/gpu/glsl/GrGLSLVarying.h" #include "src/gpu/glsl/GrGLSLVarying.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
void GrPathTessellationShader::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
args.fVaryingHandler->emitAttributes(args.fGeomProc);
// Vertex shader.
const char* affineMatrix, *translate;
fAffineMatrixUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
kFloat4_GrSLType, "affineMatrix",
&affineMatrix);
fTranslateUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
kFloat2_GrSLType, "translate", &translate);
args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);", affineMatrix);
args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;", translate);
this->emitVertexCode(args.fVertBuilder, gpArgs);
// Fragment shader.
const char* color;
fColorUniform = args.fUniformHandler->addUniform(nullptr, kFragment_GrShaderFlag,
kHalf4_GrSLType, "color", &color);
args.fFragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, color);
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
}
void GrPathTessellationShader::Impl::setData(const GrGLSLProgramDataManager& pdman, const
GrShaderCaps&, const GrGeometryProcessor& geomProc) {
const auto& shader = geomProc.cast<GrTessellationShader>();
const SkMatrix& m = shader.viewMatrix();
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY());
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
const SkPMColor4f& color = shader.color();
pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
}
constexpr static char kSkSLTypeDefs[] = R"( constexpr static char kSkSLTypeDefs[] = R"(
#define float4x3 mat4x3 #define float4x3 mat4x3
#define float2 vec2 #define float2 vec2
@ -50,55 +84,27 @@ float2 eval_rational_cubic(float4x3 P, float T) {
return abcd.xy / abcd.z; return abcd.xy / abcd.z;
})"; })";
class GrStencilPathShader::Impl : public GrGLSLGeometryProcessor { GrGLSLGeometryProcessor* GrTriangleShader::createGLSLInstance(const GrShaderCaps&) const {
protected: class Impl : public GrPathTessellationShader::Impl {
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
const auto& shader = args.fGeomProc.cast<GrStencilPathShader>(); v->codeAppend(R"(
args.fVaryingHandler->emitAttributes(shader); float2 localcoord = inputPoint;
auto v = args.fVertBuilder; float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
const char* affineMatrix, *translate;
fAffineMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix", &affineMatrix);
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translate);
v->codeAppendf("float2 vertexpos = float2x2(%s) * inputPoint + %s;",
affineMatrix, translate);
if (shader.willUseTessellationShaders()) {
// If y is infinity then x is a conic weight. Don't transform.
v->codeAppendf("vertexpos = (isinf(inputPoint.y)) ? inputPoint : vertexpos;");
}
if (!shader.willUseTessellationShaders()) { // This is the case for the triangle shader.
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos"); gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
} else {
v->declareGlobal(GrShaderVar("P", kFloat2_GrSLType, GrShaderVar::TypeModifier::Out));
v->codeAppendf("P = %s;", "vertexpos");
} }
};
// The fragment shader is normally disabled, but output fully opaque white.
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputColor);
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
}
void setData(const GrGLSLProgramDataManager& pdman,
const GrShaderCaps&,
const GrGeometryProcessor& geomProc) override {
const SkMatrix& m = geomProc.cast<GrStencilPathShader>().viewMatrix();
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY());
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
}
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
};
GrGLSLGeometryProcessor* GrStencilPathShader::createGLSLInstance(const GrShaderCaps&) const {
return new Impl; return new Impl;
} }
GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrShaderCaps&) const { GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrShaderCaps&) const {
class Impl : public GrStencilPathShader::Impl { class Impl : public GrPathTessellationShader::Impl {
void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs*) override {
v->declareGlobal(GrShaderVar("P", kFloat2_GrSLType, GrShaderVar::TypeModifier::Out));
v->codeAppend(R"(
// If y is infinity then x is a conic weight. Don't transform.
P = (isinf(inputPoint.y)) ? inputPoint : AFFINE_MATRIX * inputPoint + TRANSLATE;)");
}
SkString getTessControlShaderGLSL(const GrGeometryProcessor&, SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
const char* versionAndExtensionDecls, const char* versionAndExtensionDecls,
const GrGLSLUniformHandler&, const GrGLSLUniformHandler&,
@ -178,7 +184,6 @@ GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrSha
return code; return code;
} }
SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&, SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
const char* versionAndExtensionDecls, const char* versionAndExtensionDecls,
const GrGLSLUniformHandler&, const GrGLSLUniformHandler&,
@ -226,12 +231,17 @@ GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrSha
return code; return code;
} }
}; };
return new Impl; return new Impl;
} }
GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrShaderCaps&) const { GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrShaderCaps&) const {
class Impl : public GrStencilPathShader::Impl { class Impl : public GrPathTessellationShader::Impl {
void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs*) override {
v->declareGlobal(GrShaderVar("P", kFloat2_GrSLType, GrShaderVar::TypeModifier::Out));
v->codeAppend(R"(
// If y is infinity then x is a conic weight. Don't transform.
P = (isinf(inputPoint.y)) ? inputPoint : AFFINE_MATRIX * inputPoint + TRANSLATE;)");
}
SkString getTessControlShaderGLSL(const GrGeometryProcessor&, SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
const char* versionAndExtensionDecls, const char* versionAndExtensionDecls,
const GrGLSLUniformHandler&, const GrGLSLUniformHandler&,
@ -284,7 +294,6 @@ GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrSha
return code; return code;
} }
SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&, SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
const char* versionAndExtensionDecls, const char* versionAndExtensionDecls,
const GrGLSLUniformHandler&, const GrGLSLUniformHandler&,
@ -328,19 +337,16 @@ GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrSha
return code; return code;
} }
}; };
return new Impl; return new Impl;
} }
class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl { class GrCurveMiddleOutShader::Impl : public GrPathTessellationShader::Impl {
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
const auto& shader = args.fGeomProc.cast<GrCurveMiddleOutShader>(); v->insertFunction(kUnpackRationalCubicFn);
args.fVaryingHandler->emitAttributes(shader); v->insertFunction(kEvalRationalCubicFn);
args.fVertBuilder->insertFunction(kUnpackRationalCubicFn); if (v->getProgramBuilder()->shaderCaps()->bitManipulationSupport()) {
args.fVertBuilder->insertFunction(kEvalRationalCubicFn);
if (args.fShaderCaps->bitManipulationSupport()) {
// Determines the T value at which to place the given vertex in a "middle-out" topology. // Determines the T value at which to place the given vertex in a "middle-out" topology.
args.fVertBuilder->insertFunction(R"( v->insertFunction(R"(
float find_middle_out_T() { float find_middle_out_T() {
int totalTriangleIdx = sk_VertexID/3 + 1; int totalTriangleIdx = sk_VertexID/3 + 1;
int depth = findMSB(totalTriangleIdx); int depth = findMSB(totalTriangleIdx);
@ -351,7 +357,7 @@ class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
})"); })");
} else { } else {
// Determines the T value at which to place the given vertex in a "middle-out" topology. // Determines the T value at which to place the given vertex in a "middle-out" topology.
args.fVertBuilder->insertFunction(R"( v->insertFunction(R"(
float find_middle_out_T() { float find_middle_out_T() {
float totalTriangleIdx = float(sk_VertexID/3) + 1; float totalTriangleIdx = float(sk_VertexID/3) + 1;
float depth = floor(log2(totalTriangleIdx)); float depth = floor(log2(totalTriangleIdx));
@ -361,31 +367,22 @@ class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
return vertexIdxWithinDepth * exp2(-1 - depth); return vertexIdxWithinDepth * exp2(-1 - depth);
})"); })");
} }
args.fVertBuilder->codeAppend(R"( v->codeAppend(R"(
float2 pos; float2 localcoord;
if (isinf(inputPoints_2_3.z)) { if (isinf(inputPoints_2_3.z)) {
// A conic with w=Inf is an exact triangle. // A conic with w=Inf is an exact triangle.
pos = (sk_VertexID < 1) ? inputPoints_0_1.xy localcoord = (sk_VertexID < 1) ? inputPoints_0_1.xy
: (sk_VertexID == 1) ? inputPoints_0_1.zw : (sk_VertexID == 1) ? inputPoints_0_1.zw
: inputPoints_2_3.xy; : inputPoints_2_3.xy;
} else { } else {
float4x3 P = unpack_rational_cubic(inputPoints_0_1.xy, inputPoints_0_1.zw, float4x3 P = unpack_rational_cubic(inputPoints_0_1.xy, inputPoints_0_1.zw,
inputPoints_2_3.xy, inputPoints_2_3.zw); inputPoints_2_3.xy, inputPoints_2_3.zw);
float T = find_middle_out_T(); float T = find_middle_out_T();
pos = eval_rational_cubic(P, T); localcoord = eval_rational_cubic(P, T);
})"); }
const char* affineMatrix, *translate; float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
fAffineMatrixUniform = args.fUniformHandler->addUniform( gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix", &affineMatrix); gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translate);
args.fVertBuilder->codeAppendf(R"(
pos = float2x2(%s) * pos + %s;)", affineMatrix, translate);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos");
// The fragment shader is normally disabled, but output fully opaque white.
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputColor);
args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
} }
}; };

View File

@ -5,43 +5,25 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#ifndef GrStencilPathShader_DEFINED #ifndef GrPathTessellationShader_DEFINED
#define GrStencilPathShader_DEFINED #define GrPathTessellationShader_DEFINED
#include "src/gpu/GrDrawIndirectCommand.h" #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
#include "src/gpu/tessellate/GrPathShader.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
#include "src/gpu/tessellate/GrTessellationShader.h"
// This is the base class for shaders that stencil path elements, namely, triangles, standalone // This is the base class for shaders in the GPU tessellator that fill paths.
// cubics, and wedges. class GrPathTessellationShader : public GrTessellationShader {
class GrStencilPathShader : public GrPathShader {
public: public:
GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType, GrPathTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
int tessellationPatchVertexCount = 0) int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
: GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) { const SkPMColor4f& color)
: GrTessellationShader(classID, primitiveType, tessellationPatchVertexCount, viewMatrix,
color) {
} }
// Creates a pipeline that can be used for normal Redbook stencil draws. // Returns the stencil settings to use for a standard Redbook "stencil" pass.
static const GrPipeline* MakeStencilPassPipeline(const GrPathShader::ProgramArgs& args, static const GrUserStencilSettings* StencilPathSettings(SkPathFillType fillType) {
GrAAType aaType,
GrTessellationPathRenderer::OpFlags opFlags,
const GrAppliedHardClip& hardClip) {
using OpFlags = GrTessellationPathRenderer::OpFlags;
GrPipeline::InitArgs pipelineArgs;
if (aaType != GrAAType::kNone) {
pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
}
if (args.fCaps->wireframeSupport() && (opFlags & OpFlags::kWireframe)) {
pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
}
pipelineArgs.fCaps = args.fCaps;
return args.fArena->make<GrPipeline>(pipelineArgs,
GrDisableColorXPFactory::MakeXferProcessor(),
hardClip);
}
// Returns the stencil settings to use for a standard Redbook stencil draw.
static const GrUserStencilSettings* StencilPassSettings(SkPathFillType fillType) {
// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill. // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
constexpr static GrUserStencilSettings kIncrDecrStencil( constexpr static GrUserStencilSettings kIncrDecrStencil(
GrUserStencilSettings::StaticInitSeparate< GrUserStencilSettings::StaticInitSeparate<
@ -66,69 +48,111 @@ public:
return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil; return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil;
} }
template<typename ShaderType> // Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero
static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix, // stencil values to pass and write a color, and resets the stencil value back to zero; discards
const GrPipeline* pipeline, // immediately on stencil values of zero.
const GrUserStencilSettings* stencil) { static const GrUserStencilSettings* TestAndResetStencilSettings() {
const auto* shader = args.fArena->make<ShaderType>(viewMatrix); constexpr static GrUserStencilSettings kTestAndResetStencil(
return GrPathShader::MakeProgram(args, shader, pipeline, stencil); 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;
} }
template<typename ShaderType> // Creates a pipeline that does not write to the color buffer.
static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix, static const GrPipeline* MakeStencilOnlyPipeline(const ProgramArgs& args, GrAAType aaType,
const GrPipeline* pipeline, GrTessellationPathRenderer::OpFlags opFlags,
const SkPathFillType fillType) { const GrAppliedHardClip& hardClip) {
return MakeStencilProgram<ShaderType>(args, viewMatrix, pipeline, using OpFlags = GrTessellationPathRenderer::OpFlags;
StencilPassSettings(fillType)); GrPipeline::InitArgs pipelineArgs;
if (aaType == GrAAType::kMSAA) {
pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
}
if (args.fCaps->wireframeSupport() && (opFlags & OpFlags::kWireframe)) {
pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
}
pipelineArgs.fCaps = args.fCaps;
return args.fArena->make<GrPipeline>(pipelineArgs,
GrDisableColorXPFactory::MakeXferProcessor(),
hardClip);
} }
protected: protected:
constexpr static Attribute kSinglePointAttrib{"inputPoint", kFloat2_GrVertexAttribType, // Default path tessellation shader implementation that manages a uniform matrix and color.
kFloat2_GrSLType}; class Impl : public GrGLSLGeometryProcessor {
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {} public:
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; void onEmitCode(EmitArgs&, GrGPArgs*) final;
void setData(const GrGLSLProgramDataManager&, const GrShaderCaps&,
const GrGeometryProcessor&) override;
class Impl; protected:
virtual void emitVertexCode(GrGLSLVertexBuilder*, GrGPArgs*) = 0;
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
GrGLSLUniformHandler::UniformHandle fColorUniform;
};
}; };
// Draws simple triangles to the stencil buffer. // Draws a simple array of triangles.
class GrStencilTriangleShader : public GrStencilPathShader { class GrTriangleShader : public GrPathTessellationShader {
public: public:
GrStencilTriangleShader(const SkMatrix& viewMatrix) : GrStencilPathShader( GrTriangleShader(const SkMatrix& viewMatrix, SkPMColor4f color)
kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) { : GrPathTessellationShader(kTessellate_GrTriangleShader_ClassID,
this->setVertexAttributes(&kSinglePointAttrib, 1); GrPrimitiveType::kTriangles, 0, viewMatrix, color) {
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
this->setVertexAttributes(&kInputPointAttrib, 1);
} }
const char* name() const override { return "tessellate_GrStencilTriangleShader"; }
private:
const char* name() const final { return "tessellate_GrTriangleShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
}; };
// Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics. // Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics.
// TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
class GrCurveTessellateShader : public GrStencilPathShader { class GrCurveTessellateShader : public GrPathTessellationShader {
public: public:
GrCurveTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader( GrCurveTessellateShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
kTessellate_GrCurveTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) { : GrPathTessellationShader(kTessellate_GrCurveTessellateShader_ClassID,
this->setVertexAttributes(&kSinglePointAttrib, 1); GrPrimitiveType::kPatches, 4, viewMatrix, color) {
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
this->setVertexAttributes(&kInputPointAttrib, 1);
} }
const char* name() const override { return "tessellate_GrCurveTessellateShader"; }
private: private:
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; const char* name() const final { return "tessellate_GrCurveTessellateShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
}; };
// Uses GPU tessellation shaders to linearize, triangulate, and render cubic "wedge" patches. A // Uses GPU tessellation shaders to linearize, triangulate, and render cubic "wedge" patches. A
// wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning from // wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning from
// the center of the curve's resident contour. // the center of the curve's resident contour.
// TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
class GrWedgeTessellateShader : public GrStencilPathShader { class GrWedgeTessellateShader : public GrPathTessellationShader {
public: public:
GrWedgeTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader( GrWedgeTessellateShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
kTessellate_GrWedgeTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) { : GrPathTessellationShader(kTessellate_GrWedgeTessellateShader_ClassID,
this->setVertexAttributes(&kSinglePointAttrib, 1); GrPrimitiveType::kPatches, 5, viewMatrix, color) {
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
this->setVertexAttributes(&kInputPointAttrib, 1);
} }
const char* name() const override { return "tessellate_GrWedgeTessellateShader"; }
private: private:
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; const char* name() const final { return "tessellate_GrWedgeTessellateShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
}; };
// Uses instanced draws to triangulate standalone closed curves with a "middle-out" topology. // Uses instanced draws to triangulate standalone closed curves with a "middle-out" topology.
@ -142,7 +166,7 @@ private:
// The caller may compute each cubic's resolveLevel on the CPU (i.e., the log2 number of line // The caller may compute each cubic's resolveLevel on the CPU (i.e., the log2 number of line
// segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2/conic_log2), and // segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2/conic_log2), and
// then sort the instance buffer by resolveLevel for efficient batching of indirect draws. // then sort the instance buffer by resolveLevel for efficient batching of indirect draws.
class GrCurveMiddleOutShader : public GrStencilPathShader { class GrCurveMiddleOutShader : public GrPathTessellationShader {
public: public:
// How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel // How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel
// line segments? // line segments?
@ -167,19 +191,19 @@ public:
indirectWriter->write(instanceCount, baseInstance, vertexCount, 0); indirectWriter->write(instanceCount, baseInstance, vertexCount, 0);
} }
GrCurveMiddleOutShader(const SkMatrix& viewMatrix) GrCurveMiddleOutShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
: GrStencilPathShader(kTessellate_GrCurveMiddleOutShader_ClassID, viewMatrix, : GrPathTessellationShader(kTessellate_GrCurveMiddleOutShader_ClassID,
GrPrimitiveType::kTriangles) { GrPrimitiveType::kTriangles, 0, viewMatrix, color) {
constexpr static Attribute kInputPtsAttribs[] = { constexpr static Attribute kInputPtsAttribs[] = {
{"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, {"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
{"inputPoints_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; {"inputPoints_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
this->setInstanceAttributes(kInputPtsAttribs, 2); this->setInstanceAttributes(kInputPtsAttribs, 2);
} }
const char* name() const override { return "tessellate_GrCurveMiddleOutShader"; }
private: private:
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; const char* name() const final { return "tessellate_GrCurveMiddleOutShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
class Impl; class Impl;
}; };

View File

@ -14,7 +14,7 @@
#include "src/gpu/tessellate/GrCullTest.h" #include "src/gpu/tessellate/GrCullTest.h"
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h" #include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/GrMidpointContourParser.h" #include "src/gpu/tessellate/GrMidpointContourParser.h"
#include "src/gpu/tessellate/GrStencilPathShader.h" #include "src/gpu/tessellate/GrPathTessellationShader.h"
constexpr static float kPrecision = GrTessellationPathRenderer::kLinearizationPrecision; constexpr static float kPrecision = GrTessellationPathRenderer::kLinearizationPrecision;
@ -27,27 +27,29 @@ static bool can_use_hardware_tessellation(const SkPath& path, const GrCaps& caps
return path.countVerbs() >= caps.minPathVerbsForHwTessellation(); return path.countVerbs() >= caps.minPathVerbsForHwTessellation();
} }
GrPathTessellator* GrPathTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix, GrPathTessellator* GrPathTessellator::Make(SkArenaAlloc* arena, const SkPath& path,
const SkPath& path, DrawInnerFan drawInnerFan, const SkMatrix& viewMatrix, const SkPMColor4f& color,
const GrCaps& caps) { DrawInnerFan drawInnerFan, const GrCaps& caps) {
if (can_use_hardware_tessellation(path, caps)) { if (can_use_hardware_tessellation(path, caps)) {
if (drawInnerFan == DrawInnerFan::kNo) { if (drawInnerFan == DrawInnerFan::kNo) {
return GrPathOuterCurveTessellator::Make(arena, viewMatrix, drawInnerFan); return GrPathOuterCurveTessellator::Make(arena, viewMatrix, color, drawInnerFan);
} else { } else {
return GrPathWedgeTessellator::Make(arena, viewMatrix); return GrPathWedgeTessellator::Make(arena, viewMatrix, color);
} }
} else { } else {
return GrPathIndirectTessellator::Make(arena, viewMatrix, path, drawInnerFan); return GrPathIndirectTessellator::Make(arena, path, viewMatrix, color, drawInnerFan);
} }
} }
GrPathTessellator* GrPathIndirectTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix, GrPathTessellator* GrPathIndirectTessellator::Make(SkArenaAlloc* arena, const SkPath& path,
const SkPath& path, DrawInnerFan drawInnerFan) { const SkMatrix& viewMatrix,
auto shader = arena->make<GrCurveMiddleOutShader>(viewMatrix); const SkPMColor4f& color,
DrawInnerFan drawInnerFan) {
auto shader = arena->make<GrCurveMiddleOutShader>(viewMatrix, color);
return arena->make<GrPathIndirectTessellator>(shader, path, drawInnerFan); return arena->make<GrPathIndirectTessellator>(shader, path, drawInnerFan);
} }
GrPathIndirectTessellator::GrPathIndirectTessellator(GrStencilPathShader* shader, GrPathIndirectTessellator::GrPathIndirectTessellator(GrPathTessellationShader* shader,
const SkPath& path, DrawInnerFan drawInnerFan) const SkPath& path, DrawInnerFan drawInnerFan)
: GrPathTessellator(shader) : GrPathTessellator(shader)
, fDrawInnerFan(drawInnerFan != DrawInnerFan::kNo) { , fDrawInnerFan(drawInnerFan != DrawInnerFan::kNo) {
@ -243,7 +245,7 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkRe
instanceLocations[level].writeArray(pts, 4); instanceLocations[level].writeArray(pts, 4);
break; break;
case SkPathVerb::kConic: case SkPathVerb::kConic:
GrPathShader::WriteConicPatch(pts, *w, &instanceLocations[level]); GrTessellationShader::WriteConicPatch(pts, *w, &instanceLocations[level]);
break; break;
default: default:
SkUNREACHABLE; SkUNREACHABLE;
@ -279,8 +281,9 @@ void GrPathIndirectTessellator::drawHullInstances(GrOpFlushState* flushState) co
GrPathTessellator* GrPathOuterCurveTessellator::Make(SkArenaAlloc* arena, GrPathTessellator* GrPathOuterCurveTessellator::Make(SkArenaAlloc* arena,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
const SkPMColor4f& color,
DrawInnerFan drawInnerFan) { DrawInnerFan drawInnerFan) {
auto shader = arena->make<GrCurveTessellateShader>(viewMatrix); auto shader = arena->make<GrCurveTessellateShader>(viewMatrix, color);
return arena->make<GrPathOuterCurveTessellator>(shader, drawInnerFan); return arena->make<GrPathOuterCurveTessellator>(shader, drawInnerFan);
} }
@ -359,7 +362,7 @@ void GrPathOuterCurveTessellator::prepare(GrMeshDrawOp::Target* target, const Sk
return; return;
} }
if (GrVertexWriter vertexWriter = chunker->appendVertex()) { if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
GrPathShader::WriteConicPatch(p, w, &vertexWriter); GrTessellationShader::WriteConicPatch(p, w, &vertexWriter);
} }
} }
@ -446,8 +449,9 @@ void GrPathOuterCurveTessellator::prepare(GrMeshDrawOp::Target* target, const Sk
} }
} }
GrPathTessellator* GrPathWedgeTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix) { GrPathTessellator* GrPathWedgeTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix,
auto shader = arena->make<GrWedgeTessellateShader>(viewMatrix); const SkPMColor4f& color) {
auto shader = arena->make<GrWedgeTessellateShader>(viewMatrix, color);
return arena->make<GrPathWedgeTessellator>(shader); return arena->make<GrPathWedgeTessellator>(shader);
} }
@ -506,7 +510,7 @@ void GrPathWedgeTessellator::prepare(GrMeshDrawOp::Target* target, const SkRect&
return; return;
} }
if (GrVertexWriter vertexWriter = chunker->appendVertex()) { if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
GrPathShader::WriteConicPatch(p, w, &vertexWriter); GrTessellationShader::WriteConicPatch(p, w, &vertexWriter);
vertexWriter.write(midpoint); vertexWriter.write(midpoint);
} }
} }

View File

@ -14,7 +14,7 @@
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
class SkPath; class SkPath;
class GrStencilPathShader; class GrPathTessellationShader;
// Prepares GPU data for, and then draws a path's tessellated geometry. Depending on the subclass, // Prepares GPU data for, and then draws a path's tessellated geometry. Depending on the subclass,
// the caller may or may not be required to draw the path's inner fan separately. // the caller may or may not be required to draw the path's inner fan separately.
@ -30,10 +30,10 @@ public:
}; };
// Creates the tessellator best suited to draw the given path. // Creates the tessellator best suited to draw the given path.
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, const SkPath&, DrawInnerFan, static GrPathTessellator* Make(SkArenaAlloc*, const SkPath&, const SkMatrix&,
const GrCaps&); const SkPMColor4f&, DrawInnerFan, const GrCaps&);
const GrStencilPathShader* shader() const { return fShader; } const GrPathTessellationShader* shader() const { return fShader; }
// Called before draw(). Prepares GPU buffers containing the geometry to tessellate. If the // Called before draw(). Prepares GPU buffers containing the geometry to tessellate. If the
// given BreadcrumbTriangleList is non-null, then this class will also include the breadcrumb // given BreadcrumbTriangleList is non-null, then this class will also include the breadcrumb
@ -53,9 +53,9 @@ public:
virtual ~GrPathTessellator() {} virtual ~GrPathTessellator() {}
protected: protected:
GrPathTessellator(GrStencilPathShader* shader) : fShader(shader) {} GrPathTessellator(GrPathTessellationShader* shader) : fShader(shader) {}
GrStencilPathShader* fShader; GrPathTessellationShader* fShader;
}; };
// Draws tessellations of the path's outer curves and, optionally, inner fan triangles using // Draws tessellations of the path's outer curves and, optionally, inner fan triangles using
@ -64,7 +64,8 @@ protected:
// cubic or a conic. // cubic or a conic.
class GrPathIndirectTessellator final : public GrPathTessellator { class GrPathIndirectTessellator final : public GrPathTessellator {
public: public:
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, const SkPath&, DrawInnerFan); static GrPathTessellator* Make(SkArenaAlloc*, const SkPath&, const SkMatrix&,
const SkPMColor4f&, DrawInnerFan);
void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&, void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&,
const BreadcrumbTriangleList*) override; const BreadcrumbTriangleList*) override;
@ -74,7 +75,7 @@ public:
private: private:
constexpr static int kMaxResolveLevel = GrTessellationPathRenderer::kMaxResolveLevel; constexpr static int kMaxResolveLevel = GrTessellationPathRenderer::kMaxResolveLevel;
GrPathIndirectTessellator(GrStencilPathShader*, const SkPath&, DrawInnerFan); GrPathIndirectTessellator(GrPathTessellationShader*, const SkPath&, DrawInnerFan);
const bool fDrawInnerFan; const bool fDrawInnerFan;
int fResolveLevelCounts[kMaxResolveLevel + 1] = {0}; int fResolveLevelCounts[kMaxResolveLevel + 1] = {0};
@ -97,7 +98,7 @@ public:
void draw(GrOpFlushState*) const final; void draw(GrOpFlushState*) const final;
protected: protected:
GrPathHardwareTessellator(GrStencilPathShader* shader, int numVerticesPerPatch) GrPathHardwareTessellator(GrPathTessellationShader* shader, int numVerticesPerPatch)
: GrPathTessellator(shader), fNumVerticesPerPatch(numVerticesPerPatch) {} : GrPathTessellator(shader), fNumVerticesPerPatch(numVerticesPerPatch) {}
GrVertexChunkArray fVertexChunkArray; GrVertexChunkArray fVertexChunkArray;
@ -109,14 +110,15 @@ protected:
// or a conic. Quadratics are converted to cubics and triangles are converted to conics with w=Inf. // or a conic. Quadratics are converted to cubics and triangles are converted to conics with w=Inf.
class GrPathOuterCurveTessellator final : public GrPathHardwareTessellator { class GrPathOuterCurveTessellator final : public GrPathHardwareTessellator {
public: public:
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, DrawInnerFan drawInnerFan); static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, const SkPMColor4f&,
DrawInnerFan);
void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&, void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&,
const BreadcrumbTriangleList*) override; const BreadcrumbTriangleList*) override;
void drawHullInstances(GrOpFlushState*) const override; void drawHullInstances(GrOpFlushState*) const override;
private: private:
GrPathOuterCurveTessellator(GrStencilPathShader* shader, DrawInnerFan drawInnerFan) GrPathOuterCurveTessellator(GrPathTessellationShader* shader, DrawInnerFan drawInnerFan)
: GrPathHardwareTessellator(shader, 4) : GrPathHardwareTessellator(shader, 4)
, fDrawInnerFan(drawInnerFan == DrawInnerFan::kYes) {} , fDrawInnerFan(drawInnerFan == DrawInnerFan::kYes) {}
@ -131,13 +133,14 @@ private:
// converted to cubics. Once stencilled, these wedges alone define the complete path. // converted to cubics. Once stencilled, these wedges alone define the complete path.
class GrPathWedgeTessellator final : public GrPathHardwareTessellator { class GrPathWedgeTessellator final : public GrPathHardwareTessellator {
public: public:
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&); static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, const SkPMColor4f&);
void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&, void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&,
const BreadcrumbTriangleList*) override; const BreadcrumbTriangleList*) override;
private: private:
GrPathWedgeTessellator(GrStencilPathShader* shader) : GrPathHardwareTessellator(shader, 5) {} GrPathWedgeTessellator(GrPathTessellationShader* shader)
: GrPathHardwareTessellator(shader, 5) {}
friend class SkArenaAlloc; // For constructor. friend class SkArenaAlloc; // For constructor.
}; };

View File

@ -84,7 +84,7 @@ public:
return; return;
} }
SkPoint conic[4]; SkPoint conic[4];
GrPathShader::WriteConicPatch(p, w, conic); GrTessellationShader::WriteConicPatch(p, w, conic);
SkPoint endControlPoint = conic[1]; SkPoint endControlPoint = conic[1];
this->writeStroke(conic, endControlPoint); this->writeStroke(conic, endControlPoint);
fMaxParametricSegments_pow4 = std::max(numParametricSegments_pow4, fMaxParametricSegments_pow4 = std::max(numParametricSegments_pow4,

View File

@ -369,7 +369,7 @@ private:
if (w == 1) { if (w == 1) {
GrPathUtils::convertQuadToCubic(p, asPatch); GrPathUtils::convertQuadToCubic(p, asPatch);
} else { } else {
GrPathShader::WriteConicPatch(p, w, asPatch); GrTessellationShader::WriteConicPatch(p, w, asPatch);
} }
float numParametricSegments_pow4 = GrWangsFormula::quadratic_pow4(fParametricPrecision, p); float numParametricSegments_pow4 = GrWangsFormula::quadratic_pow4(fParametricPrecision, p);
@ -835,7 +835,7 @@ void GrStrokeHardwareTessellator::prepare(GrMeshDrawOp::Target* target, int tota
// case. Write it out directly. // case. Write it out directly.
prevJoinFitsInPatch = patchWriter.stroke180FitsInPatch_withJoin( prevJoinFitsInPatch = patchWriter.stroke180FitsInPatch_withJoin(
numParametricSegments_pow4); numParametricSegments_pow4);
GrPathShader::WriteConicPatch(p, *w, scratchPts); GrTessellationShader::WriteConicPatch(p, *w, scratchPts);
patchPts = scratchPts; patchPts = scratchPts;
endControlPoint = p[1]; endControlPoint = p[1];
break; break;

View File

@ -890,7 +890,7 @@ void GrStrokeIndirectTessellator::writeBuffers(GrDrawIndirectWriter* indirectWri
binningWriter.writeCircle(cuspResolveLevel, cusp); binningWriter.writeCircle(cuspResolveLevel, cusp);
resolveLevel = (isRoundJoin) ? *nextResolveLevel++ : 0; resolveLevel = (isRoundJoin) ? *nextResolveLevel++ : 0;
} else { } else {
GrPathShader::WriteConicPatch(pts, iter.w(), scratch); GrTessellationShader::WriteConicPatch(pts, iter.w(), scratch);
} }
pts_ = scratch; pts_ = scratch;
break; break;

View File

@ -8,7 +8,7 @@
#ifndef GrStrokeShader_DEFINED #ifndef GrStrokeShader_DEFINED
#define GrStrokeShader_DEFINED #define GrStrokeShader_DEFINED
#include "src/gpu/tessellate/GrPathShader.h" #include "src/gpu/tessellate/GrTessellationShader.h"
#include "include/core/SkStrokeRec.h" #include "include/core/SkStrokeRec.h"
#include "src/gpu/GrVx.h" #include "src/gpu/GrVx.h"
@ -23,7 +23,7 @@
// divide the curve's _rotation_ into even steps. The tessellation shader evaluates both sets of // divide the curve's _rotation_ into even steps. The tessellation shader evaluates both sets of
// edges and sorts them into a single quad strip. With this combined set of edges we can stroke any // edges and sorts them into a single quad strip. With this combined set of edges we can stroke any
// curve, regardless of curvature. // curve, regardless of curvature.
class GrStrokeShader : public GrPathShader { class GrStrokeShader : public GrTessellationShader {
public: public:
// Are we using hardware tessellation or indirect draws? // Are we using hardware tessellation or indirect draws?
enum class Mode : int8_t { enum class Mode : int8_t {
@ -98,17 +98,17 @@ public:
}; };
// 'viewMatrix' is applied to the geometry post tessellation. It cannot have perspective. // 'viewMatrix' is applied to the geometry post tessellation. It cannot have perspective.
GrStrokeShader(Mode mode, ShaderFlags shaderFlags, int8_t maxParametricSegments_log2, GrStrokeShader(Mode mode, ShaderFlags shaderFlags, const SkMatrix& viewMatrix,
const SkMatrix& viewMatrix, const SkStrokeRec& stroke, SkPMColor4f color) const SkStrokeRec& stroke, SkPMColor4f color, int8_t maxParametricSegments_log2)
: GrPathShader(kTessellate_GrStrokeShader_ClassID, viewMatrix, : GrTessellationShader(kTessellate_GrStrokeShader_ClassID,
(mode == Mode::kHardwareTessellation) ? (mode == Mode::kHardwareTessellation)
GrPrimitiveType::kPatches : GrPrimitiveType::kTriangleStrip, ? GrPrimitiveType::kPatches
(mode == Mode::kHardwareTessellation) ? 1 : 0) : GrPrimitiveType::kTriangleStrip,
(mode == Mode::kHardwareTessellation) ? 1 : 0, viewMatrix, color)
, fMode(mode) , fMode(mode)
, fShaderFlags(shaderFlags) , fShaderFlags(shaderFlags)
, fMaxParametricSegments_log2(maxParametricSegments_log2)
, fStroke(stroke) , fStroke(stroke)
, fColor(color) { , fMaxParametricSegments_log2(maxParametricSegments_log2) {
if (fMode == Mode::kHardwareTessellation) { if (fMode == Mode::kHardwareTessellation) {
// A join calculates its starting angle using prevCtrlPtAttr. // A join calculates its starting angle using prevCtrlPtAttr.
fAttribs.emplace_back("prevCtrlPtAttr", kFloat2_GrVertexAttribType, kFloat2_GrSLType); fAttribs.emplace_back("prevCtrlPtAttr", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
@ -168,11 +168,10 @@ public:
Mode mode() const { return fMode; } Mode mode() const { return fMode; }
ShaderFlags flags() const { return fShaderFlags; } ShaderFlags flags() const { return fShaderFlags; }
int8_t maxParametricSegments_log2() const { return fMaxParametricSegments_log2; }
bool hasDynamicStroke() const { return fShaderFlags & ShaderFlags::kDynamicStroke; } bool hasDynamicStroke() const { return fShaderFlags & ShaderFlags::kDynamicStroke; }
bool hasDynamicColor() const { return fShaderFlags & ShaderFlags::kDynamicColor; } bool hasDynamicColor() const { return fShaderFlags & ShaderFlags::kDynamicColor; }
const SkStrokeRec& stroke() const { return fStroke;} const SkStrokeRec& stroke() const { return fStroke;}
const SkPMColor4f& color() const { return fColor;} int8_t maxParametricSegments_log2() const { return fMaxParametricSegments_log2; }
float fixedCountNumTotalEdges() const { return fFixedCountNumTotalEdges;} float fixedCountNumTotalEdges() const { return fFixedCountNumTotalEdges;}
// Used by GrFixedCountTessellator to configure the uniform value that tells the shader how many // Used by GrFixedCountTessellator to configure the uniform value that tells the shader how many
@ -189,9 +188,8 @@ private:
const Mode fMode; const Mode fMode;
const ShaderFlags fShaderFlags; const ShaderFlags fShaderFlags;
const int8_t fMaxParametricSegments_log2;
const SkStrokeRec fStroke; const SkStrokeRec fStroke;
const SkPMColor4f fColor; const int8_t fMaxParametricSegments_log2;
constexpr static int kMaxAttribCount = 5; constexpr static int kMaxAttribCount = 5;
SkSTArray<kMaxAttribCount, Attribute> fAttribs; SkSTArray<kMaxAttribCount, Attribute> fAttribs;

View File

@ -9,11 +9,10 @@
#include "src/core/SkPathPriv.h" #include "src/core/SkPathPriv.h"
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/tessellate/GrFillPathShader.h"
#include "src/gpu/tessellate/GrStencilPathShader.h"
#include "src/gpu/tessellate/GrStrokeFixedCountTessellator.h" #include "src/gpu/tessellate/GrStrokeFixedCountTessellator.h"
#include "src/gpu/tessellate/GrStrokeHardwareTessellator.h" #include "src/gpu/tessellate/GrStrokeHardwareTessellator.h"
#include "src/gpu/tessellate/GrStrokeIndirectTessellator.h" #include "src/gpu/tessellate/GrStrokeIndirectTessellator.h"
#include "src/gpu/tessellate/GrTessellationShader.h"
using DynamicStroke = GrStrokeShader::DynamicStroke; using DynamicStroke = GrStrokeShader::DynamicStroke;
@ -164,7 +163,7 @@ bool GrStrokeTessellateOp::canUseHardwareTessellation(int numVerbs, const GrCaps
return numVerbs >= caps.minStrokeVerbsForHwTessellation(); return numVerbs >= caps.minStrokeVerbsForHwTessellation();
} }
void GrStrokeTessellateOp::prePrepareTessellator(GrPathShader::ProgramArgs&& args, void GrStrokeTessellateOp::prePrepareTessellator(GrTessellationShader::ProgramArgs&& args,
GrAppliedClip&& clip) { GrAppliedClip&& clip) {
SkASSERT(!fTessellator); SkASSERT(!fTessellator);
SkASSERT(!fFillProgram); SkASSERT(!fFillProgram);
@ -212,17 +211,18 @@ void GrStrokeTessellateOp::prePrepareTessellator(GrPathShader::ProgramArgs&& arg
strokeCullBounds); strokeCullBounds);
} }
auto* pipeline = GrFillPathShader::MakeFillPassPipeline(args, fAAType, std::move(clip), auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(clip),
std::move(fProcessors)); std::move(fProcessors));
auto fillStencil = &GrUserStencilSettings::kUnused; auto fillStencil = &GrUserStencilSettings::kUnused;
if (fNeedsStencil) { if (fNeedsStencil) {
fStencilProgram = GrPathShader::MakeProgram(args, fTessellator->shader(), pipeline, fStencilProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(), pipeline,
&kMarkStencil); &kMarkStencil);
fillStencil = &kTestAndResetStencil; fillStencil = &kTestAndResetStencil;
args.fXferBarrierFlags = GrXferBarrierFlags::kNone; args.fXferBarrierFlags = GrXferBarrierFlags::kNone;
} }
fFillProgram = GrPathShader::MakeProgram(args, fTessellator->shader(), pipeline, fillStencil); fFillProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(), pipeline,
fillStencil);
} }
void GrStrokeTessellateOp::onPrePrepare(GrRecordingContext* context, void GrStrokeTessellateOp::onPrePrepare(GrRecordingContext* context,

View File

@ -10,8 +10,8 @@
#include "include/core/SkStrokeRec.h" #include "include/core/SkStrokeRec.h"
#include "src/gpu/ops/GrMeshDrawOp.h" #include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/tessellate/GrPathShader.h"
#include "src/gpu/tessellate/GrStrokeTessellator.h" #include "src/gpu/tessellate/GrStrokeTessellator.h"
#include "src/gpu/tessellate/GrTessellationShader.h"
class GrRecordingContext; class GrRecordingContext;
@ -55,7 +55,7 @@ private:
CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override; CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
// Creates the tessellator and the stencil/fill program(s) we will use with it. // Creates the tessellator and the stencil/fill program(s) we will use with it.
void prePrepareTessellator(GrPathShader::ProgramArgs&&, GrAppliedClip&&); void prePrepareTessellator(GrTessellationShader::ProgramArgs&&, GrAppliedClip&&);
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*, void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags, const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,

View File

@ -29,14 +29,14 @@ public:
int8_t maxParametricSegments_log2, const SkMatrix& viewMatrix, int8_t maxParametricSegments_log2, const SkMatrix& viewMatrix,
PathStrokeList* pathStrokeList, std::array<float,2> matrixMinMaxScales, PathStrokeList* pathStrokeList, std::array<float,2> matrixMinMaxScales,
const SkRect& strokeCullBounds) const SkRect& strokeCullBounds)
: fShader(shaderMode, shaderFlags, maxParametricSegments_log2, viewMatrix, : fShader(shaderMode, shaderFlags, viewMatrix, pathStrokeList->fStroke,
pathStrokeList->fStroke, pathStrokeList->fColor) pathStrokeList->fColor, maxParametricSegments_log2)
, fPathStrokeList(pathStrokeList) , fPathStrokeList(pathStrokeList)
, fMatrixMinMaxScales(matrixMinMaxScales) , fMatrixMinMaxScales(matrixMinMaxScales)
, fStrokeCullBounds(strokeCullBounds) { , fStrokeCullBounds(strokeCullBounds) {
} }
const GrPathShader* shader() const { return &fShader; } const GrTessellationShader* shader() const { return &fShader; }
// Called before draw(). Prepares GPU buffers containing the geometry to tessellate. // Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
virtual void prepare(GrMeshDrawOp::Target*, int totalCombinedVerbCnt) = 0; virtual void prepare(GrMeshDrawOp::Target*, int totalCombinedVerbCnt) = 0;

View File

@ -5,26 +5,27 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#ifndef GrPathShader_DEFINED #ifndef GrTessellationShader_DEFINED
#define GrPathShader_DEFINED #define GrTessellationShader_DEFINED
#include "src/core/SkArenaAlloc.h"
#include "src/gpu/GrGeometryProcessor.h" #include "src/gpu/GrGeometryProcessor.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrOpsRenderPass.h"
#include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrVertexWriter.h" #include "src/gpu/GrVertexWriter.h"
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h" #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
class SkArenaAlloc;
// This is a common base class for shaders in the GPU tessellator. // This is a common base class for shaders in the GPU tessellator.
class GrPathShader : public GrGeometryProcessor { class GrTessellationShader : public GrGeometryProcessor {
public: public:
GrPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType, GrTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
int tessellationPatchVertexCount) int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
const SkPMColor4f& color)
: GrGeometryProcessor(classID) : GrGeometryProcessor(classID)
, fViewMatrix(viewMatrix)
, fPrimitiveType(primitiveType) , fPrimitiveType(primitiveType)
, fTessellationPatchVertexCount(tessellationPatchVertexCount) { , fTessellationPatchVertexCount(tessellationPatchVertexCount)
, fViewMatrix(viewMatrix)
, fColor(color) {
if (fTessellationPatchVertexCount) { if (fTessellationPatchVertexCount) {
this->setWillUseTessellationShaders(); this->setWillUseTessellationShaders();
} }
@ -33,24 +34,7 @@ public:
GrPrimitiveType primitiveType() const { return fPrimitiveType; } GrPrimitiveType primitiveType() const { return fPrimitiveType; }
int tessellationPatchVertexCount() const { return fTessellationPatchVertexCount; } int tessellationPatchVertexCount() const { return fTessellationPatchVertexCount; }
const SkMatrix& viewMatrix() const { return fViewMatrix; } const SkMatrix& viewMatrix() const { return fViewMatrix; }
const SkPMColor4f& color() const { return fColor;}
struct ProgramArgs {
SkArenaAlloc* fArena;
const GrSurfaceProxyView& fWriteView;
const GrXferProcessor::DstProxyView* fDstProxyView;
GrXferBarrierFlags fXferBarrierFlags;
GrLoadOp fColorLoadOp;
const GrCaps* fCaps;
};
static GrProgramInfo* MakeProgram(const ProgramArgs& args, const GrPathShader* shader,
const GrPipeline* pipeline,
const GrUserStencilSettings* stencil) {
return args.fArena->make<GrProgramInfo>(args.fWriteView, pipeline, stencil, shader,
shader->fPrimitiveType,
shader->fTessellationPatchVertexCount,
args.fXferBarrierFlags, args.fColorLoadOp);
}
// Fills in a 4-point patch in such a way that the shader will recognize it as a conic. // Fills in a 4-point patch in such a way that the shader will recognize it as a conic.
static void WriteConicPatch(const SkPoint pts[3], float w, GrVertexWriter* writer) { static void WriteConicPatch(const SkPoint pts[3], float w, GrVertexWriter* writer) {
@ -64,12 +48,41 @@ public:
WriteConicPatch(pts, w, &writer); WriteConicPatch(pts, w, &writer);
} }
struct ProgramArgs {
SkArenaAlloc* fArena;
const GrSurfaceProxyView& fWriteView;
const GrXferProcessor::DstProxyView* fDstProxyView;
GrXferBarrierFlags fXferBarrierFlags;
GrLoadOp fColorLoadOp;
const GrCaps* fCaps;
};
static const GrPipeline* MakePipeline(const ProgramArgs& args, GrAAType aaType,
GrAppliedClip&& appliedClip,
GrProcessorSet&& processors) {
auto pipelineFlags = GrPipeline::InputFlags::kNone;
if (aaType == GrAAType::kMSAA) {
pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
}
return GrSimpleMeshDrawOpHelper::CreatePipeline(
args.fCaps, args.fArena, args.fWriteView.swizzle(), std::move(appliedClip),
*args.fDstProxyView, std::move(processors), pipelineFlags);
}
static GrProgramInfo* MakeProgram(const ProgramArgs& args, const GrTessellationShader* shader,
const GrPipeline* pipeline,
const GrUserStencilSettings* stencil) {
return args.fArena->make<GrProgramInfo>(args.fWriteView, pipeline, stencil, shader,
shader->fPrimitiveType,
shader->fTessellationPatchVertexCount,
args.fXferBarrierFlags, args.fColorLoadOp);
}
private: private:
const SkMatrix fViewMatrix;
const GrPrimitiveType fPrimitiveType; const GrPrimitiveType fPrimitiveType;
const int fTessellationPatchVertexCount; const int fTessellationPatchVertexCount;
const SkMatrix fViewMatrix;
class Impl; const SkPMColor4f fColor;
}; };
#endif #endif