Reland "Implement batching for convex tessellated paths"
This is a reland of 9613060bdf
Original change's description:
> Implement batching for convex tessellated paths
>
> Moves the view matrix transformation onto the CPU (when local coords
> are not used), and plumbs a color attrib through the tessellation
> patches.
>
> Bug: skia:12524
> Change-Id: Ic4740048b4fc85cb18e7235a7754d57762db3daf
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/468997
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Bug: skia:12524
Change-Id: I77cd079d8921b224925bd2f7364c564822886d61
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/470436
Commit-Queue: Robert Phillips <robertphillips@google.com>
Auto-Submit: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
05c41162fb
commit
08a971126e
@ -149,7 +149,8 @@ DEF_PATH_TESS_BENCH(GrPathCurveTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
fTarget->caps().minPathVerbsForHwTessellation(),
|
||||
noVaryingsPipeline,
|
||||
fTarget->caps());
|
||||
tess->prepare(fTarget.get(), {gAlmostIdentity, fPath}, fPath.countVerbs());
|
||||
tess->prepare(fTarget.get(), {gAlmostIdentity, fPath, SK_PMColor4fTRANSPARENT},
|
||||
fPath.countVerbs());
|
||||
}
|
||||
|
||||
DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
@ -162,7 +163,8 @@ DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
fTarget->caps().minPathVerbsForHwTessellation(),
|
||||
noVaryingsPipeline,
|
||||
fTarget->caps());
|
||||
tess->prepare(fTarget.get(), {gAlmostIdentity, fPath}, fPath.countVerbs());
|
||||
tess->prepare(fTarget.get(), {gAlmostIdentity, fPath, SK_PMColor4fTRANSPARENT},
|
||||
fPath.countVerbs());
|
||||
}
|
||||
|
||||
static void benchmark_wangs_formula_cubic_log2(const SkMatrix& matrix, const SkPath& path) {
|
||||
|
59
gm/batchedconvexpaths.cpp
Normal file
59
gm/batchedconvexpaths.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "gm/gm.h"
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/gpu/GrContextOptions.h"
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class BatchedConvexPathsGM : public GM {
|
||||
private:
|
||||
SkString onShortName() override { return SkString("batchedconvexpaths"); }
|
||||
SkISize onISize() override { return SkISize::Make(512, 512); }
|
||||
|
||||
void modifyGrContextOptions(GrContextOptions* ctxOptions) override {
|
||||
// Ensure our paths don't go through the atlas path renderer.
|
||||
ctxOptions->fGpuPathRenderers &= ~GpuPathRenderers::kAtlas;
|
||||
}
|
||||
|
||||
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
|
||||
canvas->clear(SK_ColorBLACK);
|
||||
for (uint32_t i = 0; i < 10; ++i) {
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
|
||||
int numPoints = (i + 3) * 3;
|
||||
SkPath path;
|
||||
path.moveTo(1, 0);
|
||||
for (float j = 1; j < numPoints; j += 3) {
|
||||
constexpr float k2PI = SK_ScalarPI * 2;
|
||||
path.cubicTo(cosf(j/numPoints * k2PI), sinf(j/numPoints * k2PI),
|
||||
cosf((j+1)/numPoints * k2PI), sinf((j+1)/numPoints * k2PI),
|
||||
j+2 == numPoints ? 1 : cosf((j+2)/numPoints * k2PI),
|
||||
j+2 == numPoints ? 0 : sinf((j+2)/numPoints * k2PI));
|
||||
}
|
||||
float scale = 256 - i*24;
|
||||
canvas->translate(scale + (256 - scale) * .33f, scale + (256 - scale) * .33f);
|
||||
canvas->scale(scale, scale);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(((i + 123458383u) * 285018463u) | 0xff808080);
|
||||
paint.setAlphaf(0.3f);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
canvas->drawPath(path, paint);
|
||||
}
|
||||
return DrawResult::kOk;
|
||||
}
|
||||
};
|
||||
|
||||
DEF_GM( return new BatchedConvexPathsGM; )
|
||||
|
||||
} // namespace skiagm
|
@ -31,6 +31,7 @@ gm_sources = [
|
||||
"$_gm/backdrop.cpp",
|
||||
"$_gm/backdrop_imagefilter_croprect.cpp",
|
||||
"$_gm/badpaint.cpp",
|
||||
"$_gm/batchedconvexpaths.cpp",
|
||||
"$_gm/bc1_transparency.cpp",
|
||||
"$_gm/beziers.cpp",
|
||||
"$_gm/bicubic.cpp",
|
||||
|
@ -122,7 +122,7 @@ private:
|
||||
caps);
|
||||
break;
|
||||
}
|
||||
fTessellator->prepare(flushState, {pathMatrix, fPath}, fPath.countVerbs());
|
||||
fTessellator->prepare(flushState, {pathMatrix, fPath, kCyan}, fPath.countVerbs());
|
||||
fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
|
||||
flushState->usesMSAASurface(),
|
||||
&flushState->dstProxyView(),
|
||||
|
@ -68,7 +68,8 @@ private:
|
||||
class AtlasPathList : SkNoncopyable {
|
||||
public:
|
||||
void add(PathDrawAllocator* alloc, const SkMatrix& pathMatrix, const SkPath& path) {
|
||||
fPathDrawList = &alloc->emplace_back(pathMatrix, path, fPathDrawList);
|
||||
fPathDrawList = &alloc->emplace_back(pathMatrix, path, SK_PMColor4fTRANSPARENT,
|
||||
fPathDrawList);
|
||||
if (path.isInverseFillType()) {
|
||||
// The atlas never has inverse paths. The inversion happens later.
|
||||
fPathDrawList->fPath.toggleInverseFillType();
|
||||
|
@ -24,7 +24,8 @@ class HullShader : public GrPathTessellationShader {
|
||||
public:
|
||||
HullShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
|
||||
: GrPathTessellationShader(kTessellate_HullShader_ClassID,
|
||||
GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
|
||||
GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color,
|
||||
skgpu::PatchAttribs::kNone) {
|
||||
fInstanceAttribs.emplace_back("p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
|
||||
fInstanceAttribs.emplace_back("p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
|
||||
if (!shaderCaps.infinitySupport()) {
|
||||
@ -55,8 +56,11 @@ private:
|
||||
std::unique_ptr<GrGeometryProcessor::ProgramImpl> HullShader::makeProgramImpl(
|
||||
const GrShaderCaps&) const {
|
||||
class Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
|
||||
void emitVertexCode(const GrShaderCaps& shaderCaps,
|
||||
const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v,
|
||||
GrGLSLVaryingHandler*,
|
||||
GrGPArgs* gpArgs) override {
|
||||
if (shaderCaps.infinitySupport()) {
|
||||
v->insertFunction(R"(
|
||||
bool is_conic_curve() { return isinf(p23.w); }
|
||||
@ -409,7 +413,7 @@ void PathInnerTriangulateOp::onPrepare(GrOpFlushState* flushState) {
|
||||
if (fTessellator) {
|
||||
// Must be called after polysToTriangles() in order for fFanBreadcrumbs to be complete.
|
||||
fTessellator->prepare(flushState,
|
||||
{SkMatrix::I(), fPath},
|
||||
{SkMatrix::I(), fPath, SK_PMColor4fTRANSPARENT},
|
||||
fPath.countVerbs(),
|
||||
&fFanBreadcrumbs);
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ void PathStencilCoverOp::onPrepare(GrOpFlushState* flushState) {
|
||||
int maxTrianglesInFans = std::max(maxCombinedFanEdges - 2, 0);
|
||||
VertexWriter triangleVertexWriter = vertexAlloc.lock<SkPoint>(maxTrianglesInFans * 3);
|
||||
int fanTriangleCount = 0;
|
||||
for (auto [pathMatrix, path] : *fPathDrawList) {
|
||||
for (auto [pathMatrix, path, color] : *fPathDrawList) {
|
||||
AffineMatrix m(pathMatrix);
|
||||
for (PathMiddleOutFanIter it(path); !it.done();) {
|
||||
for (auto [p0, p1, p2] : it.nextStack()) {
|
||||
@ -269,7 +269,7 @@ void PathStencilCoverOp::onPrepare(GrOpFlushState* flushState) {
|
||||
&fBBoxBuffer,
|
||||
&fBBoxBaseInstance);
|
||||
SkDEBUGCODE(int pathCount = 0;)
|
||||
for (auto [pathMatrix, path] : *fPathDrawList) {
|
||||
for (auto [pathMatrix, path, color] : *fPathDrawList) {
|
||||
SkDEBUGCODE(auto end = vertexWriter.makeOffset(instanceStride));
|
||||
vertexWriter << pathMatrix.getScaleX()
|
||||
<< pathMatrix.getSkewY()
|
||||
|
@ -34,7 +34,7 @@ private:
|
||||
FillPathFlags pathFlags,
|
||||
const SkRect& drawBounds)
|
||||
: GrDrawOp(ClassID())
|
||||
, fPathDrawList(arena->make<PathDrawList>(viewMatrix, path))
|
||||
, fPathDrawList(arena->make<PathDrawList>(viewMatrix, path, SK_PMColor4fTRANSPARENT))
|
||||
, fTotalCombinedPathVerbCnt(path.countVerbs())
|
||||
, fPathCount(1)
|
||||
, fPathFlags(pathFlags)
|
||||
|
@ -25,8 +25,46 @@ void PathTessellateOp::visitProxies(const GrVisitProxyFunc& func) const {
|
||||
GrProcessorSet::Analysis PathTessellateOp::finalize(const GrCaps& caps,
|
||||
const GrAppliedClip* clip,
|
||||
GrClampType clampType) {
|
||||
return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
|
||||
clampType, &fColor);
|
||||
auto analysis = fProcessors.finalize(this->headDraw().fColor,
|
||||
GrProcessorAnalysisCoverage::kNone,
|
||||
clip,
|
||||
nullptr,
|
||||
caps,
|
||||
clampType,
|
||||
&this->headDraw().fColor);
|
||||
if (!analysis.usesLocalCoords()) {
|
||||
// Since we don't need local coords, we can transform on CPU instead of in the shader. This
|
||||
// gives us better batching potential.
|
||||
this->headDraw().fPathMatrix = fShaderMatrix;
|
||||
fShaderMatrix = SkMatrix::I();
|
||||
}
|
||||
return analysis;
|
||||
}
|
||||
|
||||
GrDrawOp::CombineResult PathTessellateOp::onCombineIfPossible(GrOp* grOp,
|
||||
SkArenaAlloc*,
|
||||
const GrCaps&) {
|
||||
auto* op = grOp->cast<PathTessellateOp>();
|
||||
bool canMerge = fAAType == op->fAAType &&
|
||||
fStencil == op->fStencil &&
|
||||
fProcessors == op->fProcessors &&
|
||||
fShaderMatrix == op->fShaderMatrix;
|
||||
if (canMerge) {
|
||||
fTotalCombinedPathVerbCnt += op->fTotalCombinedPathVerbCnt;
|
||||
fPatchAttribs |= op->fPatchAttribs;
|
||||
|
||||
if (!(fPatchAttribs & PatchAttribs::kColor) &&
|
||||
this->headDraw().fColor != op->headDraw().fColor) {
|
||||
// Color is no longer uniform. Move it into patch attribs.
|
||||
fPatchAttribs |= PatchAttribs::kColor;
|
||||
}
|
||||
|
||||
*fPathDrawTail = op->fPathDrawList;
|
||||
fPathDrawTail = op->fPathDrawTail;
|
||||
return CombineResult::kMerged;
|
||||
}
|
||||
|
||||
return CombineResult::kCannotCombine;
|
||||
}
|
||||
|
||||
void PathTessellateOp::prepareTessellator(const GrTessellationShader::ProgramArgs& args,
|
||||
@ -35,9 +73,16 @@ void PathTessellateOp::prepareTessellator(const GrTessellationShader::ProgramArg
|
||||
SkASSERT(!fTessellationProgram);
|
||||
auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(appliedClip),
|
||||
std::move(fProcessors));
|
||||
fTessellator = PathWedgeTessellator::Make(args.fArena, fViewMatrix, fColor, fPath.countVerbs(),
|
||||
*pipeline, *args.fCaps);
|
||||
fTessellationProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(), pipeline,
|
||||
fTessellator = PathWedgeTessellator::Make(args.fArena,
|
||||
fShaderMatrix,
|
||||
this->headDraw().fColor,
|
||||
fTotalCombinedPathVerbCnt,
|
||||
*pipeline,
|
||||
*args.fCaps,
|
||||
fPatchAttribs);
|
||||
fTessellationProgram = GrTessellationShader::MakeProgram(args,
|
||||
fTessellator->shader(),
|
||||
pipeline,
|
||||
fStencil);
|
||||
}
|
||||
|
||||
@ -64,7 +109,7 @@ void PathTessellateOp::onPrepare(GrOpFlushState* flushState) {
|
||||
&flushState->caps()}, flushState->detachAppliedClip());
|
||||
SkASSERT(fTessellator);
|
||||
}
|
||||
fTessellator->prepare(flushState, {SkMatrix::I(), fPath}, fPath.countVerbs());
|
||||
fTessellator->prepare(flushState, *fPathDrawList, fTotalCombinedPathVerbCnt);
|
||||
}
|
||||
|
||||
void PathTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
|
||||
@ -73,7 +118,6 @@ void PathTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chain
|
||||
flushState->bindPipelineAndScissorClip(*fTessellationProgram, this->bounds());
|
||||
flushState->bindTextures(fTessellationProgram->geomProc(), nullptr,
|
||||
fTessellationProgram->pipeline());
|
||||
|
||||
fTessellator->draw(flushState);
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,10 @@
|
||||
#define PathTessellateOp_DEFINED
|
||||
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/PathTessellator.h"
|
||||
#include "src/gpu/tessellate/Tessellation.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
namespace skgpu {
|
||||
|
||||
class PathTessellator;
|
||||
|
||||
};
|
||||
|
||||
namespace skgpu::v1 {
|
||||
|
||||
// Tessellates a path directly to the color buffer, using one single render pass. This currently
|
||||
@ -25,39 +21,54 @@ class PathTessellateOp final : public GrDrawOp {
|
||||
private:
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
PathTessellateOp(const SkMatrix& viewMatrix, const SkPath& path, GrPaint&& paint,
|
||||
GrAAType aaType, const GrUserStencilSettings* stencil,
|
||||
using PathDrawList = PathTessellator::PathDrawList;
|
||||
|
||||
PathTessellateOp(SkArenaAlloc* arena,
|
||||
GrAAType aaType,
|
||||
const GrUserStencilSettings* stencil,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPath& path,
|
||||
GrPaint&& paint,
|
||||
const SkRect& drawBounds)
|
||||
: GrDrawOp(ClassID())
|
||||
, fViewMatrix(viewMatrix)
|
||||
, fPath(path)
|
||||
, fAAType(aaType)
|
||||
, fStencil(stencil)
|
||||
, fColor(paint.getColor4f())
|
||||
, fProcessors(std::move(paint)) {
|
||||
SkASSERT(!fPath.isInverseFillType());
|
||||
, fTotalCombinedPathVerbCnt(path.countVerbs())
|
||||
, fPathDrawList(arena->make<PathDrawList>(SkMatrix::I(), path, paint.getColor4f()))
|
||||
, fPathDrawTail(&fPathDrawList->fNext)
|
||||
, fProcessors(std::move(paint))
|
||||
, fShaderMatrix(viewMatrix) {
|
||||
SkASSERT(!path.isInverseFillType());
|
||||
if (!this->headDraw().fColor.fitsInBytes()) {
|
||||
fPatchAttribs |= PatchAttribs::kWideColorIfEnabled;
|
||||
}
|
||||
this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
|
||||
}
|
||||
|
||||
PathDrawList& headDraw() { return *fPathDrawList; }
|
||||
|
||||
void prepareTessellator(const GrTessellationShader::ProgramArgs&, GrAppliedClip&& clip);
|
||||
|
||||
// GrDrawOp overrides.
|
||||
const char* name() const override { return "PathTessellateOp"; }
|
||||
bool usesMSAA() const override { return fAAType == GrAAType::kMSAA; }
|
||||
void visitProxies(const GrVisitProxyFunc&) const override;
|
||||
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
|
||||
bool usesStencil() const override { return !fStencil->isUnused(); }
|
||||
|
||||
void prepareTessellator(const GrTessellationShader::ProgramArgs&, GrAppliedClip&& clip);
|
||||
|
||||
CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
|
||||
void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
|
||||
const GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override;
|
||||
void onPrepare(GrOpFlushState*) override;
|
||||
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
|
||||
|
||||
const SkMatrix fViewMatrix;
|
||||
const SkPath fPath;
|
||||
const GrAAType fAAType;
|
||||
const GrUserStencilSettings* const fStencil;
|
||||
SkPMColor4f fColor;
|
||||
int fTotalCombinedPathVerbCnt;
|
||||
PatchAttribs fPatchAttribs = PatchAttribs::kNone;
|
||||
PathDrawList* const fPathDrawList;
|
||||
PathDrawList** fPathDrawTail;
|
||||
GrProcessorSet fProcessors;
|
||||
SkMatrix fShaderMatrix;
|
||||
|
||||
// Decided during prepareTessellator.
|
||||
PathTessellator* fTessellator = nullptr;
|
||||
|
@ -165,9 +165,14 @@ bool TessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
|
||||
// Handle convex paths.
|
||||
if (args.fShape->knownToBeConvex() && !path.isInverseFillType()) {
|
||||
auto op = GrOp::Make<PathTessellateOp>(args.fContext, *args.fViewMatrix, path,
|
||||
std::move(args.fPaint), args.fAAType,
|
||||
args.fUserStencilSettings, pathDevBounds);
|
||||
auto op = GrOp::Make<PathTessellateOp>(args.fContext,
|
||||
args.fSurfaceDrawContext->arenaAlloc(),
|
||||
args.fAAType,
|
||||
args.fUserStencilSettings,
|
||||
*args.fViewMatrix,
|
||||
path,
|
||||
std::move(args.fPaint),
|
||||
pathDevBounds);
|
||||
sdc->addDrawOp(args.fClip, std::move(op));
|
||||
return true;
|
||||
}
|
||||
@ -221,8 +226,13 @@ void TessellationPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
||||
|
||||
GrPaint stencilPaint;
|
||||
stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
|
||||
auto op = GrOp::Make<PathTessellateOp>(args.fContext, *args.fViewMatrix, path,
|
||||
std::move(stencilPaint), aaType, &kMarkStencil,
|
||||
auto op = GrOp::Make<PathTessellateOp>(args.fContext,
|
||||
args.fSurfaceDrawContext->arenaAlloc(),
|
||||
aaType,
|
||||
&kMarkStencil,
|
||||
*args.fViewMatrix,
|
||||
path,
|
||||
std::move(stencilPaint),
|
||||
pathDevBounds);
|
||||
sdc->addDrawOp(args.fClip, std::move(op));
|
||||
return;
|
||||
|
@ -28,12 +28,20 @@ public:
|
||||
}
|
||||
|
||||
// Updates the fan point that will be written out with each patch (i.e., the point that wedges
|
||||
// fan around). PathPatchAttrib::kFanPoint must be enabled.
|
||||
// fan around).
|
||||
// PathPatchAttrib::kFanPoint must be enabled.
|
||||
void updateFanPointAttrib(SkPoint fanPoint) {
|
||||
SkASSERT(fPatchAttribs & PatchAttribs::kFanPoint);
|
||||
fFanPointAttrib = fanPoint;
|
||||
}
|
||||
|
||||
// Updates the color that will be written out with each patch.
|
||||
// PathPatchAttrib::kColor must be enabled.
|
||||
void updateColorAttrib(const SkPMColor4f& color) {
|
||||
SkASSERT(fPatchAttribs & PatchAttribs::kColor);
|
||||
fColorAttrib.set(color, fPatchAttribs & PatchAttribs::kWideColorIfEnabled);
|
||||
}
|
||||
|
||||
// RAII. Appends a patch during construction and writes the remaining data for a cubic during
|
||||
// destruction. The caller outputs p0,p1,p2,p3 (8 floats):
|
||||
//
|
||||
@ -122,11 +130,13 @@ private:
|
||||
|
||||
void outputPatchAttribs(VertexWriter vertexWriter, float explicitCurveType) {
|
||||
vertexWriter << If((fPatchAttribs & PatchAttribs::kFanPoint), fFanPointAttrib)
|
||||
<< If((fPatchAttribs & PatchAttribs::kColor), fColorAttrib)
|
||||
<< If((fPatchAttribs & PatchAttribs::kExplicitCurveType), explicitCurveType);
|
||||
}
|
||||
|
||||
const PatchAttribs fPatchAttribs;
|
||||
SkPoint fFanPointAttrib;
|
||||
GrVertexColor fColorAttrib;
|
||||
|
||||
GrVertexChunkBuilder fChunker;
|
||||
|
||||
|
@ -33,22 +33,26 @@ PathCurveTessellator* PathCurveTessellator::Make(SkArenaAlloc* arena,
|
||||
DrawInnerFan drawInnerFan,
|
||||
int numPathVerbs,
|
||||
const GrPipeline& pipeline,
|
||||
const GrCaps& caps) {
|
||||
using PatchType = GrPathTessellationShader::PatchType;
|
||||
const GrCaps& caps,
|
||||
PatchAttribs attribs) {
|
||||
if (!caps.shaderCaps()->infinitySupport()) {
|
||||
attribs |= PatchAttribs::kExplicitCurveType;
|
||||
}
|
||||
GrPathTessellationShader* shader;
|
||||
if (caps.shaderCaps()->tessellationSupport() &&
|
||||
caps.shaderCaps()->infinitySupport() && // The hw tessellation shaders use infinity.
|
||||
!pipeline.usesLocalCoords() && // Our tessellation back door doesn't handle varyings.
|
||||
!(attribs & PatchAttribs::kColor) && // Input color isn't implemented for tessellation.
|
||||
numPathVerbs >= caps.minPathVerbsForHwTessellation()) {
|
||||
shader = GrPathTessellationShader::MakeHardwareTessellationShader(arena, viewMatrix, color,
|
||||
PatchType::kCurves);
|
||||
attribs);
|
||||
} else {
|
||||
shader = GrPathTessellationShader::MakeMiddleOutFixedCountShader(*caps.shaderCaps(), arena,
|
||||
viewMatrix, color,
|
||||
PatchType::kCurves);
|
||||
attribs);
|
||||
}
|
||||
return arena->make([=](void* objStart) {
|
||||
return new(objStart) PathCurveTessellator(shader, drawInnerFan);
|
||||
return new(objStart) PathCurveTessellator(shader, attribs, drawInnerFan);
|
||||
});
|
||||
}
|
||||
|
||||
@ -84,16 +88,15 @@ void PathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
size_t patchStride = fShader->willUseTessellationShaders() ? fShader->vertexStride() * 4
|
||||
: fShader->instanceStride();
|
||||
|
||||
auto attribs = PatchAttribs::kNone;
|
||||
if (!shaderCaps.infinitySupport()) {
|
||||
attribs |= PatchAttribs::kExplicitCurveType;
|
||||
}
|
||||
PatchWriter patchWriter(target, &fVertexChunkArray, patchStride, patchAllocCount, attribs);
|
||||
PatchWriter patchWriter(target, &fVertexChunkArray, patchStride, patchAllocCount, fAttribs);
|
||||
|
||||
// Write out inner fan triangles.
|
||||
if (fDrawInnerFan) {
|
||||
for (auto [pathMatrix, path] : pathDrawList) {
|
||||
for (auto [pathMatrix, path, color] : pathDrawList) {
|
||||
AffineMatrix m(pathMatrix);
|
||||
if (fAttribs & PatchAttribs::kColor) {
|
||||
patchWriter.updateColorAttrib(color);
|
||||
}
|
||||
for (PathMiddleOutFanIter it(path); !it.done();) {
|
||||
for (auto [p0, p1, p2] : it.nextStack()) {
|
||||
TrianglePatch(patchWriter) << m.map2Points(p0, p1) << m.mapPoint(p2);
|
||||
@ -106,14 +109,18 @@ void PathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
if (breadcrumbTriangleList) {
|
||||
SkDEBUGCODE(int count = 0;)
|
||||
#ifdef SK_DEBUG
|
||||
for (auto [pathMatrix, path] : pathDrawList) {
|
||||
// This assert isn't actually necessary, but we currently only use breadcrumb
|
||||
// triangles with an identity pathMatrix. If that ever changes, this assert will
|
||||
// serve as a gentle reminder to make sure the breadcrumb triangles are also
|
||||
for (auto [pathMatrix, path, color] : pathDrawList) {
|
||||
// This assert isn't actually necessary, but we currently only use breadcrumb triangles
|
||||
// with an identity pathMatrix and transparent color. If that ever changes, this assert
|
||||
// will serve as a gentle reminder to make sure the breadcrumb triangles are also
|
||||
// transformed on the CPU.
|
||||
SkASSERT(pathMatrix.isIdentity());
|
||||
SkASSERT(color == SK_PMColor4fTRANSPARENT);
|
||||
}
|
||||
#endif
|
||||
if (fAttribs & PatchAttribs::kColor) {
|
||||
patchWriter.updateColorAttrib(SK_PMColor4fTRANSPARENT);
|
||||
}
|
||||
for (const auto* tri = breadcrumbTriangleList->head(); tri; tri = tri->fNext) {
|
||||
SkDEBUGCODE(++count;)
|
||||
auto p0 = float2::Load(tri->fPts);
|
||||
@ -149,9 +156,12 @@ void PathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
// emit at least 2 segments so we can support triangles.
|
||||
float numFixedSegments_pow4 = 2*2*2*2;
|
||||
|
||||
for (auto [pathMatrix, path] : pathDrawList) {
|
||||
for (auto [pathMatrix, path, color] : pathDrawList) {
|
||||
AffineMatrix m(pathMatrix);
|
||||
wangs_formula::VectorXform totalXform(SkMatrix::Concat(fShader->viewMatrix(), pathMatrix));
|
||||
if (fAttribs & PatchAttribs::kColor) {
|
||||
patchWriter.updateColorAttrib(color);
|
||||
}
|
||||
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
||||
switch (verb) {
|
||||
case SkPathVerb::kQuad: {
|
||||
|
@ -36,7 +36,8 @@ public:
|
||||
DrawInnerFan,
|
||||
int numPathVerbs,
|
||||
const GrPipeline&,
|
||||
const GrCaps&);
|
||||
const GrCaps&,
|
||||
PatchAttribs = PatchAttribs::kNone);
|
||||
|
||||
void prepare(GrMeshDrawTarget* target,
|
||||
const PathDrawList& pathDrawList,
|
||||
@ -64,8 +65,10 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
PathCurveTessellator(GrPathTessellationShader* shader, DrawInnerFan drawInnerFan)
|
||||
: PathTessellator(shader)
|
||||
PathCurveTessellator(GrPathTessellationShader* shader,
|
||||
PatchAttribs attribs,
|
||||
DrawInnerFan drawInnerFan)
|
||||
: PathTessellator(shader, attribs)
|
||||
, fDrawInnerFan(drawInnerFan == DrawInnerFan::kYes) {}
|
||||
|
||||
const bool fDrawInnerFan;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "src/gpu/BufferWriter.h"
|
||||
#include "src/gpu/GrVx.h"
|
||||
#include "src/gpu/geometry/GrInnerFanTriangulator.h"
|
||||
#include "src/gpu/tessellate/Tessellation.h"
|
||||
|
||||
class SkPath;
|
||||
class GrMeshDrawTarget;
|
||||
@ -28,18 +29,22 @@ public:
|
||||
using BreadcrumbTriangleList = GrInnerFanTriangulator::BreadcrumbTriangleList;
|
||||
|
||||
struct PathDrawList {
|
||||
PathDrawList(const SkMatrix& pathMatrix, const SkPath& path, PathDrawList* next = nullptr)
|
||||
: fPathMatrix(pathMatrix), fPath(path), fNext(next) {}
|
||||
PathDrawList(const SkMatrix& pathMatrix,
|
||||
const SkPath& path,
|
||||
const SkPMColor4f& color,
|
||||
PathDrawList* next = nullptr)
|
||||
: fPathMatrix(pathMatrix), fPath(path), fColor(color), fNext(next) {}
|
||||
|
||||
SkMatrix fPathMatrix;
|
||||
SkPath fPath;
|
||||
SkPMColor4f fColor;
|
||||
PathDrawList* fNext;
|
||||
|
||||
struct Iter {
|
||||
void operator++() { fHead = fHead->fNext; }
|
||||
bool operator!=(const Iter& b) const { return fHead != b.fHead; }
|
||||
std::tuple<const SkMatrix&, const SkPath&> operator*() const {
|
||||
return {fHead->fPathMatrix, fHead->fPath};
|
||||
std::tuple<const SkMatrix&, const SkPath&, const SkPMColor4f&> operator*() const {
|
||||
return {fHead->fPathMatrix, fHead->fPath, fHead->fColor};
|
||||
}
|
||||
const PathDrawList* fHead;
|
||||
};
|
||||
@ -74,9 +79,11 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
PathTessellator(GrPathTessellationShader* shader) : fShader(shader) {}
|
||||
PathTessellator(GrPathTessellationShader* shader, PatchAttribs attribs)
|
||||
: fShader(shader), fAttribs(attribs) {}
|
||||
|
||||
GrPathTessellationShader* fShader;
|
||||
GrPathTessellationShader* const fShader;
|
||||
const PatchAttribs fAttribs;
|
||||
};
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -133,22 +133,27 @@ PathTessellator* PathWedgeTessellator::Make(SkArenaAlloc* arena,
|
||||
const SkPMColor4f& color,
|
||||
int numPathVerbs,
|
||||
const GrPipeline& pipeline,
|
||||
const GrCaps& caps) {
|
||||
using PatchType = GrPathTessellationShader::PatchType;
|
||||
const GrCaps& caps,
|
||||
PatchAttribs attribs) {
|
||||
GrPathTessellationShader* shader;
|
||||
attribs |= PatchAttribs::kFanPoint;
|
||||
if (!caps.shaderCaps()->infinitySupport()) {
|
||||
attribs |= PatchAttribs::kExplicitCurveType;
|
||||
}
|
||||
if (caps.shaderCaps()->tessellationSupport() &&
|
||||
caps.shaderCaps()->infinitySupport() && // The hw tessellation shaders use infinity.
|
||||
!pipeline.usesLocalCoords() && // Our tessellation back door doesn't handle varyings.
|
||||
!(attribs & PatchAttribs::kColor) && // Input color isn't implemented for tessellation.
|
||||
numPathVerbs >= caps.minPathVerbsForHwTessellation()) {
|
||||
shader = GrPathTessellationShader::MakeHardwareTessellationShader(arena, viewMatrix, color,
|
||||
PatchType::kWedges);
|
||||
attribs);
|
||||
} else {
|
||||
shader = GrPathTessellationShader::MakeMiddleOutFixedCountShader(*caps.shaderCaps(), arena,
|
||||
viewMatrix, color,
|
||||
PatchType::kWedges);
|
||||
attribs);
|
||||
}
|
||||
return arena->make([=](void* objStart) {
|
||||
return new(objStart) PathWedgeTessellator(shader);
|
||||
return new(objStart) PathWedgeTessellator(shader, attribs);
|
||||
});
|
||||
}
|
||||
|
||||
@ -171,11 +176,7 @@ void PathWedgeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
size_t patchStride = fShader->willUseTessellationShaders() ? fShader->vertexStride() * 5
|
||||
: fShader->instanceStride();
|
||||
|
||||
auto attribs = PatchAttribs::kFanPoint;
|
||||
if (!shaderCaps.infinitySupport()) {
|
||||
attribs |= PatchAttribs::kExplicitCurveType;
|
||||
}
|
||||
PatchWriter patchWriter(target, &fVertexChunkArray, patchStride, wedgeAllocCount, attribs);
|
||||
PatchWriter patchWriter(target, &fVertexChunkArray, patchStride, wedgeAllocCount, fAttribs);
|
||||
|
||||
int maxFixedCountResolveLevel = GrPathTessellationShader::kMaxFixedCountResolveLevel;
|
||||
int maxSegments;
|
||||
@ -191,9 +192,12 @@ void PathWedgeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
// emit at least 1 segment.
|
||||
float numFixedSegments_pow4 = 1;
|
||||
|
||||
for (auto [pathMatrix, path] : pathDrawList) {
|
||||
for (auto [pathMatrix, path, color] : pathDrawList) {
|
||||
AffineMatrix m(pathMatrix);
|
||||
wangs_formula::VectorXform totalXform(SkMatrix::Concat(fShader->viewMatrix(), pathMatrix));
|
||||
if (fAttribs & PatchAttribs::kColor) {
|
||||
patchWriter.updateColorAttrib(color);
|
||||
}
|
||||
MidpointContourParser parser(path);
|
||||
while (parser.parseNextContour()) {
|
||||
patchWriter.updateFanPointAttrib(m.mapPoint(parser.currentMidpoint()));
|
||||
|
@ -29,7 +29,8 @@ public:
|
||||
const SkPMColor4f&,
|
||||
int numPathVerbs,
|
||||
const GrPipeline&,
|
||||
const GrCaps&);
|
||||
const GrCaps&,
|
||||
PatchAttribs = PatchAttribs::kNone);
|
||||
|
||||
void prepare(GrMeshDrawTarget*, const PathDrawList&, int totalCombinedPathVerbCnt) override;
|
||||
|
||||
@ -39,7 +40,8 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
PathWedgeTessellator(GrPathTessellationShader* shader) : PathTessellator(shader) {}
|
||||
PathWedgeTessellator(GrPathTessellationShader* shader, PatchAttribs attribs)
|
||||
: PathTessellator(shader, attribs) {}
|
||||
|
||||
GrVertexChunkArray fVertexChunkArray;
|
||||
|
||||
|
@ -23,11 +23,17 @@ struct VertexWriter;
|
||||
// Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve.
|
||||
SK_MAYBE_UNUSED constexpr static float kTessellationPrecision = 4;
|
||||
|
||||
// Optional attribs that are included in tessellation patches, following the control points.
|
||||
// Optional attribs that are included in tessellation patches, following the control points and in
|
||||
// the same order as they appear here.
|
||||
enum class PatchAttribs {
|
||||
// Attribs.
|
||||
kNone = 0,
|
||||
kFanPoint = 1, // Used by wedges. This is the center point the wedges fan around.
|
||||
kExplicitCurveType = 1 << 1, // Used when the GPU can't infer curve type based on infinity.
|
||||
kFanPoint = 1 << 0, // [float2] Used by wedges. This is the center point the wedges fan around.
|
||||
kColor = 1 << 1, // [ubyte4 or float4] Used by direct-rendered convex paths.
|
||||
kExplicitCurveType = 1 << 2, // [float] Used when GPU can't infer curve type based on infinity.
|
||||
|
||||
// Extra flags.
|
||||
kWideColorIfEnabled = 1 << 3, // If kColor is set, specifies it to be float4 wide color.
|
||||
};
|
||||
|
||||
GR_MAKE_BITFIELD_CLASS_OPS(PatchAttribs)
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
||||
|
||||
using skgpu::PatchAttribs;
|
||||
|
||||
namespace {
|
||||
|
||||
// Draws a simple array of triangles.
|
||||
@ -19,7 +21,8 @@ class SimpleTriangleShader : public GrPathTessellationShader {
|
||||
public:
|
||||
SimpleTriangleShader(const SkMatrix& viewMatrix, SkPMColor4f color)
|
||||
: GrPathTessellationShader(kTessellate_SimpleTriangleShader_ClassID,
|
||||
GrPrimitiveType::kTriangles, 0, viewMatrix, color) {
|
||||
GrPrimitiveType::kTriangles, 0, viewMatrix, color,
|
||||
PatchAttribs::kNone) {
|
||||
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
|
||||
kFloat2_GrSLType};
|
||||
this->setVertexAttributes(&kInputPointAttrib, 1);
|
||||
@ -34,8 +37,11 @@ private:
|
||||
std::unique_ptr<GrGeometryProcessor::ProgramImpl> SimpleTriangleShader::makeProgramImpl(
|
||||
const GrShaderCaps&) const {
|
||||
class Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(const GrShaderCaps&, const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
|
||||
void emitVertexCode(const GrShaderCaps&,
|
||||
const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v,
|
||||
GrGLSLVaryingHandler*,
|
||||
GrGPArgs* gpArgs) override {
|
||||
v->codeAppend(R"(
|
||||
float2 localcoord = inputPoint;
|
||||
float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
|
||||
@ -97,23 +103,34 @@ void GrPathTessellationShader::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs
|
||||
kFloat2_GrSLType, "translate", &translate);
|
||||
args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);", affineMatrix);
|
||||
args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;", translate);
|
||||
this->emitVertexCode(*args.fShaderCaps, shader, args.fVertBuilder, gpArgs);
|
||||
this->emitVertexCode(*args.fShaderCaps,
|
||||
shader,
|
||||
args.fVertBuilder,
|
||||
args.fVaryingHandler,
|
||||
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);
|
||||
if (!(shader.fAttribs & PatchAttribs::kColor)) {
|
||||
const char* color;
|
||||
fColorUniform = args.fUniformHandler->addUniform(nullptr, kFragment_GrShaderFlag,
|
||||
kHalf4_GrSLType, "color", &color);
|
||||
args.fFragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, color);
|
||||
} else {
|
||||
args.fFragBuilder->codeAppendf("half4 %s = %s;",
|
||||
args.fOutputColor, fVaryingColorName.c_str());
|
||||
}
|
||||
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 auto& shader = geomProc.cast<GrPathTessellationShader>();
|
||||
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);
|
||||
if (!(shader.fAttribs & PatchAttribs::kColor)) {
|
||||
const SkPMColor4f& color = shader.color();
|
||||
pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef GrPathTessellationShader_DEFINED
|
||||
#define GrPathTessellationShader_DEFINED
|
||||
|
||||
#include "src/gpu/tessellate/Tessellation.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
// This is the base class for shaders in the GPU tessellator that fill paths.
|
||||
@ -28,14 +29,6 @@ public:
|
||||
return (1 << resolveLevel) - 1;
|
||||
}
|
||||
|
||||
enum class PatchType : bool {
|
||||
// An ice cream cone shaped patch, with 4 curve control points on top of a triangle that
|
||||
// fans from a 5th point at the center of the contour. (5 points per patch.)
|
||||
kWedges,
|
||||
// A standalone closed curve made up 4 control points. (4 points per patch.)
|
||||
kCurves
|
||||
};
|
||||
|
||||
// Uses instanced draws to triangulate curves with a "middle-out" topology. Middle-out draws a
|
||||
// triangle with vertices at T=[0, 1/2, 1] and then recurses breadth first:
|
||||
//
|
||||
@ -48,10 +41,14 @@ public:
|
||||
// smoothly, and emits empty triangles at any vertices whose sk_VertexIDs are higher than
|
||||
// necessary. It is the caller's responsibility to draw enough vertices per instance for the
|
||||
// most complex curve in the batch to render smoothly (i.e., NumTrianglesAtResolveLevel() * 3).
|
||||
//
|
||||
// If PatchAttribs::kFanPoint is set, an additional triangle is added, connecting the base of
|
||||
// the curve to the fan point.
|
||||
static GrPathTessellationShader* MakeMiddleOutFixedCountShader(const GrShaderCaps&,
|
||||
SkArenaAlloc*,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f&, PatchType);
|
||||
const SkPMColor4f&,
|
||||
skgpu::PatchAttribs);
|
||||
|
||||
// This is the largest number of segments the middle-out shader will accept in a single
|
||||
// instance. If a curve requires more segments, it needs to be chopped.
|
||||
@ -63,9 +60,6 @@ public:
|
||||
// the middle-out fixed count shader. The data sequence is identical for any length of
|
||||
// tessellation segments, so the caller can use them with any instance length (up to
|
||||
// kMaxFixedCountResolveLevel).
|
||||
//
|
||||
// The "curve" and "wedge" buffers are nearly identical, but we keep them separate for now in
|
||||
// case there is a perf hit in the curve case for not using index 0.
|
||||
constexpr static int SizeOfVertexBufferForMiddleOutCurves() {
|
||||
constexpr int kMaxVertexCount = (1 << kMaxFixedCountResolveLevel) + 1;
|
||||
return kMaxVertexCount * kMiddleOutVertexStride;
|
||||
@ -89,12 +83,14 @@ public:
|
||||
}
|
||||
static void InitializeIndexBufferForMiddleOutWedges(skgpu::VertexWriter, size_t bufferSize);
|
||||
|
||||
// Uses GPU tessellation shaders to linearize, triangulate, and render cubic "wedge" patches. A
|
||||
// wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning
|
||||
// from the center of the curve's resident contour.
|
||||
// Uses GPU tessellation shaders to linearize, triangulate, and render curves.
|
||||
//
|
||||
// If PatchAttribs::kFanPoint is set, an additional triangle is added, connecting the base of
|
||||
// the curve to the fan point.
|
||||
static GrPathTessellationShader* MakeHardwareTessellationShader(SkArenaAlloc*,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f&, PatchType);
|
||||
const SkPMColor4f&,
|
||||
skgpu::PatchAttribs);
|
||||
|
||||
// Returns the stencil settings to use for a standard Redbook "stencil" pass.
|
||||
static const GrUserStencilSettings* StencilPathSettings(GrFillRule fillRule) {
|
||||
@ -162,9 +158,10 @@ protected:
|
||||
|
||||
GrPathTessellationShader(ClassID classID, GrPrimitiveType primitiveType,
|
||||
int tessellationPatchVertexCount, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color)
|
||||
const SkPMColor4f& color, skgpu::PatchAttribs attribs)
|
||||
: GrTessellationShader(classID, primitiveType, tessellationPatchVertexCount, viewMatrix,
|
||||
color) {
|
||||
color)
|
||||
, fAttribs(attribs) {
|
||||
}
|
||||
|
||||
// Default path tessellation shader implementation that manages a uniform matrix and color.
|
||||
@ -183,13 +180,19 @@ protected:
|
||||
// does not always.
|
||||
static const char* kEvalRationalCubicFn;
|
||||
|
||||
virtual void emitVertexCode(const GrShaderCaps&, const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder*, GrGPArgs*) = 0;
|
||||
virtual void emitVertexCode(const GrShaderCaps&,
|
||||
const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder*,
|
||||
GrGLSLVaryingHandler*,
|
||||
GrGPArgs*) = 0;
|
||||
|
||||
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
|
||||
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
|
||||
GrGLSLUniformHandler::UniformHandle fColorUniform;
|
||||
SkString fVaryingColorName;
|
||||
};
|
||||
|
||||
const skgpu::PatchAttribs fAttribs;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "src/gpu/tessellate/Tessellation.h"
|
||||
#include "src/gpu/tessellate/WangsFormula.h"
|
||||
|
||||
using skgpu::PatchAttribs;
|
||||
|
||||
namespace {
|
||||
|
||||
// Converts keywords from shared SkSL strings to native GLSL keywords.
|
||||
@ -30,9 +32,11 @@ constexpr static char kSkSLTypeDefs[] = R"(
|
||||
// TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
|
||||
class HardwareWedgeShader : public GrPathTessellationShader {
|
||||
public:
|
||||
HardwareWedgeShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
|
||||
HardwareWedgeShader(const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
PatchAttribs attribs)
|
||||
: GrPathTessellationShader(kTessellate_HardwareWedgeShader_ClassID,
|
||||
GrPrimitiveType::kPatches, 5, viewMatrix, color) {
|
||||
GrPrimitiveType::kPatches, 5, viewMatrix, color, attribs) {
|
||||
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
|
||||
kFloat2_GrSLType};
|
||||
this->setVertexAttributes(&kInputPointAttrib, 1);
|
||||
@ -47,8 +51,11 @@ private:
|
||||
std::unique_ptr<GrGeometryProcessor::ProgramImpl> HardwareWedgeShader::makeProgramImpl(
|
||||
const GrShaderCaps&) const {
|
||||
class Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(const GrShaderCaps&, const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v, GrGPArgs*) override {
|
||||
void emitVertexCode(const GrShaderCaps&,
|
||||
const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v,
|
||||
GrGLSLVaryingHandler*,
|
||||
GrGPArgs*) override {
|
||||
v->declareGlobal(GrShaderVar("vsPt", kFloat2_GrSLType, GrShaderVar::TypeModifier::Out));
|
||||
v->codeAppend(R"(
|
||||
// If y is infinity then x is a conic weight. Don't transform.
|
||||
@ -159,9 +166,12 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> HardwareWedgeShader::makeProgr
|
||||
// TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics.
|
||||
class HardwareCurveShader : public GrPathTessellationShader {
|
||||
public:
|
||||
HardwareCurveShader(const SkMatrix& viewMatrix, const SkPMColor4f& color)
|
||||
HardwareCurveShader(const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
PatchAttribs attribs)
|
||||
: GrPathTessellationShader(kTessellate_HardwareCurveShader_ClassID,
|
||||
GrPrimitiveType::kPatches, 4, viewMatrix, color) {
|
||||
GrPrimitiveType::kPatches, 4, viewMatrix, color,
|
||||
attribs) {
|
||||
constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
|
||||
kFloat2_GrSLType};
|
||||
this->setVertexAttributes(&kInputPointAttrib, 1);
|
||||
@ -176,8 +186,11 @@ private:
|
||||
std::unique_ptr<GrGeometryProcessor::ProgramImpl> HardwareCurveShader::makeProgramImpl(
|
||||
const GrShaderCaps&) const {
|
||||
class Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(const GrShaderCaps&, const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v, GrGPArgs*) override {
|
||||
void emitVertexCode(const GrShaderCaps&,
|
||||
const GrPathTessellationShader&,
|
||||
GrGLSLVertexBuilder* v,
|
||||
GrGLSLVaryingHandler*,
|
||||
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.
|
||||
@ -315,12 +328,11 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> HardwareCurveShader::makeProgr
|
||||
|
||||
GrPathTessellationShader* GrPathTessellationShader::MakeHardwareTessellationShader(
|
||||
SkArenaAlloc* arena, const SkMatrix& viewMatrix, const SkPMColor4f& color,
|
||||
PatchType patchType) {
|
||||
switch (patchType) {
|
||||
case PatchType::kWedges:
|
||||
return arena->make<HardwareWedgeShader>(viewMatrix, color);
|
||||
case PatchType::kCurves:
|
||||
return arena->make<HardwareCurveShader>(viewMatrix, color);
|
||||
PatchAttribs attribs) {
|
||||
SkASSERT(!(attribs & PatchAttribs::kColor)); // Not yet implemented.
|
||||
if (attribs & PatchAttribs::kFanPoint) {
|
||||
return arena->make<HardwareWedgeShader>(viewMatrix, color, attribs);
|
||||
} else {
|
||||
return arena->make<HardwareCurveShader>(viewMatrix, color, attribs);
|
||||
}
|
||||
SkUNREACHABLE;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "src/gpu/tessellate/Tessellation.h"
|
||||
#include "src/gpu/tessellate/WangsFormula.h"
|
||||
|
||||
using skgpu::PatchAttribs;
|
||||
using skgpu::VertexWriter;
|
||||
|
||||
namespace {
|
||||
@ -31,16 +32,24 @@ namespace {
|
||||
class MiddleOutShader : public GrPathTessellationShader {
|
||||
public:
|
||||
MiddleOutShader(const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color, PatchType patchType)
|
||||
const SkPMColor4f& color, PatchAttribs attribs)
|
||||
: GrPathTessellationShader(kTessellate_MiddleOutShader_ClassID,
|
||||
GrPrimitiveType::kTriangles, 0, viewMatrix, color)
|
||||
, fPatchType(patchType) {
|
||||
GrPrimitiveType::kTriangles, 0, viewMatrix, color, attribs) {
|
||||
fInstanceAttribs.emplace_back("p01", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
|
||||
fInstanceAttribs.emplace_back("p23", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
|
||||
if (fPatchType == PatchType::kWedges) {
|
||||
fInstanceAttribs.emplace_back("fanPoint", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
|
||||
if (fAttribs & PatchAttribs::kFanPoint) {
|
||||
fInstanceAttribs.emplace_back("fanPointAttrib",
|
||||
kFloat2_GrVertexAttribType,
|
||||
kFloat2_GrSLType);
|
||||
}
|
||||
if (!shaderCaps.infinitySupport()) {
|
||||
if (fAttribs & PatchAttribs::kColor) {
|
||||
fInstanceAttribs.emplace_back("colorAttrib",
|
||||
(fAttribs & PatchAttribs::kWideColorIfEnabled)
|
||||
? kFloat4_GrVertexAttribType
|
||||
: kUByte4_norm_GrVertexAttribType,
|
||||
kHalf4_GrSLType);
|
||||
}
|
||||
if (fAttribs & PatchAttribs::kExplicitCurveType) {
|
||||
// A conic curve is written out with p3=[w,Infinity], but GPUs that don't support
|
||||
// infinity can't detect this. On these platforms we also write out an extra float with
|
||||
// each patch that explicitly tells the shader what type of curve it is.
|
||||
@ -57,35 +66,43 @@ public:
|
||||
private:
|
||||
const char* name() const final { return "tessellate_MiddleOutShader"; }
|
||||
void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
|
||||
b->add32((uint32_t)fPatchType);
|
||||
// When color is in a uniform, it's always wide so we need to ignore kWideColorIfEnabled.
|
||||
// When color is in an attrib, its wideness is accounted for as part of the attrib key in
|
||||
// GrGeometryProcessor::getAttributeKey().
|
||||
// Either way, we get the correct key by ignoring .
|
||||
b->add32((uint32_t)(fAttribs & ~PatchAttribs::kWideColorIfEnabled));
|
||||
}
|
||||
std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
|
||||
const PatchType fPatchType;
|
||||
|
||||
constexpr static int kMaxInstanceAttribCount = 4;
|
||||
constexpr static int kMaxInstanceAttribCount = 5;
|
||||
SkSTArray<kMaxInstanceAttribCount, Attribute> fInstanceAttribs;
|
||||
};
|
||||
|
||||
std::unique_ptr<GrGeometryProcessor::ProgramImpl> MiddleOutShader::makeProgramImpl(
|
||||
const GrShaderCaps&) const {
|
||||
class Impl : public GrPathTessellationShader::Impl {
|
||||
void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader& shader,
|
||||
GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
|
||||
void emitVertexCode(const GrShaderCaps& shaderCaps,
|
||||
const GrPathTessellationShader& shader,
|
||||
GrGLSLVertexBuilder* v,
|
||||
GrGLSLVaryingHandler* varyingHandler,
|
||||
GrGPArgs* gpArgs) override {
|
||||
const MiddleOutShader& middleOutShader = shader.cast<MiddleOutShader>();
|
||||
v->defineConstant("PRECISION", skgpu::kTessellationPrecision);
|
||||
v->defineConstant("MAX_FIXED_RESOLVE_LEVEL", (float)kMaxFixedCountResolveLevel);
|
||||
v->defineConstant("MAX_FIXED_SEGMENTS", (float)kMaxFixedCountSegments);
|
||||
v->insertFunction(skgpu::wangs_formula::as_sksl().c_str());
|
||||
if (shaderCaps.infinitySupport()) {
|
||||
v->insertFunction(R"(
|
||||
bool is_conic_curve() { return isinf(p23.w); }
|
||||
bool is_triangular_conic_curve() { return isinf(p23.z); })");
|
||||
} else {
|
||||
if (middleOutShader.fAttribs & PatchAttribs::kExplicitCurveType) {
|
||||
v->insertFunction(SkStringPrintf(R"(
|
||||
bool is_conic_curve() { return curveType != %g; })", kCubicCurveType).c_str());
|
||||
v->insertFunction(SkStringPrintf(R"(
|
||||
bool is_triangular_conic_curve() {
|
||||
return curveType == %g;
|
||||
})", kTriangularConicCurveType).c_str());
|
||||
} else {
|
||||
SkASSERT(shaderCaps.infinitySupport());
|
||||
v->insertFunction(R"(
|
||||
bool is_conic_curve() { return isinf(p23.w); }
|
||||
bool is_triangular_conic_curve() { return isinf(p23.z); })");
|
||||
}
|
||||
if (shaderCaps.bitManipulationSupport()) {
|
||||
v->insertFunction(R"(
|
||||
@ -102,11 +119,11 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> MiddleOutShader::makeProgramIm
|
||||
float resolveLevel = resolveLevel_and_idx.x;
|
||||
float idxInResolveLevel = resolveLevel_and_idx.y;
|
||||
float2 localcoord;)");
|
||||
if (shader.cast<MiddleOutShader>().fPatchType == PatchType::kWedges) {
|
||||
if (middleOutShader.fAttribs & PatchAttribs::kFanPoint) {
|
||||
v->codeAppend(R"(
|
||||
// A negative resolve level means this is the fan point.
|
||||
if (resolveLevel < 0) {
|
||||
localcoord = fanPoint;
|
||||
localcoord = fanPointAttrib;
|
||||
} else)"); // Fall through to next if ().
|
||||
}
|
||||
v->codeAppend(R"(
|
||||
@ -169,6 +186,14 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> MiddleOutShader::makeProgramIm
|
||||
float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
|
||||
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
|
||||
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
|
||||
if (middleOutShader.fAttribs & PatchAttribs::kColor) {
|
||||
GrGLSLVarying colorVarying(GrSLType::kHalf4_GrSLType);
|
||||
varyingHandler->addVarying("color",
|
||||
&colorVarying,
|
||||
GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
|
||||
v->codeAppendf("%s = colorAttrib;", colorVarying.vsOut());
|
||||
fVaryingColorName = colorVarying.fsIn();
|
||||
}
|
||||
}
|
||||
};
|
||||
return std::make_unique<Impl>();
|
||||
@ -178,8 +203,8 @@ std::unique_ptr<GrGeometryProcessor::ProgramImpl> MiddleOutShader::makeProgramIm
|
||||
|
||||
GrPathTessellationShader* GrPathTessellationShader::MakeMiddleOutFixedCountShader(
|
||||
const GrShaderCaps& shaderCaps, SkArenaAlloc* arena, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color, PatchType patchType) {
|
||||
return arena->make<MiddleOutShader>(shaderCaps, viewMatrix, color, patchType);
|
||||
const SkPMColor4f& color, PatchAttribs attribs) {
|
||||
return arena->make<MiddleOutShader>(shaderCaps, viewMatrix, color, attribs);
|
||||
}
|
||||
|
||||
void GrPathTessellationShader::InitializeVertexBufferForMiddleOutCurves(VertexWriter vertexWriter,
|
||||
|
Loading…
Reference in New Issue
Block a user