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()) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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/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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user