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:
parent
8f73edeaf6
commit
2f733ec2dd
@ -113,21 +113,21 @@ protected:
|
||||
|
||||
DEF_PATH_TESS_BENCH(GrPathIndirectTessellator, make_cubic_path(18), SkMatrix::I()) {
|
||||
SkArenaAlloc arena(1024);
|
||||
auto tess = GrPathIndirectTessellator::Make(&arena, fMatrix, fPath,
|
||||
auto tess = GrPathIndirectTessellator::Make(&arena, fPath, fMatrix, SK_PMColor4fTRANSPARENT,
|
||||
GrPathIndirectTessellator::DrawInnerFan::kNo);
|
||||
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr);
|
||||
}
|
||||
|
||||
DEF_PATH_TESS_BENCH(GrPathOuterCurveTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
SkArenaAlloc arena(1024);
|
||||
auto tess = GrPathOuterCurveTessellator::Make(&arena, fMatrix,
|
||||
auto tess = GrPathOuterCurveTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT,
|
||||
GrPathTessellator::DrawInnerFan::kNo);
|
||||
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), fPath, nullptr);
|
||||
}
|
||||
|
||||
DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -452,19 +452,16 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/tessellate/GrCullTest.h",
|
||||
"$_src/gpu/tessellate/GrDrawAtlasPathOp.cpp",
|
||||
"$_src/gpu/tessellate/GrDrawAtlasPathOp.h",
|
||||
"$_src/gpu/tessellate/GrFillPathShader.cpp",
|
||||
"$_src/gpu/tessellate/GrFillPathShader.h",
|
||||
"$_src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h",
|
||||
"$_src/gpu/tessellate/GrMidpointContourParser.h",
|
||||
"$_src/gpu/tessellate/GrPathInnerTriangulateOp.cpp",
|
||||
"$_src/gpu/tessellate/GrPathInnerTriangulateOp.h",
|
||||
"$_src/gpu/tessellate/GrPathShader.h",
|
||||
"$_src/gpu/tessellate/GrPathStencilFillOp.cpp",
|
||||
"$_src/gpu/tessellate/GrPathStencilFillOp.h",
|
||||
"$_src/gpu/tessellate/GrPathTessellationShader.cpp",
|
||||
"$_src/gpu/tessellate/GrPathTessellationShader.h",
|
||||
"$_src/gpu/tessellate/GrPathTessellator.cpp",
|
||||
"$_src/gpu/tessellate/GrPathTessellator.h",
|
||||
"$_src/gpu/tessellate/GrStencilPathShader.cpp",
|
||||
"$_src/gpu/tessellate/GrStencilPathShader.h",
|
||||
"$_src/gpu/tessellate/GrStrokeFixedCountTessellator.cpp",
|
||||
"$_src/gpu/tessellate/GrStrokeFixedCountTessellator.h",
|
||||
"$_src/gpu/tessellate/GrStrokeHardwareTessellator.cpp",
|
||||
@ -483,6 +480,7 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/tessellate/GrStrokeTessellator.h",
|
||||
"$_src/gpu/tessellate/GrTessellationPathRenderer.cpp",
|
||||
"$_src/gpu/tessellate/GrTessellationPathRenderer.h",
|
||||
"$_src/gpu/tessellate/GrTessellationShader.h",
|
||||
"$_src/gpu/tessellate/GrVectorXform.h",
|
||||
|
||||
# text
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/GrSurfaceDrawContext.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellationShader.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellator.h"
|
||||
#include "src/gpu/tessellate/GrStencilPathShader.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -66,28 +66,30 @@ private:
|
||||
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
|
||||
GrLoadOp colorLoadOp) override {}
|
||||
void onPrepare(GrOpFlushState* flushState) override {
|
||||
constexpr static SkPMColor4f kCyan = {0,1,1,1};
|
||||
auto alloc = flushState->allocator();
|
||||
switch (fMode) {
|
||||
case Mode::kCurveMiddleOut:
|
||||
fTessellator = GrPathIndirectTessellator::Make(
|
||||
alloc, fMatrix, fPath, GrPathTessellator::DrawInnerFan::kYes);
|
||||
alloc, fPath, fMatrix, kCyan, GrPathTessellator::DrawInnerFan::kYes);
|
||||
break;
|
||||
case Mode::kWedgeTessellate:
|
||||
fTessellator = GrPathWedgeTessellator::Make(alloc, fMatrix);
|
||||
fTessellator = GrPathWedgeTessellator::Make(alloc, fMatrix, kCyan);
|
||||
break;
|
||||
case Mode::kCurveTessellate:
|
||||
fTessellator = GrPathOuterCurveTessellator::Make(
|
||||
alloc, fMatrix, GrPathTessellator::DrawInnerFan::kYes);
|
||||
alloc, fMatrix, kCyan, GrPathTessellator::DrawInnerFan::kYes);
|
||||
break;
|
||||
}
|
||||
fTessellator->prepare(flushState, this->bounds(), fPath);
|
||||
auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
|
||||
fPipelineFlags);
|
||||
fProgram = GrPathShader::MakeProgram({alloc, flushState->writeView(),
|
||||
&flushState->dstProxyView(),
|
||||
flushState->renderPassBarriers(), GrLoadOp::kClear,
|
||||
&flushState->caps()}, fTessellator->shader(), pipeline,
|
||||
&GrUserStencilSettings::kUnused);
|
||||
fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
|
||||
&flushState->dstProxyView(),
|
||||
flushState->renderPassBarriers(),
|
||||
GrLoadOp::kClear, &flushState->caps()},
|
||||
fTessellator->shader(), pipeline,
|
||||
&GrUserStencilSettings::kUnused);
|
||||
}
|
||||
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
|
||||
flushState->bindPipeline(*fProgram, chainBounds);
|
||||
|
@ -128,14 +128,13 @@ public:
|
||||
kStencilResolveProcessor_ClassID,
|
||||
kFwidthSquircleTestProcessor_ClassID,
|
||||
kSwizzleFragmentProcessor_ClassID,
|
||||
kTessellate_BoundingBoxShader_ClassID,
|
||||
kTessellate_GrCurveMiddleOutShader_ClassID,
|
||||
kTessellate_GrCurveTessellateShader_ClassID,
|
||||
kTessellate_GrFillBoundingBoxShader_ClassID,
|
||||
kTessellate_GrFillCubicHullShader_ClassID,
|
||||
kTessellate_GrFillTriangleShader_ClassID,
|
||||
kTessellate_GrStencilTriangleShader_ClassID,
|
||||
kTessellate_GrStrokeShader_ClassID,
|
||||
kTessellate_GrTriangleShader_ClassID,
|
||||
kTessellate_GrWedgeTessellateShader_ClassID,
|
||||
kTessellate_HullShader_ClassID,
|
||||
kTessellationTestTriShader_ClassID,
|
||||
kTessellationTestRectShader_ClassID,
|
||||
kTestFP_ClassID,
|
||||
|
@ -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;)");
|
||||
}
|
@ -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
|
@ -11,13 +11,102 @@
|
||||
#include "src/gpu/GrInnerFanTriangulator.h"
|
||||
#include "src/gpu/GrOpFlushState.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/GrStencilPathShader.h"
|
||||
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
|
||||
|
||||
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 {
|
||||
if (fPipelineForFills) {
|
||||
fPipelineForFills->visitProxies(fn);
|
||||
@ -41,22 +130,23 @@ GrProcessorSet::Analysis GrPathInnerTriangulateOp::finalize(const GrCaps& caps,
|
||||
clampType, &fColor);
|
||||
}
|
||||
|
||||
void GrPathInnerTriangulateOp::pushFanStencilProgram(const GrPathShader::ProgramArgs& args,
|
||||
void GrPathInnerTriangulateOp::pushFanStencilProgram(const GrTessellationShader::ProgramArgs& args,
|
||||
const GrPipeline* pipelineForStencils,
|
||||
const GrUserStencilSettings* stencil) {
|
||||
SkASSERT(pipelineForStencils);
|
||||
fFanPrograms.push_back(GrStencilPathShader::MakeStencilProgram<GrStencilTriangleShader>(
|
||||
args, fViewMatrix, pipelineForStencils, stencil));
|
||||
}
|
||||
auto shader = args.fArena->make<GrTriangleShader>(fViewMatrix, SK_PMColor4fTRANSPARENT);
|
||||
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) {
|
||||
SkASSERT(fPipelineForFills);
|
||||
auto* shader = args.fArena->make<GrFillTriangleShader>(fViewMatrix, fColor);
|
||||
fFanPrograms.push_back(GrPathShader::MakeProgram(args, shader, fPipelineForFills, stencil));
|
||||
auto* shader = args.fArena->make<GrTriangleShader>(fViewMatrix, fColor);
|
||||
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) {
|
||||
SkASSERT(!fFanTriangulator);
|
||||
SkASSERT(!fFanPolys);
|
||||
@ -82,15 +172,15 @@ void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArg
|
||||
// Create a pipeline for stencil passes if needed.
|
||||
const GrPipeline* pipelineForStencils = nullptr;
|
||||
if (forceRedbookStencilPass || !isLinear) { // Curves always get stencilled.
|
||||
pipelineForStencils = GrStencilPathShader::MakeStencilPassPipeline(args, fAAType, fOpFlags,
|
||||
appliedClip.hardClip());
|
||||
pipelineForStencils = GrPathTessellationShader::MakeStencilOnlyPipeline(
|
||||
args, fAAType, fOpFlags, appliedClip.hardClip());
|
||||
}
|
||||
|
||||
// Create a pipeline for fill passes if needed.
|
||||
if (doFill) {
|
||||
fPipelineForFills = GrFillPathShader::MakeFillPassPipeline(args, fAAType,
|
||||
std::move(appliedClip),
|
||||
std::move(fProcessors));
|
||||
fPipelineForFills = GrTessellationShader::MakePipeline(args, fAAType,
|
||||
std::move(appliedClip),
|
||||
std::move(fProcessors));
|
||||
}
|
||||
|
||||
// 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
|
||||
// we can do with hw tessellation. So far we haven't found any platforms where trying to use
|
||||
// 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);
|
||||
fStencilCurvesProgram = GrPathShader::MakeProgram(
|
||||
args, fTessellator->shader(), pipelineForStencils,
|
||||
GrStencilPathShader::StencilPassSettings(fPath.getFillType()));
|
||||
const GrUserStencilSettings* stencilPathSettings =
|
||||
GrPathTessellationShader::StencilPathSettings(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.
|
||||
@ -111,11 +204,12 @@ void GrPathInnerTriangulateOp::prePreparePrograms(const GrPathShader::ProgramArg
|
||||
if (forceRedbookStencilPass) {
|
||||
// Use a standard Redbook "stencil then fill" algorithm instead of bypassing the stencil
|
||||
// buffer to fill the fan directly.
|
||||
this->pushFanStencilProgram(
|
||||
args, pipelineForStencils,
|
||||
GrStencilPathShader::StencilPassSettings(fPath.getFillType()));
|
||||
const GrUserStencilSettings* stencilPathSettings =
|
||||
GrPathTessellationShader::StencilPathSettings(fPath.getFillType());
|
||||
this->pushFanStencilProgram(args, pipelineForStencils, stencilPathSettings);
|
||||
if (doFill) {
|
||||
this->pushFanFillProgram(args, GrFillPathShader::TestAndResetStencilSettings());
|
||||
this->pushFanFillProgram(args,
|
||||
GrPathTessellationShader::TestAndResetStencilSettings());
|
||||
}
|
||||
} else if (isLinear) {
|
||||
// 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.
|
||||
// This will fill in any remaining samples and reset the stencil values back to zero.
|
||||
SkASSERT(fTessellator);
|
||||
auto* hullShader = args.fArena->make<GrFillCubicHullShader>(fViewMatrix, fColor);
|
||||
fFillHullsProgram = GrPathShader::MakeProgram(
|
||||
auto* hullShader = args.fArena->make<HullShader>(fViewMatrix, fColor);
|
||||
fFillHullsProgram = GrTessellationShader::MakeProgram(
|
||||
args, hullShader, fPipelineForFills,
|
||||
GrFillPathShader::TestAndResetStencilSettings());
|
||||
GrPathTessellationShader::TestAndResetStencilSettings());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
||||
|
||||
#include "src/gpu/GrInnerFanTriangulator.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"
|
||||
|
||||
class GrPathTessellator;
|
||||
@ -46,10 +47,10 @@ private:
|
||||
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.
|
||||
void pushFanStencilProgram(const GrPathShader::ProgramArgs&,
|
||||
void pushFanStencilProgram(const GrTessellationShader::ProgramArgs&,
|
||||
const GrPipeline* pipelineForStencils, const GrUserStencilSettings*);
|
||||
void pushFanFillProgram(const GrPathShader::ProgramArgs&, const GrUserStencilSettings*);
|
||||
void prePreparePrograms(const GrPathShader::ProgramArgs&, GrAppliedClip&&);
|
||||
void pushFanFillProgram(const GrTessellationShader::ProgramArgs&, const GrUserStencilSettings*);
|
||||
void prePreparePrograms(const GrTessellationShader::ProgramArgs&, GrAppliedClip&&);
|
||||
|
||||
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
|
||||
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
|
||||
|
@ -10,14 +10,56 @@
|
||||
#include "src/gpu/GrEagerVertexAllocator.h"
|
||||
#include "src/gpu/GrOpFlushState.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/GrPathTessellationShader.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellator.h"
|
||||
#include "src/gpu/tessellate/GrStencilPathShader.h"
|
||||
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
|
||||
|
||||
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 {
|
||||
if (fFillBBoxProgram) {
|
||||
fFillBBoxProgram->pipeline().visitProxies(fn);
|
||||
@ -41,7 +83,7 @@ GrProcessorSet::Analysis GrPathStencilFillOp::finalize(const GrCaps& caps,
|
||||
clampType, &fColor);
|
||||
}
|
||||
|
||||
void GrPathStencilFillOp::prePreparePrograms(const GrPathShader::ProgramArgs& args,
|
||||
void GrPathStencilFillOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
|
||||
GrAppliedClip&& appliedClip) {
|
||||
SkASSERT(!fTessellator);
|
||||
SkASSERT(!fStencilFanProgram);
|
||||
@ -52,41 +94,45 @@ void GrPathStencilFillOp::prePreparePrograms(const GrPathShader::ProgramArgs& ar
|
||||
return;
|
||||
}
|
||||
|
||||
const GrPipeline* stencilPassPipeline = GrStencilPathShader::MakeStencilPassPipeline(
|
||||
const GrPipeline* stencilPipeline = GrPathTessellationShader::MakeStencilOnlyPipeline(
|
||||
args, fAAType, fOpFlags, appliedClip.hardClip());
|
||||
const GrUserStencilSettings* stencilPathSettings =
|
||||
GrPathTessellationShader::StencilPathSettings(fPath.getFillType());
|
||||
|
||||
if ((fOpFlags & OpFlags::kPreferWedges) && args.fCaps->shaderCaps()->tessellationSupport()) {
|
||||
// The path is an atlas with relatively small contours, or something else that does best
|
||||
// with wedges.
|
||||
fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix);
|
||||
fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix,
|
||||
SK_PMColor4fTRANSPARENT);
|
||||
} else {
|
||||
auto drawFanWithTessellator = GrPathTessellator::DrawInnerFan::kYes;
|
||||
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.
|
||||
// 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.
|
||||
fStencilFanProgram = GrStencilPathShader::MakeStencilProgram<GrStencilTriangleShader>(
|
||||
args, fViewMatrix, stencilPassPipeline, fPath.getFillType());
|
||||
auto shader = args.fArena->make<GrTriangleShader>(fViewMatrix, SK_PMColor4fTRANSPARENT);
|
||||
fStencilFanProgram = GrTessellationShader::MakeProgram(args, shader, stencilPipeline,
|
||||
stencilPathSettings);
|
||||
drawFanWithTessellator = GrPathTessellator::DrawInnerFan::kNo;
|
||||
}
|
||||
fTessellator = GrPathTessellator::Make(args.fArena, fViewMatrix, fPath,
|
||||
drawFanWithTessellator, *args.fCaps);
|
||||
fTessellator = GrPathTessellator::Make(args.fArena, fPath, fViewMatrix,
|
||||
SK_PMColor4fTRANSPARENT, drawFanWithTessellator,
|
||||
*args.fCaps);
|
||||
}
|
||||
|
||||
fStencilPathProgram = GrPathShader::MakeProgram(
|
||||
args, fTessellator->shader(), stencilPassPipeline,
|
||||
GrStencilPathShader::StencilPassSettings(fPath.getFillType()));
|
||||
fStencilPathProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
|
||||
stencilPipeline, stencilPathSettings);
|
||||
|
||||
if (!(fOpFlags & OpFlags::kStencilOnly)) {
|
||||
// Create a program that draws a bounding box over the path and fills its stencil coverage
|
||||
// into the color buffer.
|
||||
auto* bboxShader = args.fArena->make<GrFillBoundingBoxShader>(fViewMatrix, fColor,
|
||||
fPath.getBounds());
|
||||
auto* bboxPipeline = GrFillPathShader::MakeFillPassPipeline(args, fAAType,
|
||||
std::move(appliedClip),
|
||||
std::move(fProcessors));
|
||||
auto* bboxStencil = GrFillPathShader::TestAndResetStencilSettings();
|
||||
fFillBBoxProgram = GrPathShader::MakeProgram(args, bboxShader, bboxPipeline, bboxStencil);
|
||||
auto* bboxShader = args.fArena->make<BoundingBoxShader>(fViewMatrix, fColor);
|
||||
auto* bboxPipeline = GrTessellationShader::MakePipeline(args, fAAType,
|
||||
std::move(appliedClip),
|
||||
std::move(fProcessors));
|
||||
auto* bboxStencil = GrPathTessellationShader::TestAndResetStencilSettings();
|
||||
fFillBBoxProgram = GrTessellationShader::MakeProgram(args, bboxShader, bboxPipeline,
|
||||
bboxStencil);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
#define GrPathStencilFillOp_DEFINED
|
||||
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/GrPathShader.h"
|
||||
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
|
||||
#include "src/gpu/tessellate/GrTessellationShader.h"
|
||||
|
||||
class GrPathTessellator;
|
||||
|
||||
@ -41,7 +41,7 @@ private:
|
||||
|
||||
// Chooses the rendering method we will use and creates the corresponding tessellator and
|
||||
// stencil/fill programs.
|
||||
void prePreparePrograms(const GrPathShader::ProgramArgs&, GrAppliedClip&& clip);
|
||||
void prePreparePrograms(const GrTessellationShader::ProgramArgs&, GrAppliedClip&& clip);
|
||||
|
||||
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
|
||||
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
|
||||
|
@ -5,13 +5,47 @@
|
||||
* 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/glsl/GrGLSLGeometryProcessor.h"
|
||||
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
|
||||
#include "src/gpu/glsl/GrGLSLVarying.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"(
|
||||
#define float4x3 mat4x3
|
||||
#define float2 vec2
|
||||
@ -50,55 +84,27 @@ float2 eval_rational_cubic(float4x3 P, float T) {
|
||||
return abcd.xy / abcd.z;
|
||||
})";
|
||||
|
||||
class GrStencilPathShader::Impl : public GrGLSLGeometryProcessor {
|
||||
protected:
|
||||
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
||||
const auto& shader = args.fGeomProc.cast<GrStencilPathShader>();
|
||||
args.fVaryingHandler->emitAttributes(shader);
|
||||
auto v = args.fVertBuilder;
|
||||
|
||||
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.
|
||||
GrGLSLGeometryProcessor* GrTriangleShader::createGLSLInstance(const GrShaderCaps&) const {
|
||||
class Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
|
||||
v->codeAppend(R"(
|
||||
float2 localcoord = inputPoint;
|
||||
float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
|
||||
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
|
||||
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;
|
||||
}
|
||||
|
||||
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&,
|
||||
const char* versionAndExtensionDecls,
|
||||
const GrGLSLUniformHandler&,
|
||||
@ -178,7 +184,6 @@ GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrSha
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
|
||||
const char* versionAndExtensionDecls,
|
||||
const GrGLSLUniformHandler&,
|
||||
@ -226,12 +231,17 @@ GrGLSLGeometryProcessor* GrCurveTessellateShader::createGLSLInstance(const GrSha
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
return new Impl;
|
||||
}
|
||||
|
||||
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&,
|
||||
const char* versionAndExtensionDecls,
|
||||
const GrGLSLUniformHandler&,
|
||||
@ -284,7 +294,6 @@ GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrSha
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
|
||||
const char* versionAndExtensionDecls,
|
||||
const GrGLSLUniformHandler&,
|
||||
@ -328,19 +337,16 @@ GrGLSLGeometryProcessor* GrWedgeTessellateShader::createGLSLInstance(const GrSha
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
return new Impl;
|
||||
}
|
||||
|
||||
class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
|
||||
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
||||
const auto& shader = args.fGeomProc.cast<GrCurveMiddleOutShader>();
|
||||
args.fVaryingHandler->emitAttributes(shader);
|
||||
args.fVertBuilder->insertFunction(kUnpackRationalCubicFn);
|
||||
args.fVertBuilder->insertFunction(kEvalRationalCubicFn);
|
||||
if (args.fShaderCaps->bitManipulationSupport()) {
|
||||
class GrCurveMiddleOutShader::Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
|
||||
v->insertFunction(kUnpackRationalCubicFn);
|
||||
v->insertFunction(kEvalRationalCubicFn);
|
||||
if (v->getProgramBuilder()->shaderCaps()->bitManipulationSupport()) {
|
||||
// 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() {
|
||||
int totalTriangleIdx = sk_VertexID/3 + 1;
|
||||
int depth = findMSB(totalTriangleIdx);
|
||||
@ -351,7 +357,7 @@ class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
|
||||
})");
|
||||
} else {
|
||||
// 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 totalTriangleIdx = float(sk_VertexID/3) + 1;
|
||||
float depth = floor(log2(totalTriangleIdx));
|
||||
@ -361,31 +367,22 @@ class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
|
||||
return vertexIdxWithinDepth * exp2(-1 - depth);
|
||||
})");
|
||||
}
|
||||
args.fVertBuilder->codeAppend(R"(
|
||||
float2 pos;
|
||||
v->codeAppend(R"(
|
||||
float2 localcoord;
|
||||
if (isinf(inputPoints_2_3.z)) {
|
||||
// A conic with w=Inf is an exact triangle.
|
||||
pos = (sk_VertexID < 1) ? inputPoints_0_1.xy
|
||||
: (sk_VertexID == 1) ? inputPoints_0_1.zw
|
||||
: inputPoints_2_3.xy;
|
||||
localcoord = (sk_VertexID < 1) ? inputPoints_0_1.xy
|
||||
: (sk_VertexID == 1) ? inputPoints_0_1.zw
|
||||
: inputPoints_2_3.xy;
|
||||
} else {
|
||||
float4x3 P = unpack_rational_cubic(inputPoints_0_1.xy, inputPoints_0_1.zw,
|
||||
inputPoints_2_3.xy, inputPoints_2_3.zw);
|
||||
float T = find_middle_out_T();
|
||||
pos = eval_rational_cubic(P, T);
|
||||
})");
|
||||
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(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);
|
||||
localcoord = eval_rational_cubic(P, T);
|
||||
}
|
||||
float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
|
||||
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
|
||||
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
|
||||
}
|
||||
};
|
||||
|
@ -5,43 +5,25 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrStencilPathShader_DEFINED
|
||||
#define GrStencilPathShader_DEFINED
|
||||
#ifndef GrPathTessellationShader_DEFINED
|
||||
#define GrPathTessellationShader_DEFINED
|
||||
|
||||
#include "src/gpu/GrDrawIndirectCommand.h"
|
||||
#include "src/gpu/tessellate/GrPathShader.h"
|
||||
#include "src/gpu/glsl/GrGLSLGeometryProcessor.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
|
||||
// cubics, and wedges.
|
||||
class GrStencilPathShader : public GrPathShader {
|
||||
// This is the base class for shaders in the GPU tessellator that fill paths.
|
||||
class GrPathTessellationShader : public GrTessellationShader {
|
||||
public:
|
||||
GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType,
|
||||
int tessellationPatchVertexCount = 0)
|
||||
: GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) {
|
||||
GrPathTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
|
||||
int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color)
|
||||
: GrTessellationShader(classID, primitiveType, tessellationPatchVertexCount, viewMatrix,
|
||||
color) {
|
||||
}
|
||||
|
||||
// Creates a pipeline that can be used for normal Redbook stencil draws.
|
||||
static const GrPipeline* MakeStencilPassPipeline(const GrPathShader::ProgramArgs& args,
|
||||
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) {
|
||||
// Returns the stencil settings to use for a standard Redbook "stencil" pass.
|
||||
static const GrUserStencilSettings* StencilPathSettings(SkPathFillType fillType) {
|
||||
// Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
|
||||
constexpr static GrUserStencilSettings kIncrDecrStencil(
|
||||
GrUserStencilSettings::StaticInitSeparate<
|
||||
@ -66,69 +48,111 @@ public:
|
||||
return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil;
|
||||
}
|
||||
|
||||
template<typename ShaderType>
|
||||
static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix,
|
||||
const GrPipeline* pipeline,
|
||||
const GrUserStencilSettings* stencil) {
|
||||
const auto* shader = args.fArena->make<ShaderType>(viewMatrix);
|
||||
return GrPathShader::MakeProgram(args, shader, pipeline, stencil);
|
||||
// Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero
|
||||
// stencil values to pass and write a color, and resets the stencil value back to zero; discards
|
||||
// immediately on stencil values of zero.
|
||||
static const GrUserStencilSettings* TestAndResetStencilSettings() {
|
||||
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;
|
||||
}
|
||||
|
||||
template<typename ShaderType>
|
||||
static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix,
|
||||
const GrPipeline* pipeline,
|
||||
const SkPathFillType fillType) {
|
||||
return MakeStencilProgram<ShaderType>(args, viewMatrix, pipeline,
|
||||
StencilPassSettings(fillType));
|
||||
// Creates a pipeline that does not write to the color buffer.
|
||||
static const GrPipeline* MakeStencilOnlyPipeline(const ProgramArgs& args, GrAAType aaType,
|
||||
GrTessellationPathRenderer::OpFlags opFlags,
|
||||
const GrAppliedHardClip& hardClip) {
|
||||
using OpFlags = GrTessellationPathRenderer::OpFlags;
|
||||
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:
|
||||
constexpr static Attribute kSinglePointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
|
||||
kFloat2_GrSLType};
|
||||
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {}
|
||||
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
|
||||
// Default path tessellation shader implementation that manages a uniform matrix and color.
|
||||
class Impl : public GrGLSLGeometryProcessor {
|
||||
public:
|
||||
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.
|
||||
class GrStencilTriangleShader : public GrStencilPathShader {
|
||||
// Draws a simple array of triangles.
|
||||
class GrTriangleShader : public GrPathTessellationShader {
|
||||
public:
|
||||
GrStencilTriangleShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
|
||||
kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) {
|
||||
this->setVertexAttributes(&kSinglePointAttrib, 1);
|
||||
GrTriangleShader(const SkMatrix& viewMatrix, SkPMColor4f color)
|
||||
: GrPathTessellationShader(kTessellate_GrTriangleShader_ClassID,
|
||||
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.
|
||||
// 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:
|
||||
GrCurveTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
|
||||
kTessellate_GrCurveTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) {
|
||||
this->setVertexAttributes(&kSinglePointAttrib, 1);
|
||||
GrCurveTessellateShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
|
||||
: GrPathTessellationShader(kTessellate_GrCurveTessellateShader_ClassID,
|
||||
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:
|
||||
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
|
||||
// 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.
|
||||
// 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:
|
||||
GrWedgeTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader(
|
||||
kTessellate_GrWedgeTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) {
|
||||
this->setVertexAttributes(&kSinglePointAttrib, 1);
|
||||
GrWedgeTessellateShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
|
||||
: GrPathTessellationShader(kTessellate_GrWedgeTessellateShader_ClassID,
|
||||
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:
|
||||
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.
|
||||
@ -142,7 +166,7 @@ private:
|
||||
// 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
|
||||
// then sort the instance buffer by resolveLevel for efficient batching of indirect draws.
|
||||
class GrCurveMiddleOutShader : public GrStencilPathShader {
|
||||
class GrCurveMiddleOutShader : public GrPathTessellationShader {
|
||||
public:
|
||||
// How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel
|
||||
// line segments?
|
||||
@ -167,19 +191,19 @@ public:
|
||||
indirectWriter->write(instanceCount, baseInstance, vertexCount, 0);
|
||||
}
|
||||
|
||||
GrCurveMiddleOutShader(const SkMatrix& viewMatrix)
|
||||
: GrStencilPathShader(kTessellate_GrCurveMiddleOutShader_ClassID, viewMatrix,
|
||||
GrPrimitiveType::kTriangles) {
|
||||
GrCurveMiddleOutShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
|
||||
: GrPathTessellationShader(kTessellate_GrCurveMiddleOutShader_ClassID,
|
||||
GrPrimitiveType::kTriangles, 0, viewMatrix, color) {
|
||||
constexpr static Attribute kInputPtsAttribs[] = {
|
||||
{"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
|
||||
{"inputPoints_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
|
||||
this->setInstanceAttributes(kInputPtsAttribs, 2);
|
||||
}
|
||||
|
||||
const char* name() const override { return "tessellate_GrCurveMiddleOutShader"; }
|
||||
|
||||
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;
|
||||
};
|
@ -14,7 +14,7 @@
|
||||
#include "src/gpu/tessellate/GrCullTest.h"
|
||||
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.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;
|
||||
|
||||
@ -27,27 +27,29 @@ static bool can_use_hardware_tessellation(const SkPath& path, const GrCaps& caps
|
||||
return path.countVerbs() >= caps.minPathVerbsForHwTessellation();
|
||||
}
|
||||
|
||||
GrPathTessellator* GrPathTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix,
|
||||
const SkPath& path, DrawInnerFan drawInnerFan,
|
||||
const GrCaps& caps) {
|
||||
GrPathTessellator* GrPathTessellator::Make(SkArenaAlloc* arena, const SkPath& path,
|
||||
const SkMatrix& viewMatrix, const SkPMColor4f& color,
|
||||
DrawInnerFan drawInnerFan, const GrCaps& caps) {
|
||||
if (can_use_hardware_tessellation(path, caps)) {
|
||||
if (drawInnerFan == DrawInnerFan::kNo) {
|
||||
return GrPathOuterCurveTessellator::Make(arena, viewMatrix, drawInnerFan);
|
||||
return GrPathOuterCurveTessellator::Make(arena, viewMatrix, color, drawInnerFan);
|
||||
} else {
|
||||
return GrPathWedgeTessellator::Make(arena, viewMatrix);
|
||||
return GrPathWedgeTessellator::Make(arena, viewMatrix, color);
|
||||
}
|
||||
} else {
|
||||
return GrPathIndirectTessellator::Make(arena, viewMatrix, path, drawInnerFan);
|
||||
return GrPathIndirectTessellator::Make(arena, path, viewMatrix, color, drawInnerFan);
|
||||
}
|
||||
}
|
||||
|
||||
GrPathTessellator* GrPathIndirectTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix,
|
||||
const SkPath& path, DrawInnerFan drawInnerFan) {
|
||||
auto shader = arena->make<GrCurveMiddleOutShader>(viewMatrix);
|
||||
GrPathTessellator* GrPathIndirectTessellator::Make(SkArenaAlloc* arena, const SkPath& path,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
DrawInnerFan drawInnerFan) {
|
||||
auto shader = arena->make<GrCurveMiddleOutShader>(viewMatrix, color);
|
||||
return arena->make<GrPathIndirectTessellator>(shader, path, drawInnerFan);
|
||||
}
|
||||
|
||||
GrPathIndirectTessellator::GrPathIndirectTessellator(GrStencilPathShader* shader,
|
||||
GrPathIndirectTessellator::GrPathIndirectTessellator(GrPathTessellationShader* shader,
|
||||
const SkPath& path, DrawInnerFan drawInnerFan)
|
||||
: GrPathTessellator(shader)
|
||||
, fDrawInnerFan(drawInnerFan != DrawInnerFan::kNo) {
|
||||
@ -243,7 +245,7 @@ void GrPathIndirectTessellator::prepare(GrMeshDrawOp::Target* target, const SkRe
|
||||
instanceLocations[level].writeArray(pts, 4);
|
||||
break;
|
||||
case SkPathVerb::kConic:
|
||||
GrPathShader::WriteConicPatch(pts, *w, &instanceLocations[level]);
|
||||
GrTessellationShader::WriteConicPatch(pts, *w, &instanceLocations[level]);
|
||||
break;
|
||||
default:
|
||||
SkUNREACHABLE;
|
||||
@ -279,8 +281,9 @@ void GrPathIndirectTessellator::drawHullInstances(GrOpFlushState* flushState) co
|
||||
|
||||
GrPathTessellator* GrPathOuterCurveTessellator::Make(SkArenaAlloc* arena,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
DrawInnerFan drawInnerFan) {
|
||||
auto shader = arena->make<GrCurveTessellateShader>(viewMatrix);
|
||||
auto shader = arena->make<GrCurveTessellateShader>(viewMatrix, color);
|
||||
return arena->make<GrPathOuterCurveTessellator>(shader, drawInnerFan);
|
||||
}
|
||||
|
||||
@ -359,7 +362,7 @@ void GrPathOuterCurveTessellator::prepare(GrMeshDrawOp::Target* target, const Sk
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
auto shader = arena->make<GrWedgeTessellateShader>(viewMatrix);
|
||||
GrPathTessellator* GrPathWedgeTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color) {
|
||||
auto shader = arena->make<GrWedgeTessellateShader>(viewMatrix, color);
|
||||
return arena->make<GrPathWedgeTessellator>(shader);
|
||||
}
|
||||
|
||||
@ -506,7 +510,7 @@ void GrPathWedgeTessellator::prepare(GrMeshDrawOp::Target* target, const SkRect&
|
||||
return;
|
||||
}
|
||||
if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
|
||||
GrPathShader::WriteConicPatch(p, w, &vertexWriter);
|
||||
GrTessellationShader::WriteConicPatch(p, w, &vertexWriter);
|
||||
vertexWriter.write(midpoint);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
|
||||
|
||||
class SkPath;
|
||||
class GrStencilPathShader;
|
||||
class GrPathTessellationShader;
|
||||
|
||||
// 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.
|
||||
@ -30,10 +30,10 @@ public:
|
||||
};
|
||||
|
||||
// Creates the tessellator best suited to draw the given path.
|
||||
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, const SkPath&, DrawInnerFan,
|
||||
const GrCaps&);
|
||||
static GrPathTessellator* Make(SkArenaAlloc*, const SkPath&, const SkMatrix&,
|
||||
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
|
||||
// given BreadcrumbTriangleList is non-null, then this class will also include the breadcrumb
|
||||
@ -53,9 +53,9 @@ public:
|
||||
virtual ~GrPathTessellator() {}
|
||||
|
||||
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
|
||||
@ -64,7 +64,8 @@ protected:
|
||||
// cubic or a conic.
|
||||
class GrPathIndirectTessellator final : public GrPathTessellator {
|
||||
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&,
|
||||
const BreadcrumbTriangleList*) override;
|
||||
@ -74,7 +75,7 @@ public:
|
||||
private:
|
||||
constexpr static int kMaxResolveLevel = GrTessellationPathRenderer::kMaxResolveLevel;
|
||||
|
||||
GrPathIndirectTessellator(GrStencilPathShader*, const SkPath&, DrawInnerFan);
|
||||
GrPathIndirectTessellator(GrPathTessellationShader*, const SkPath&, DrawInnerFan);
|
||||
|
||||
const bool fDrawInnerFan;
|
||||
int fResolveLevelCounts[kMaxResolveLevel + 1] = {0};
|
||||
@ -97,7 +98,7 @@ public:
|
||||
void draw(GrOpFlushState*) const final;
|
||||
|
||||
protected:
|
||||
GrPathHardwareTessellator(GrStencilPathShader* shader, int numVerticesPerPatch)
|
||||
GrPathHardwareTessellator(GrPathTessellationShader* shader, int numVerticesPerPatch)
|
||||
: GrPathTessellator(shader), fNumVerticesPerPatch(numVerticesPerPatch) {}
|
||||
|
||||
GrVertexChunkArray fVertexChunkArray;
|
||||
@ -109,14 +110,15 @@ protected:
|
||||
// or a conic. Quadratics are converted to cubics and triangles are converted to conics with w=Inf.
|
||||
class GrPathOuterCurveTessellator final : public GrPathHardwareTessellator {
|
||||
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&,
|
||||
const BreadcrumbTriangleList*) override;
|
||||
void drawHullInstances(GrOpFlushState*) const override;
|
||||
|
||||
private:
|
||||
GrPathOuterCurveTessellator(GrStencilPathShader* shader, DrawInnerFan drawInnerFan)
|
||||
GrPathOuterCurveTessellator(GrPathTessellationShader* shader, DrawInnerFan drawInnerFan)
|
||||
: GrPathHardwareTessellator(shader, 4)
|
||||
, fDrawInnerFan(drawInnerFan == DrawInnerFan::kYes) {}
|
||||
|
||||
@ -131,13 +133,14 @@ private:
|
||||
// converted to cubics. Once stencilled, these wedges alone define the complete path.
|
||||
class GrPathWedgeTessellator final : public GrPathHardwareTessellator {
|
||||
public:
|
||||
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&);
|
||||
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix&, const SkPMColor4f&);
|
||||
|
||||
void prepare(GrMeshDrawOp::Target*, const SkRect& cullBounds, const SkPath&,
|
||||
const BreadcrumbTriangleList*) override;
|
||||
|
||||
private:
|
||||
GrPathWedgeTessellator(GrStencilPathShader* shader) : GrPathHardwareTessellator(shader, 5) {}
|
||||
GrPathWedgeTessellator(GrPathTessellationShader* shader)
|
||||
: GrPathHardwareTessellator(shader, 5) {}
|
||||
|
||||
friend class SkArenaAlloc; // For constructor.
|
||||
};
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
return;
|
||||
}
|
||||
SkPoint conic[4];
|
||||
GrPathShader::WriteConicPatch(p, w, conic);
|
||||
GrTessellationShader::WriteConicPatch(p, w, conic);
|
||||
SkPoint endControlPoint = conic[1];
|
||||
this->writeStroke(conic, endControlPoint);
|
||||
fMaxParametricSegments_pow4 = std::max(numParametricSegments_pow4,
|
||||
|
@ -369,7 +369,7 @@ private:
|
||||
if (w == 1) {
|
||||
GrPathUtils::convertQuadToCubic(p, asPatch);
|
||||
} else {
|
||||
GrPathShader::WriteConicPatch(p, w, asPatch);
|
||||
GrTessellationShader::WriteConicPatch(p, w, asPatch);
|
||||
}
|
||||
|
||||
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.
|
||||
prevJoinFitsInPatch = patchWriter.stroke180FitsInPatch_withJoin(
|
||||
numParametricSegments_pow4);
|
||||
GrPathShader::WriteConicPatch(p, *w, scratchPts);
|
||||
GrTessellationShader::WriteConicPatch(p, *w, scratchPts);
|
||||
patchPts = scratchPts;
|
||||
endControlPoint = p[1];
|
||||
break;
|
||||
|
@ -890,7 +890,7 @@ void GrStrokeIndirectTessellator::writeBuffers(GrDrawIndirectWriter* indirectWri
|
||||
binningWriter.writeCircle(cuspResolveLevel, cusp);
|
||||
resolveLevel = (isRoundJoin) ? *nextResolveLevel++ : 0;
|
||||
} else {
|
||||
GrPathShader::WriteConicPatch(pts, iter.w(), scratch);
|
||||
GrTessellationShader::WriteConicPatch(pts, iter.w(), scratch);
|
||||
}
|
||||
pts_ = scratch;
|
||||
break;
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef GrStrokeShader_DEFINED
|
||||
#define GrStrokeShader_DEFINED
|
||||
|
||||
#include "src/gpu/tessellate/GrPathShader.h"
|
||||
#include "src/gpu/tessellate/GrTessellationShader.h"
|
||||
|
||||
#include "include/core/SkStrokeRec.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
|
||||
// edges and sorts them into a single quad strip. With this combined set of edges we can stroke any
|
||||
// curve, regardless of curvature.
|
||||
class GrStrokeShader : public GrPathShader {
|
||||
class GrStrokeShader : public GrTessellationShader {
|
||||
public:
|
||||
// Are we using hardware tessellation or indirect draws?
|
||||
enum class Mode : int8_t {
|
||||
@ -98,17 +98,17 @@ public:
|
||||
};
|
||||
|
||||
// 'viewMatrix' is applied to the geometry post tessellation. It cannot have perspective.
|
||||
GrStrokeShader(Mode mode, ShaderFlags shaderFlags, int8_t maxParametricSegments_log2,
|
||||
const SkMatrix& viewMatrix, const SkStrokeRec& stroke, SkPMColor4f color)
|
||||
: GrPathShader(kTessellate_GrStrokeShader_ClassID, viewMatrix,
|
||||
(mode == Mode::kHardwareTessellation) ?
|
||||
GrPrimitiveType::kPatches : GrPrimitiveType::kTriangleStrip,
|
||||
(mode == Mode::kHardwareTessellation) ? 1 : 0)
|
||||
GrStrokeShader(Mode mode, ShaderFlags shaderFlags, const SkMatrix& viewMatrix,
|
||||
const SkStrokeRec& stroke, SkPMColor4f color, int8_t maxParametricSegments_log2)
|
||||
: GrTessellationShader(kTessellate_GrStrokeShader_ClassID,
|
||||
(mode == Mode::kHardwareTessellation)
|
||||
? GrPrimitiveType::kPatches
|
||||
: GrPrimitiveType::kTriangleStrip,
|
||||
(mode == Mode::kHardwareTessellation) ? 1 : 0, viewMatrix, color)
|
||||
, fMode(mode)
|
||||
, fShaderFlags(shaderFlags)
|
||||
, fMaxParametricSegments_log2(maxParametricSegments_log2)
|
||||
, fStroke(stroke)
|
||||
, fColor(color) {
|
||||
, fMaxParametricSegments_log2(maxParametricSegments_log2) {
|
||||
if (fMode == Mode::kHardwareTessellation) {
|
||||
// A join calculates its starting angle using prevCtrlPtAttr.
|
||||
fAttribs.emplace_back("prevCtrlPtAttr", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
|
||||
@ -168,11 +168,10 @@ public:
|
||||
|
||||
Mode mode() const { return fMode; }
|
||||
ShaderFlags flags() const { return fShaderFlags; }
|
||||
int8_t maxParametricSegments_log2() const { return fMaxParametricSegments_log2; }
|
||||
bool hasDynamicStroke() const { return fShaderFlags & ShaderFlags::kDynamicStroke; }
|
||||
bool hasDynamicColor() const { return fShaderFlags & ShaderFlags::kDynamicColor; }
|
||||
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;}
|
||||
|
||||
// Used by GrFixedCountTessellator to configure the uniform value that tells the shader how many
|
||||
@ -189,9 +188,8 @@ private:
|
||||
|
||||
const Mode fMode;
|
||||
const ShaderFlags fShaderFlags;
|
||||
const int8_t fMaxParametricSegments_log2;
|
||||
const SkStrokeRec fStroke;
|
||||
const SkPMColor4f fColor;
|
||||
const int8_t fMaxParametricSegments_log2;
|
||||
|
||||
constexpr static int kMaxAttribCount = 5;
|
||||
SkSTArray<kMaxAttribCount, Attribute> fAttribs;
|
||||
|
@ -9,11 +9,10 @@
|
||||
|
||||
#include "src/core/SkPathPriv.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/GrStrokeHardwareTessellator.h"
|
||||
#include "src/gpu/tessellate/GrStrokeIndirectTessellator.h"
|
||||
#include "src/gpu/tessellate/GrTessellationShader.h"
|
||||
|
||||
using DynamicStroke = GrStrokeShader::DynamicStroke;
|
||||
|
||||
@ -164,7 +163,7 @@ bool GrStrokeTessellateOp::canUseHardwareTessellation(int numVerbs, const GrCaps
|
||||
return numVerbs >= caps.minStrokeVerbsForHwTessellation();
|
||||
}
|
||||
|
||||
void GrStrokeTessellateOp::prePrepareTessellator(GrPathShader::ProgramArgs&& args,
|
||||
void GrStrokeTessellateOp::prePrepareTessellator(GrTessellationShader::ProgramArgs&& args,
|
||||
GrAppliedClip&& clip) {
|
||||
SkASSERT(!fTessellator);
|
||||
SkASSERT(!fFillProgram);
|
||||
@ -212,17 +211,18 @@ void GrStrokeTessellateOp::prePrepareTessellator(GrPathShader::ProgramArgs&& arg
|
||||
strokeCullBounds);
|
||||
}
|
||||
|
||||
auto* pipeline = GrFillPathShader::MakeFillPassPipeline(args, fAAType, std::move(clip),
|
||||
std::move(fProcessors));
|
||||
auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(clip),
|
||||
std::move(fProcessors));
|
||||
auto fillStencil = &GrUserStencilSettings::kUnused;
|
||||
if (fNeedsStencil) {
|
||||
fStencilProgram = GrPathShader::MakeProgram(args, fTessellator->shader(), pipeline,
|
||||
&kMarkStencil);
|
||||
fStencilProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(), pipeline,
|
||||
&kMarkStencil);
|
||||
fillStencil = &kTestAndResetStencil;
|
||||
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,
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
#include "include/core/SkStrokeRec.h"
|
||||
#include "src/gpu/ops/GrMeshDrawOp.h"
|
||||
#include "src/gpu/tessellate/GrPathShader.h"
|
||||
#include "src/gpu/tessellate/GrStrokeTessellator.h"
|
||||
#include "src/gpu/tessellate/GrTessellationShader.h"
|
||||
|
||||
class GrRecordingContext;
|
||||
|
||||
@ -55,7 +55,7 @@ private:
|
||||
CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
|
||||
|
||||
// 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*,
|
||||
const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
|
||||
|
@ -29,14 +29,14 @@ public:
|
||||
int8_t maxParametricSegments_log2, const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList, std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds)
|
||||
: fShader(shaderMode, shaderFlags, maxParametricSegments_log2, viewMatrix,
|
||||
pathStrokeList->fStroke, pathStrokeList->fColor)
|
||||
: fShader(shaderMode, shaderFlags, viewMatrix, pathStrokeList->fStroke,
|
||||
pathStrokeList->fColor, maxParametricSegments_log2)
|
||||
, fPathStrokeList(pathStrokeList)
|
||||
, fMatrixMinMaxScales(matrixMinMaxScales)
|
||||
, 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.
|
||||
virtual void prepare(GrMeshDrawOp::Target*, int totalCombinedVerbCnt) = 0;
|
||||
|
@ -5,26 +5,27 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathShader_DEFINED
|
||||
#define GrPathShader_DEFINED
|
||||
#ifndef GrTessellationShader_DEFINED
|
||||
#define GrTessellationShader_DEFINED
|
||||
|
||||
#include "src/core/SkArenaAlloc.h"
|
||||
#include "src/gpu/GrGeometryProcessor.h"
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#include "src/gpu/GrOpsRenderPass.h"
|
||||
#include "src/gpu/GrProgramInfo.h"
|
||||
#include "src/gpu/GrVertexWriter.h"
|
||||
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
|
||||
|
||||
class SkArenaAlloc;
|
||||
|
||||
// This is a common base class for shaders in the GPU tessellator.
|
||||
class GrPathShader : public GrGeometryProcessor {
|
||||
class GrTessellationShader : public GrGeometryProcessor {
|
||||
public:
|
||||
GrPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType,
|
||||
int tessellationPatchVertexCount)
|
||||
GrTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
|
||||
int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color)
|
||||
: GrGeometryProcessor(classID)
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fPrimitiveType(primitiveType)
|
||||
, fTessellationPatchVertexCount(tessellationPatchVertexCount) {
|
||||
, fTessellationPatchVertexCount(tessellationPatchVertexCount)
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fColor(color) {
|
||||
if (fTessellationPatchVertexCount) {
|
||||
this->setWillUseTessellationShaders();
|
||||
}
|
||||
@ -33,24 +34,7 @@ public:
|
||||
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
|
||||
int tessellationPatchVertexCount() const { return fTessellationPatchVertexCount; }
|
||||
const SkMatrix& viewMatrix() const { return fViewMatrix; }
|
||||
|
||||
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);
|
||||
}
|
||||
const SkPMColor4f& color() const { return fColor;}
|
||||
|
||||
// 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) {
|
||||
@ -64,12 +48,41 @@ public:
|
||||
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:
|
||||
const SkMatrix fViewMatrix;
|
||||
const GrPrimitiveType fPrimitiveType;
|
||||
const int fTessellationPatchVertexCount;
|
||||
|
||||
class Impl;
|
||||
const SkMatrix fViewMatrix;
|
||||
const SkPMColor4f fColor;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user