Create an skgpu::tess namespace
This is just a bunch of renaming, and for now the tessellate/shaders directory remains untouched. The next steps will be to clean up and remove all Ganesh v1 dependencies from tessellation. Bug: skia:12524 Change-Id: I8cc166c0c78f9fb160de807131fa53fcc0765818 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/458876 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
a9b48583bc
commit
0de8a96a72
@ -12,11 +12,11 @@
|
||||
#include "src/gpu/GrDirectContextPriv.h"
|
||||
#include "src/gpu/geometry/GrWangsFormula.h"
|
||||
#include "src/gpu/mock/GrMockOpTarget.h"
|
||||
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/GrStrokeFixedCountTessellator.h"
|
||||
#include "src/gpu/tessellate/GrStrokeHardwareTessellator.h"
|
||||
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/PathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/PathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeFixedCountTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeHardwareTessellator.h"
|
||||
#include "tools/ToolUtils.h"
|
||||
#include <vector>
|
||||
|
||||
@ -119,10 +119,14 @@ DEF_PATH_TESS_BENCH(GrPathCurveTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
SkArenaAlloc arena(1024);
|
||||
GrPipeline noVaryingsPipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
|
||||
GrSwizzle::RGBA());
|
||||
auto tess = GrPathCurveTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT,
|
||||
GrPathCurveTessellator::DrawInnerFan::kNo,
|
||||
fTarget->caps().minPathVerbsForHwTessellation(),
|
||||
noVaryingsPipeline, fTarget->caps());
|
||||
auto tess = skgpu::tess::PathCurveTessellator::Make(
|
||||
&arena,
|
||||
fMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
skgpu::tess::PathCurveTessellator::DrawInnerFan::kNo,
|
||||
fTarget->caps().minPathVerbsForHwTessellation(),
|
||||
noVaryingsPipeline,
|
||||
fTarget->caps());
|
||||
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), {gAlmostIdentity, fPath},
|
||||
fPath.countVerbs());
|
||||
}
|
||||
@ -131,16 +135,20 @@ DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
|
||||
SkArenaAlloc arena(1024);
|
||||
GrPipeline noVaryingsPipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
|
||||
GrSwizzle::RGBA());
|
||||
auto tess = GrPathWedgeTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT,
|
||||
fTarget->caps().minPathVerbsForHwTessellation(),
|
||||
noVaryingsPipeline, fTarget->caps());
|
||||
auto tess = skgpu::tess::PathWedgeTessellator::Make(
|
||||
&arena,
|
||||
fMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
fTarget->caps().minPathVerbsForHwTessellation(),
|
||||
noVaryingsPipeline,
|
||||
fTarget->caps());
|
||||
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), {gAlmostIdentity, fPath},
|
||||
fPath.countVerbs());
|
||||
}
|
||||
|
||||
static void benchmark_wangs_formula_cubic_log2(const SkMatrix& matrix, const SkPath& path) {
|
||||
int sum = 0;
|
||||
GrVectorXform xform(matrix);
|
||||
skgpu::tess::VectorXform xform(matrix);
|
||||
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
||||
if (verb == SkPathVerb::kCubic) {
|
||||
sum += GrWangsFormula::cubic_log2(4, pts, xform);
|
||||
@ -168,7 +176,7 @@ DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_affine, make_cubic_path(18),
|
||||
|
||||
static void benchmark_wangs_formula_conic(const SkMatrix& matrix, const SkPath& path) {
|
||||
int sum = 0;
|
||||
GrVectorXform xform(matrix);
|
||||
skgpu::tess::VectorXform xform(matrix);
|
||||
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
||||
if (verb == SkPathVerb::kConic) {
|
||||
sum += GrWangsFormula::conic(4, pts, *w, xform);
|
||||
@ -182,7 +190,7 @@ static void benchmark_wangs_formula_conic(const SkMatrix& matrix, const SkPath&
|
||||
|
||||
static void benchmark_wangs_formula_conic_log2(const SkMatrix& matrix, const SkPath& path) {
|
||||
int sum = 0;
|
||||
GrVectorXform xform(matrix);
|
||||
skgpu::tess::VectorXform xform(matrix);
|
||||
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
||||
if (verb == SkPathVerb::kConic) {
|
||||
sum += GrWangsFormula::conic_log2(4, pts, *w, xform);
|
||||
@ -210,32 +218,40 @@ DEF_PATH_TESS_BENCH(middle_out_triangulation,
|
||||
GrVertexWriter vertexWriter = static_cast<SkPoint*>(fTarget->makeVertexSpace(
|
||||
sizeof(SkPoint), kNumCubicsInChalkboard, &buffer, &baseVertex));
|
||||
int numTrianglesWritten;
|
||||
GrMiddleOutPolygonTriangulator::WritePathInnerFan(std::move(vertexWriter), 0, 0,
|
||||
gAlmostIdentity, fPath, &numTrianglesWritten);
|
||||
skgpu::tess::MiddleOutPolygonTriangulator::WritePathInnerFan(std::move(vertexWriter),
|
||||
0,
|
||||
0,
|
||||
gAlmostIdentity,
|
||||
fPath,
|
||||
&numTrianglesWritten);
|
||||
}
|
||||
|
||||
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
|
||||
using MakeTessellatorFn = std::unique_ptr<GrStrokeTessellator>(*)(ShaderFlags, const GrShaderCaps&,
|
||||
const SkMatrix&, PathStrokeList*,
|
||||
std::array<float, 2>, const
|
||||
SkRect&);
|
||||
using PathStrokeList = skgpu::tess::StrokeTessellator::PathStrokeList;
|
||||
using MakeTessellatorFn = std::unique_ptr<skgpu::tess::StrokeTessellator>(*)(ShaderFlags,
|
||||
const GrShaderCaps&,
|
||||
const SkMatrix&,
|
||||
PathStrokeList*,
|
||||
std::array<float, 2>,
|
||||
const SkRect&);
|
||||
|
||||
static std::unique_ptr<GrStrokeTessellator> make_hw_tessellator(
|
||||
static std::unique_ptr<skgpu::tess::StrokeTessellator> make_hw_tessellator(
|
||||
ShaderFlags shaderFlags, const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList, std::array<float, 2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds) {
|
||||
return std::make_unique<GrStrokeHardwareTessellator>(shaderCaps, shaderFlags, viewMatrix,
|
||||
pathStrokeList, matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
return std::make_unique<skgpu::tess::StrokeHardwareTessellator>(shaderCaps, shaderFlags,
|
||||
viewMatrix, pathStrokeList,
|
||||
matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
}
|
||||
|
||||
static std::unique_ptr<GrStrokeTessellator> make_fixed_count_tessellator(
|
||||
static std::unique_ptr<skgpu::tess::StrokeTessellator> make_fixed_count_tessellator(
|
||||
ShaderFlags shaderFlags, const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList, std::array<float, 2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds) {
|
||||
return std::make_unique<GrStrokeFixedCountTessellator>(shaderCaps, shaderFlags, viewMatrix,
|
||||
pathStrokeList, matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
return std::make_unique<skgpu::tess::StrokeFixedCountTessellator>(shaderCaps, shaderFlags,
|
||||
viewMatrix, pathStrokeList,
|
||||
matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
}
|
||||
|
||||
using MakePathStrokesFn = std::vector<PathStrokeList>(*)();
|
||||
@ -355,7 +371,7 @@ private:
|
||||
float fMatrixScale;
|
||||
std::unique_ptr<GrMockOpTarget> fTarget;
|
||||
std::vector<PathStrokeList> fPathStrokes;
|
||||
std::unique_ptr<GrStrokeTessellator> fTessellator;
|
||||
std::unique_ptr<skgpu::tess::StrokeTessellator> fTessellator;
|
||||
SkArenaAlloc fPersistentArena{1024};
|
||||
int fTotalVerbCount = 0;
|
||||
};
|
||||
|
32
gn/gpu.gni
32
gn/gpu.gni
@ -325,22 +325,22 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/gradients/GrGradientShader.h",
|
||||
|
||||
# tessellate
|
||||
"$_src/gpu/tessellate/GrCullTest.h",
|
||||
"$_src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h",
|
||||
"$_src/gpu/tessellate/GrPathCurveTessellator.cpp",
|
||||
"$_src/gpu/tessellate/GrPathCurveTessellator.h",
|
||||
"$_src/gpu/tessellate/GrPathTessellator.h",
|
||||
"$_src/gpu/tessellate/GrPathWedgeTessellator.cpp",
|
||||
"$_src/gpu/tessellate/GrPathWedgeTessellator.h",
|
||||
"$_src/gpu/tessellate/GrPathXform.h",
|
||||
"$_src/gpu/tessellate/GrStrokeFixedCountTessellator.cpp",
|
||||
"$_src/gpu/tessellate/GrStrokeFixedCountTessellator.h",
|
||||
"$_src/gpu/tessellate/GrStrokeHardwareTessellator.cpp",
|
||||
"$_src/gpu/tessellate/GrStrokeHardwareTessellator.h",
|
||||
"$_src/gpu/tessellate/GrStrokeIterator.h",
|
||||
"$_src/gpu/tessellate/GrStrokeTessellator.h",
|
||||
"$_src/gpu/tessellate/GrTessTypes.h",
|
||||
"$_src/gpu/tessellate/GrVectorXform.h",
|
||||
"$_src/gpu/tessellate/CullTest.h",
|
||||
"$_src/gpu/tessellate/MiddleOutPolygonTriangulator.h",
|
||||
"$_src/gpu/tessellate/PathCurveTessellator.cpp",
|
||||
"$_src/gpu/tessellate/PathCurveTessellator.h",
|
||||
"$_src/gpu/tessellate/PathTessellator.h",
|
||||
"$_src/gpu/tessellate/PathWedgeTessellator.cpp",
|
||||
"$_src/gpu/tessellate/PathWedgeTessellator.h",
|
||||
"$_src/gpu/tessellate/PathXform.h",
|
||||
"$_src/gpu/tessellate/StrokeFixedCountTessellator.cpp",
|
||||
"$_src/gpu/tessellate/StrokeFixedCountTessellator.h",
|
||||
"$_src/gpu/tessellate/StrokeHardwareTessellator.cpp",
|
||||
"$_src/gpu/tessellate/StrokeHardwareTessellator.h",
|
||||
"$_src/gpu/tessellate/StrokeIterator.h",
|
||||
"$_src/gpu/tessellate/StrokeTessellator.h",
|
||||
"$_src/gpu/tessellate/TessTypes.h",
|
||||
"$_src/gpu/tessellate/VectorXform.h",
|
||||
|
||||
# tessellate/shaders
|
||||
"$_src/gpu/tessellate/shaders/GrPathTessellationShader.cpp",
|
||||
|
@ -17,8 +17,8 @@
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
|
||||
#include "src/gpu/ops/TessellationPathRenderer.h"
|
||||
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/PathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/PathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
|
||||
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
|
||||
|
||||
@ -83,28 +83,41 @@ private:
|
||||
auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
|
||||
fPipelineFlags);
|
||||
switch (fMode) {
|
||||
using DrawInnerFan = GrPathCurveTessellator::DrawInnerFan;
|
||||
using DrawInnerFan = skgpu::tess::PathCurveTessellator::DrawInnerFan;
|
||||
case Mode::kWedgeMiddleOut:
|
||||
fTessellator = GrPathWedgeTessellator::Make(alloc, shaderMatrix, kCyan,
|
||||
numVerbsToGetMiddleOut, *pipeline,
|
||||
caps);
|
||||
fTessellator = skgpu::tess::PathWedgeTessellator::Make(alloc,
|
||||
shaderMatrix,
|
||||
kCyan,
|
||||
numVerbsToGetMiddleOut,
|
||||
*pipeline,
|
||||
|
||||
caps);
|
||||
break;
|
||||
case Mode::kCurveMiddleOut:
|
||||
fTessellator = GrPathCurveTessellator::Make(alloc, shaderMatrix, kCyan,
|
||||
DrawInnerFan::kYes,
|
||||
numVerbsToGetMiddleOut, *pipeline,
|
||||
caps);
|
||||
fTessellator = skgpu::tess::PathCurveTessellator::Make(alloc,
|
||||
shaderMatrix,
|
||||
kCyan,
|
||||
DrawInnerFan::kYes,
|
||||
numVerbsToGetMiddleOut,
|
||||
*pipeline,
|
||||
caps);
|
||||
break;
|
||||
case Mode::kWedgeTessellate:
|
||||
fTessellator = GrPathWedgeTessellator::Make(alloc, shaderMatrix, kCyan,
|
||||
numVerbsToGetTessellation, *pipeline,
|
||||
caps);
|
||||
fTessellator = skgpu::tess::PathWedgeTessellator::Make(alloc,
|
||||
shaderMatrix,
|
||||
kCyan,
|
||||
numVerbsToGetTessellation,
|
||||
*pipeline,
|
||||
caps);
|
||||
break;
|
||||
case Mode::kCurveTessellate:
|
||||
fTessellator = GrPathCurveTessellator::Make(alloc, shaderMatrix, kCyan,
|
||||
DrawInnerFan::kYes,
|
||||
numVerbsToGetTessellation, *pipeline,
|
||||
caps);
|
||||
fTessellator = skgpu::tess::PathCurveTessellator::Make(alloc,
|
||||
shaderMatrix,
|
||||
kCyan,
|
||||
DrawInnerFan::kYes,
|
||||
numVerbsToGetTessellation,
|
||||
*pipeline,
|
||||
caps);
|
||||
break;
|
||||
}
|
||||
fTessellator->prepare(flushState, this->bounds(), {pathMatrix, fPath}, fPath.countVerbs());
|
||||
@ -125,7 +138,7 @@ private:
|
||||
const SkMatrix fMatrix;
|
||||
const GrPipeline::InputFlags fPipelineFlags;
|
||||
const Mode fMode;
|
||||
GrPathTessellator* fTessellator = nullptr;
|
||||
skgpu::tess::PathTessellator* fTessellator = nullptr;
|
||||
GrProgramInfo* fProgram;
|
||||
GrProcessorSet fProcessors{SkBlendMode::kSrcOver};
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/private/SkFloatingPoint.h"
|
||||
#include "src/gpu/GrVx.h"
|
||||
#include "src/gpu/tessellate/GrVectorXform.h"
|
||||
#include "src/gpu/tessellate/VectorXform.h"
|
||||
|
||||
// Wang's formula gives the minimum number of evenly spaced (in the parametric sense) line segments
|
||||
// that a bezier curve must be chopped into in order to guarantee all lines stay within a distance
|
||||
@ -26,6 +26,8 @@
|
||||
// to Curves and Surfaces for Geometric Modeling". Morgan Kaufmann Publishers.)
|
||||
namespace GrWangsFormula {
|
||||
|
||||
using skgpu::tess::VectorXform;
|
||||
|
||||
// Returns the value by which to multiply length in Wang's formula. (See above.)
|
||||
template<int Degree> constexpr float length_term(float precision) {
|
||||
return (Degree * (Degree - 1) / 8.f) * precision;
|
||||
@ -56,7 +58,7 @@ SK_ALWAYS_INLINE static int nextlog16(float x) {
|
||||
|
||||
// Returns Wang's formula, raised to the 4th power, specialized for a quadratic curve.
|
||||
SK_ALWAYS_INLINE static float quadratic_pow4(float precision, const SkPoint pts[],
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
using grvx::float2, skvx::bit_pun;
|
||||
float2 p0 = bit_pun<float2>(pts[0]);
|
||||
float2 p1 = bit_pun<float2>(pts[1]);
|
||||
@ -69,21 +71,21 @@ SK_ALWAYS_INLINE static float quadratic_pow4(float precision, const SkPoint pts[
|
||||
|
||||
// Returns Wang's formula specialized for a quadratic curve.
|
||||
SK_ALWAYS_INLINE static float quadratic(float precision, const SkPoint pts[],
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
return root4(quadratic_pow4(precision, pts, vectorXform));
|
||||
}
|
||||
|
||||
// Returns the log2 value of Wang's formula specialized for a quadratic curve, rounded up to the
|
||||
// next int.
|
||||
SK_ALWAYS_INLINE static int quadratic_log2(float precision, const SkPoint pts[],
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
// nextlog16(x) == ceil(log2(sqrt(sqrt(x))))
|
||||
return nextlog16(quadratic_pow4(precision, pts, vectorXform));
|
||||
}
|
||||
|
||||
// Returns Wang's formula, raised to the 4th power, specialized for a cubic curve.
|
||||
SK_ALWAYS_INLINE static float cubic_pow4(float precision, const SkPoint pts[],
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
using grvx::float4;
|
||||
float4 p01 = float4::Load(pts);
|
||||
float4 p12 = float4::Load(pts + 1);
|
||||
@ -96,14 +98,14 @@ SK_ALWAYS_INLINE static float cubic_pow4(float precision, const SkPoint pts[],
|
||||
|
||||
// Returns Wang's formula specialized for a cubic curve.
|
||||
SK_ALWAYS_INLINE static float cubic(float precision, const SkPoint pts[],
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
return root4(cubic_pow4(precision, pts, vectorXform));
|
||||
}
|
||||
|
||||
// Returns the log2 value of Wang's formula specialized for a cubic curve, rounded up to the next
|
||||
// int.
|
||||
SK_ALWAYS_INLINE static int cubic_log2(float precision, const SkPoint pts[],
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
// nextlog16(x) == ceil(log2(sqrt(sqrt(x))))
|
||||
return nextlog16(cubic_pow4(precision, pts, vectorXform));
|
||||
}
|
||||
@ -132,7 +134,7 @@ SK_ALWAYS_INLINE static int worst_case_cubic_log2(float precision, float devWidt
|
||||
// J. Zheng, T. Sederberg. "Estimating Tessellation Parameter Intervals for
|
||||
// Rational Curves and Surfaces." ACM Transactions on Graphics 19(1). 2000.
|
||||
SK_ALWAYS_INLINE static float conic_pow2(float precision, const SkPoint pts[], float w,
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
using grvx::dot, grvx::float2, grvx::float4, skvx::bit_pun;
|
||||
float2 p0 = vectorXform(bit_pun<float2>(pts[0]));
|
||||
float2 p1 = vectorXform(bit_pun<float2>(pts[1]));
|
||||
@ -168,14 +170,14 @@ SK_ALWAYS_INLINE static float conic_pow2(float precision, const SkPoint pts[], f
|
||||
|
||||
// Returns the value of Wang's formula specialized for a conic curve.
|
||||
SK_ALWAYS_INLINE static float conic(float tolerance, const SkPoint pts[], float w,
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
return sqrtf(conic_pow2(tolerance, pts, w, vectorXform));
|
||||
}
|
||||
|
||||
// Returns the log2 value of Wang's formula specialized for a conic curve, rounded up to the next
|
||||
// int.
|
||||
SK_ALWAYS_INLINE static int conic_log2(float tolerance, const SkPoint pts[], float w,
|
||||
const GrVectorXform& vectorXform = GrVectorXform()) {
|
||||
const VectorXform& vectorXform = VectorXform()) {
|
||||
// nextlog4(x) == ceil(log2(sqrt(x)))
|
||||
return nextlog4(conic_pow2(tolerance, pts, w, vectorXform));
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ GrRenderTask::ExpectedOutcome AtlasRenderTask::onMakeClosed(GrRecordingContext*
|
||||
pathList->pathCount(),
|
||||
GrPaint(),
|
||||
GrAAType::kMSAA,
|
||||
GrTessellationPathFlags::kStencilOnly,
|
||||
skgpu::tess::TessellationPathFlags::kStencilOnly,
|
||||
drawRect);
|
||||
this->addAtlasDrawOp(std::move(op), caps);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "src/core/SkTBlockList.h"
|
||||
#include "src/gpu/GrDynamicAtlas.h"
|
||||
#include "src/gpu/ops/OpsTask.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellator.h"
|
||||
#include "src/gpu/tessellate/PathTessellator.h"
|
||||
|
||||
struct SkIPoint16;
|
||||
|
||||
@ -61,7 +61,8 @@ private:
|
||||
const std::unique_ptr<GrDynamicAtlas> fDynamicAtlas;
|
||||
|
||||
// Allocate enough inline entries for 16 atlas path draws, then spill to the heap.
|
||||
using PathDrawAllocator = SkTBlockList<GrPathTessellator::PathDrawList, 16>;
|
||||
using PathDrawList = skgpu::tess::PathTessellator::PathDrawList;
|
||||
using PathDrawAllocator = SkTBlockList<PathDrawList, 16>;
|
||||
PathDrawAllocator fPathDrawAllocator{64, SkBlockAllocator::GrowthPolicy::kFibonacci};
|
||||
|
||||
class AtlasPathList : SkNoncopyable {
|
||||
@ -75,12 +76,12 @@ private:
|
||||
fTotalCombinedPathVerbCnt += path.countVerbs();
|
||||
++fPathCount;
|
||||
}
|
||||
const GrPathTessellator::PathDrawList* pathDrawList() const { return fPathDrawList; }
|
||||
const PathDrawList* pathDrawList() const { return fPathDrawList; }
|
||||
int totalCombinedPathVerbCnt() const { return fTotalCombinedPathVerbCnt; }
|
||||
int pathCount() const { return fPathCount; }
|
||||
|
||||
private:
|
||||
GrPathTessellator::PathDrawList* fPathDrawList = nullptr;
|
||||
PathDrawList* fPathDrawList = nullptr;
|
||||
int fTotalCombinedPathVerbCnt = 0;
|
||||
int fPathCount = 0;
|
||||
};
|
||||
|
@ -13,10 +13,10 @@
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
||||
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/PathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
|
||||
|
||||
using PathFlags = GrTessellationPathFlags;
|
||||
using PathFlags = skgpu::tess::TessellationPathFlags;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -242,11 +242,14 @@ void PathInnerTriangulateOp::prePreparePrograms(const GrTessellationShader::Prog
|
||||
|
||||
// Pass 1: Tessellate the outer curves into the stencil buffer.
|
||||
if (!isLinear) {
|
||||
fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
GrPathCurveTessellator::DrawInnerFan::kNo,
|
||||
fPath.countVerbs(), *pipelineForStencils,
|
||||
*args.fCaps);
|
||||
fTessellator = skgpu::tess::PathCurveTessellator::Make(
|
||||
args.fArena,
|
||||
fViewMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
skgpu::tess::PathCurveTessellator::DrawInnerFan::kNo,
|
||||
fPath.countVerbs(),
|
||||
*pipelineForStencils,
|
||||
*args.fCaps);
|
||||
const GrUserStencilSettings* stencilPathSettings =
|
||||
GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));
|
||||
fStencilCurvesProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
|
||||
|
@ -10,10 +10,14 @@
|
||||
|
||||
#include "src/gpu/geometry/GrInnerFanTriangulator.h"
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/GrTessTypes.h"
|
||||
#include "src/gpu/tessellate/TessTypes.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
class GrPathCurveTessellator;
|
||||
namespace skgpu::tess {
|
||||
|
||||
class PathCurveTessellator;
|
||||
|
||||
};
|
||||
|
||||
namespace skgpu::v1 {
|
||||
|
||||
@ -29,8 +33,11 @@ class PathInnerTriangulateOp final : public GrDrawOp {
|
||||
private:
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
PathInnerTriangulateOp(const SkMatrix& viewMatrix, const SkPath& path, GrPaint&& paint,
|
||||
GrAAType aaType, GrTessellationPathFlags pathFlags,
|
||||
PathInnerTriangulateOp(const SkMatrix& viewMatrix,
|
||||
const SkPath& path,
|
||||
GrPaint&& paint,
|
||||
GrAAType aaType,
|
||||
skgpu::tess::TessellationPathFlags pathFlags,
|
||||
const SkRect& drawBounds)
|
||||
: GrDrawOp(ClassID())
|
||||
, fPathFlags(pathFlags)
|
||||
@ -59,7 +66,7 @@ private:
|
||||
void onPrepare(GrOpFlushState*) override;
|
||||
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
|
||||
|
||||
const GrTessellationPathFlags fPathFlags;
|
||||
const skgpu::tess::TessellationPathFlags fPathFlags;
|
||||
const SkMatrix fViewMatrix;
|
||||
const SkPath fPath;
|
||||
const GrAAType fAAType;
|
||||
@ -75,7 +82,7 @@ private:
|
||||
const GrPipeline* fPipelineForFills = nullptr;
|
||||
|
||||
// Tessellates the outer curves.
|
||||
GrPathCurveTessellator* fTessellator = nullptr;
|
||||
skgpu::tess::PathCurveTessellator* fTessellator = nullptr;
|
||||
|
||||
// Pass 1: Tessellate the outer curves into the stencil buffer.
|
||||
const GrProgramInfo* fStencilCurvesProgram = nullptr;
|
||||
|
@ -16,12 +16,12 @@
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
||||
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
|
||||
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/PathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/PathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
|
||||
|
||||
using PathFlags = GrTessellationPathFlags;
|
||||
using PathFlags = skgpu::tess::TessellationPathFlags;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -154,20 +154,21 @@ void PathStencilCoverOp::prePreparePrograms(const GrTessellationShader::ProgramA
|
||||
shader,
|
||||
stencilPipeline,
|
||||
stencilSettings);
|
||||
fTessellator = GrPathCurveTessellator::Make(args.fArena,
|
||||
shaderMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
GrPathCurveTessellator::DrawInnerFan::kNo,
|
||||
fTotalCombinedPathVerbCnt,
|
||||
*stencilPipeline,
|
||||
*args.fCaps);
|
||||
fTessellator = skgpu::tess::PathCurveTessellator::Make(
|
||||
args.fArena,
|
||||
shaderMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
skgpu::tess::PathCurveTessellator::DrawInnerFan::kNo,
|
||||
fTotalCombinedPathVerbCnt,
|
||||
*stencilPipeline,
|
||||
*args.fCaps);
|
||||
} else {
|
||||
fTessellator = GrPathWedgeTessellator::Make(args.fArena,
|
||||
shaderMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
fTotalCombinedPathVerbCnt,
|
||||
*stencilPipeline,
|
||||
*args.fCaps);
|
||||
fTessellator = skgpu::tess::PathWedgeTessellator::Make(args.fArena,
|
||||
shaderMatrix,
|
||||
SK_PMColor4fTRANSPARENT,
|
||||
fTotalCombinedPathVerbCnt,
|
||||
*stencilPipeline,
|
||||
*args.fCaps);
|
||||
}
|
||||
fStencilPathProgram = GrTessellationShader::MakeProgram(args,
|
||||
fTessellator->shader(),
|
||||
@ -236,8 +237,8 @@ void PathStencilCoverOp::onPrepare(GrOpFlushState* flushState) {
|
||||
// The inner fan isn't built into the tessellator. Generate a standard Redbook fan with a
|
||||
// middle-out topology.
|
||||
GrEagerDynamicVertexAllocator vertexAlloc(flushState, &fFanBuffer, &fFanBaseVertex);
|
||||
int maxCombinedFanEdges =
|
||||
GrPathTessellator::MaxCombinedFanEdgesInPathDrawList(fTotalCombinedPathVerbCnt);
|
||||
int maxCombinedFanEdges = skgpu::tess::PathTessellator::MaxCombinedFanEdgesInPathDrawList(
|
||||
fTotalCombinedPathVerbCnt);
|
||||
// A single n-sided polygon is fanned by n-2 triangles. Multiple polygons with a combined
|
||||
// edge count of n are fanned by strictly fewer triangles.
|
||||
int maxTrianglesInFans = std::max(maxCombinedFanEdges - 2, 0);
|
||||
@ -245,7 +246,7 @@ void PathStencilCoverOp::onPrepare(GrOpFlushState* flushState) {
|
||||
int fanTriangleCount = 0;
|
||||
for (auto [pathMatrix, path] : *fPathDrawList) {
|
||||
int numTrianglesWritten;
|
||||
triangleVertexWriter = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
|
||||
triangleVertexWriter = skgpu::tess::MiddleOutPolygonTriangulator::WritePathInnerFan(
|
||||
std::move(triangleVertexWriter),
|
||||
0,
|
||||
0,
|
||||
|
@ -9,8 +9,8 @@
|
||||
#define PathStencilCoverOp_DEFINED
|
||||
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellator.h"
|
||||
#include "src/gpu/tessellate/GrTessTypes.h"
|
||||
#include "src/gpu/tessellate/PathTessellator.h"
|
||||
#include "src/gpu/tessellate/TessTypes.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
namespace skgpu::v1 {
|
||||
@ -22,7 +22,7 @@ class PathStencilCoverOp final : public GrDrawOp {
|
||||
private:
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
using PathDrawList = GrPathTessellator::PathDrawList;
|
||||
using PathDrawList = skgpu::tess::PathTessellator::PathDrawList;
|
||||
|
||||
// If the path is inverse filled, drawBounds must be the entire backing store dimensions of the
|
||||
// render target.
|
||||
@ -31,7 +31,7 @@ private:
|
||||
const SkPath& path,
|
||||
GrPaint&& paint,
|
||||
GrAAType aaType,
|
||||
GrTessellationPathFlags pathFlags,
|
||||
skgpu::tess::TessellationPathFlags pathFlags,
|
||||
const SkRect& drawBounds)
|
||||
: GrDrawOp(ClassID())
|
||||
, fPathDrawList(arena->make<PathDrawList>(viewMatrix, path))
|
||||
@ -47,13 +47,13 @@ private:
|
||||
|
||||
// Constructs a PathStencilCoverOp from an existing draw list.
|
||||
// FIXME: The only user of this method is the atlas. We should move the GrProgramInfos into
|
||||
// GrPathTessellator so the atlas can use that directly instead of going through this class.
|
||||
// PathTessellator so the atlas can use that directly instead of going through this class.
|
||||
PathStencilCoverOp(const PathDrawList* pathDrawList,
|
||||
int totalCombinedVerbCnt,
|
||||
int pathCount,
|
||||
GrPaint&& paint,
|
||||
GrAAType aaType,
|
||||
GrTessellationPathFlags pathFlags,
|
||||
skgpu::tess::TessellationPathFlags pathFlags,
|
||||
const SkRect& drawBounds)
|
||||
: GrDrawOp(ClassID())
|
||||
, fPathDrawList(pathDrawList)
|
||||
@ -89,14 +89,14 @@ private:
|
||||
const PathDrawList* fPathDrawList;
|
||||
const int fTotalCombinedPathVerbCnt;
|
||||
const int fPathCount;
|
||||
const GrTessellationPathFlags fPathFlags;
|
||||
const skgpu::tess::TessellationPathFlags fPathFlags;
|
||||
const GrAAType fAAType;
|
||||
SkPMColor4f fColor;
|
||||
GrProcessorSet fProcessors;
|
||||
SkDEBUGCODE(SkRect fOriginalDrawBounds;)
|
||||
|
||||
// Decided during prePreparePrograms.
|
||||
GrPathTessellator* fTessellator = nullptr;
|
||||
skgpu::tess::PathTessellator* fTessellator = nullptr;
|
||||
const GrProgramInfo* fStencilFanProgram = nullptr;
|
||||
const GrProgramInfo* fStencilPathProgram = nullptr;
|
||||
const GrProgramInfo* fCoverBBoxProgram = nullptr;
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "src/gpu/GrAppliedClip.h"
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/PathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
|
||||
|
||||
namespace skgpu::v1 {
|
||||
@ -35,8 +35,9 @@ void PathTessellateOp::prepareTessellator(const GrTessellationShader::ProgramArg
|
||||
SkASSERT(!fTessellationProgram);
|
||||
auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(appliedClip),
|
||||
std::move(fProcessors));
|
||||
fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix, fColor,
|
||||
fPath.countVerbs(), *pipeline, *args.fCaps);
|
||||
fTessellator = skgpu::tess::PathWedgeTessellator::Make(args.fArena, fViewMatrix, fColor,
|
||||
fPath.countVerbs(), *pipeline,
|
||||
*args.fCaps);
|
||||
fTessellationProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(), pipeline,
|
||||
fStencil);
|
||||
}
|
||||
|
@ -11,7 +11,11 @@
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
class GrPathTessellator;
|
||||
namespace skgpu::tess {
|
||||
|
||||
class PathTessellator;
|
||||
|
||||
};
|
||||
|
||||
namespace skgpu::v1 {
|
||||
|
||||
@ -56,7 +60,7 @@ private:
|
||||
GrProcessorSet fProcessors;
|
||||
|
||||
// Decided during prepareTessellator.
|
||||
GrPathTessellator* fTessellator = nullptr;
|
||||
skgpu::tess::PathTessellator* fTessellator = nullptr;
|
||||
const GrProgramInfo* fTessellationProgram = nullptr;
|
||||
|
||||
friend class GrOp; // For ctor.
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "src/gpu/GrAppliedClip.h"
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/tessellate/GrStrokeFixedCountTessellator.h"
|
||||
#include "src/gpu/tessellate/GrStrokeHardwareTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeFixedCountTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeHardwareTessellator.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
using DynamicStroke = GrStrokeTessellationShader::DynamicStroke;
|
||||
@ -199,15 +199,19 @@ void StrokeTessellateOp::prePrepareTessellator(GrTessellationShader::ProgramArgs
|
||||
if (can_use_hardware_tessellation(fTotalCombinedVerbCnt, *pipeline, caps)) {
|
||||
// Only use hardware tessellation if we're drawing a somewhat large number of verbs.
|
||||
// Otherwise we seem to be better off using instanced draws.
|
||||
fTessellator = arena->make<GrStrokeHardwareTessellator>(*caps.shaderCaps(), fShaderFlags,
|
||||
fViewMatrix, &fPathStrokeList,
|
||||
matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
fTessellator = arena->make<skgpu::tess::StrokeHardwareTessellator>(*caps.shaderCaps(),
|
||||
fShaderFlags,
|
||||
fViewMatrix,
|
||||
&fPathStrokeList,
|
||||
matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
} else {
|
||||
fTessellator = arena->make<GrStrokeFixedCountTessellator>(*caps.shaderCaps(), fShaderFlags,
|
||||
fViewMatrix, &fPathStrokeList,
|
||||
matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
fTessellator = arena->make<skgpu::tess::StrokeFixedCountTessellator>(*caps.shaderCaps(),
|
||||
fShaderFlags,
|
||||
fViewMatrix,
|
||||
&fPathStrokeList,
|
||||
matrixMinMaxScales,
|
||||
strokeCullBounds);
|
||||
}
|
||||
|
||||
auto fillStencil = &GrUserStencilSettings::kUnused;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "include/core/SkStrokeRec.h"
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/GrStrokeTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeTessellator.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
class GrRecordingContext;
|
||||
@ -25,7 +25,7 @@ public:
|
||||
|
||||
private:
|
||||
using ShaderFlags = GrStrokeTessellationShader::ShaderFlags;
|
||||
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
|
||||
using PathStrokeList = skgpu::tess::StrokeTessellator::PathStrokeList;
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
SkStrokeRec& headStroke() { return fPathStrokeList.fStroke; }
|
||||
@ -74,7 +74,7 @@ private:
|
||||
GrProcessorSet fProcessors;
|
||||
bool fNeedsStencil;
|
||||
|
||||
GrStrokeTessellator* fTessellator = nullptr;
|
||||
skgpu::tess::StrokeTessellator* fTessellator = nullptr;
|
||||
const GrProgramInfo* fStencilProgram = nullptr; // Only used if the stroke has transparency.
|
||||
const GrProgramInfo* fFillProgram = nullptr;
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ namespace {
|
||||
|
||||
GrOp::Owner make_non_convex_fill_op(GrRecordingContext* rContext,
|
||||
SkArenaAlloc* arena,
|
||||
GrTessellationPathFlags pathFlags,
|
||||
skgpu::tess::TessellationPathFlags pathFlags,
|
||||
GrAAType aaType,
|
||||
const SkRect& drawBounds,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -150,7 +150,7 @@ bool TessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
: pathDevBounds;
|
||||
auto op = make_non_convex_fill_op(args.fContext,
|
||||
args.fSurfaceDrawContext->arenaAlloc(),
|
||||
GrTessellationPathFlags::kNone,
|
||||
skgpu::tess::TessellationPathFlags::kNone,
|
||||
args.fAAType,
|
||||
drawBounds,
|
||||
*args.fViewMatrix,
|
||||
@ -194,7 +194,7 @@ void TessellationPathRenderer::onStencilPath(const StencilPathArgs& args) {
|
||||
|
||||
auto op = make_non_convex_fill_op(args.fContext,
|
||||
args.fSurfaceDrawContext->arenaAlloc(),
|
||||
GrTessellationPathFlags::kStencilOnly,
|
||||
skgpu::tess::TessellationPathFlags::kStencilOnly,
|
||||
aaType,
|
||||
pathDevBounds,
|
||||
*args.fViewMatrix,
|
||||
|
@ -5,13 +5,15 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrCullTest_DEFINED
|
||||
#define GrCullTest_DEFINED
|
||||
#ifndef tessellate_CullTest_DEFINED
|
||||
#define tessellate_CullTest_DEFINED
|
||||
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "include/private/SkVx.h"
|
||||
#include "src/gpu/GrVx.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// This class determines whether the given local-space points will be contained in the cull bounds
|
||||
// post transform. For the versions that take >1 point, it returns whether any region of their
|
||||
// device-space bounding box will be in the cull bounds.
|
||||
@ -19,11 +21,11 @@
|
||||
// NOTE: Our view matrix is not a normal matrix. M*p maps to the float4 [x, y, -x, -y] in device
|
||||
// space. We do this to aid in quick bounds calculations. The matrix also does not have a
|
||||
// translation element. Instead we unapply the translation to the cull bounds ahead of time.
|
||||
class GrCullTest {
|
||||
class CullTest {
|
||||
public:
|
||||
GrCullTest() = default;
|
||||
CullTest() = default;
|
||||
|
||||
GrCullTest(const SkRect& devCullBounds, const SkMatrix& m) {
|
||||
CullTest(const SkRect& devCullBounds, const SkMatrix& m) {
|
||||
this->set(devCullBounds, m);
|
||||
}
|
||||
|
||||
@ -101,4 +103,6 @@ private:
|
||||
grvx::float4 fCullBounds; // [l, t, -r, -b]
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_CullTest_DEFINED
|
@ -1,33 +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 GrStrokeHardwareTessellator_DEFINED
|
||||
#define GrStrokeHardwareTessellator_DEFINED
|
||||
|
||||
#include "src/gpu/GrVertexChunkArray.h"
|
||||
#include "src/gpu/tessellate/GrStrokeTessellator.h"
|
||||
|
||||
// Renders opaque, constant-color strokes by decomposing them into standalone tessellation patches.
|
||||
// Each patch is either a "cubic" (single stroked bezier curve with butt caps) or a "join". Requires
|
||||
// MSAA if antialiasing is desired.
|
||||
class GrStrokeHardwareTessellator : public GrStrokeTessellator {
|
||||
public:
|
||||
GrStrokeHardwareTessellator(const GrShaderCaps& shaderCaps, ShaderFlags shaderFlags,
|
||||
const SkMatrix& viewMatrix, PathStrokeList* pathStrokeList,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds);
|
||||
|
||||
void prepare(GrMeshDrawTarget*, int totalCombinedVerbCnt) override;
|
||||
#if SK_GPU_V1
|
||||
void draw(GrOpFlushState*) const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrVertexChunkArray fPatchChunks;
|
||||
};
|
||||
|
||||
#endif
|
@ -5,8 +5,8 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrMiddleOutPolygonTriangulator_DEFINED
|
||||
#define GrMiddleOutPolygonTriangulator_DEFINED
|
||||
#ifndef tessellate_MiddleOutPolygonTriangulator_DEFINED
|
||||
#define tessellate_MiddleOutPolygonTriangulator_DEFINED
|
||||
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkPoint.h"
|
||||
@ -14,7 +14,9 @@
|
||||
#include "src/core/SkMathPriv.h"
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include "src/gpu/GrVertexWriter.h"
|
||||
#include "src/gpu/tessellate/GrPathXform.h"
|
||||
#include "src/gpu/tessellate/PathXform.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// This class emits a polygon triangulation with a "middle-out" topology. Conceptually, middle-out
|
||||
// emits one large triangle with vertices on both endpoints and a middle point, then recurses on
|
||||
@ -42,13 +44,13 @@
|
||||
// This class is designed to not know or store all the vertices in the polygon at once. The caller
|
||||
// pushes each vertex in linear order (perhaps while parsing a path), then rather than relying on
|
||||
// recursion, we manipulate an O(log N) stack to determine the correct middle-out triangulation.
|
||||
class GrMiddleOutPolygonTriangulator {
|
||||
class MiddleOutPolygonTriangulator {
|
||||
public:
|
||||
// Writes out 3 SkPoints per triangle to "vertexWriter". Additionally writes out "pad32Count"
|
||||
// repetitions of "pad32Value" after each triangle. Set pad32Count to 0 if the triangles are
|
||||
// to be tightly packed.
|
||||
GrMiddleOutPolygonTriangulator(GrVertexWriter&& vertexWriter, int pad32Count,
|
||||
uint32_t pad32Value, int maxPushVertexCalls)
|
||||
MiddleOutPolygonTriangulator(GrVertexWriter&& vertexWriter, int pad32Count,
|
||||
uint32_t pad32Value, int maxPushVertexCalls)
|
||||
: fVertexWriter(std::move(vertexWriter))
|
||||
, fPad32Count(pad32Count)
|
||||
, fPad32Value(pad32Value) {
|
||||
@ -128,10 +130,10 @@ public:
|
||||
static GrVertexWriter WritePathInnerFan(GrVertexWriter&& vertexWriter,
|
||||
int pad32Count,
|
||||
uint32_t pad32Value,
|
||||
const GrPathXform& pathXform,
|
||||
const PathXform& pathXform,
|
||||
const SkPath& path,
|
||||
int* numTrianglesWritten) {
|
||||
GrMiddleOutPolygonTriangulator middleOut(std::move(vertexWriter),
|
||||
MiddleOutPolygonTriangulator middleOut(std::move(vertexWriter),
|
||||
pad32Count,
|
||||
pad32Value,
|
||||
path.countVerbs());
|
||||
@ -197,4 +199,6 @@ private:
|
||||
int fTotalClosedTriangleCount = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_MiddleOutPolygonTriangulator_DEFINED
|
@ -5,18 +5,24 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
|
||||
#include "src/gpu/tessellate/PathCurveTessellator.h"
|
||||
|
||||
#include "src/core/SkUtils.h"
|
||||
#include "src/gpu/GrMeshDrawTarget.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/geometry/GrPathUtils.h"
|
||||
#include "src/gpu/geometry/GrWangsFormula.h"
|
||||
#include "src/gpu/tessellate/GrCullTest.h"
|
||||
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/GrPathXform.h"
|
||||
#include "src/gpu/tessellate/CullTest.h"
|
||||
#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
|
||||
#include "src/gpu/tessellate/PathXform.h"
|
||||
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#endif
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr static float kPrecision = GrTessellationShader::kLinearizationPrecision;
|
||||
@ -151,9 +157,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
GrCullTest fCullTest;
|
||||
GrVectorXform fTotalVectorXform;
|
||||
GrPathXform fPathXform;
|
||||
CullTest fCullTest;
|
||||
VectorXform fTotalVectorXform;
|
||||
PathXform fPathXform;
|
||||
const float fMaxSegments_pow2;
|
||||
const float fMaxSegments_pow4;
|
||||
|
||||
@ -165,12 +171,13 @@ private:
|
||||
} // namespace
|
||||
|
||||
|
||||
GrPathCurveTessellator* GrPathCurveTessellator::Make(SkArenaAlloc* arena,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
DrawInnerFan drawInnerFan, int numPathVerbs,
|
||||
const GrPipeline& pipeline,
|
||||
const GrCaps& caps) {
|
||||
PathCurveTessellator* PathCurveTessellator::Make(SkArenaAlloc* arena,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
DrawInnerFan drawInnerFan,
|
||||
int numPathVerbs,
|
||||
const GrPipeline& pipeline,
|
||||
const GrCaps& caps) {
|
||||
using PatchType = GrPathTessellationShader::PatchType;
|
||||
GrPathTessellationShader* shader;
|
||||
if (caps.shaderCaps()->tessellationSupport() &&
|
||||
@ -185,18 +192,18 @@ GrPathCurveTessellator* GrPathCurveTessellator::Make(SkArenaAlloc* arena,
|
||||
PatchType::kCurves);
|
||||
}
|
||||
return arena->make([=](void* objStart) {
|
||||
return new(objStart) GrPathCurveTessellator(shader, drawInnerFan);
|
||||
return new(objStart) PathCurveTessellator(shader, drawInnerFan);
|
||||
});
|
||||
}
|
||||
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gFixedCountVertexBufferKey);
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gFixedCountIndexBufferKey);
|
||||
|
||||
void GrPathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkRect& cullBounds,
|
||||
const PathDrawList& pathDrawList,
|
||||
int totalCombinedPathVerbCnt,
|
||||
const BreadcrumbTriangleList* breadcrumbTriangleList) {
|
||||
void PathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkRect& cullBounds,
|
||||
const PathDrawList& pathDrawList,
|
||||
int totalCombinedPathVerbCnt,
|
||||
const BreadcrumbTriangleList* breadcrumbTriangleList) {
|
||||
SkASSERT(fVertexChunkArray.empty());
|
||||
|
||||
const GrShaderCaps& shaderCaps = *target->caps().shaderCaps();
|
||||
@ -240,7 +247,7 @@ void GrPathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
: sk_bit_cast<uint32_t>(GrTessellationShader::kTriangularConicCurveType);
|
||||
for (auto [pathMatrix, path] : pathDrawList) {
|
||||
int numTrianglesWritten;
|
||||
vertexWriter = GrMiddleOutPolygonTriangulator::WritePathInnerFan(
|
||||
vertexWriter = MiddleOutPolygonTriangulator::WritePathInnerFan(
|
||||
std::move(vertexWriter),
|
||||
pad32Count,
|
||||
pad32Value,
|
||||
@ -344,9 +351,7 @@ void GrPathCurveTessellator::prepare(GrMeshDrawTarget* target,
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
|
||||
void GrPathCurveTessellator::draw(GrOpFlushState* flushState) const {
|
||||
void PathCurveTessellator::draw(GrOpFlushState* flushState) const {
|
||||
if (fShader->willUseTessellationShaders()) {
|
||||
for (const GrVertexChunk& chunk : fVertexChunkArray) {
|
||||
flushState->bindBuffers(nullptr, nullptr, chunk.fBuffer);
|
||||
@ -361,11 +366,13 @@ void GrPathCurveTessellator::draw(GrOpFlushState* flushState) const {
|
||||
}
|
||||
}
|
||||
|
||||
void GrPathCurveTessellator::drawHullInstances(
|
||||
GrOpFlushState* flushState, sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const {
|
||||
void PathCurveTessellator::drawHullInstances(GrOpFlushState* flushState,
|
||||
sk_sp<const GrGpuBuffer> vertexBufferIfNeeded) const {
|
||||
for (const GrVertexChunk& chunk : fVertexChunkArray) {
|
||||
flushState->bindBuffers(nullptr, chunk.fBuffer, vertexBufferIfNeeded);
|
||||
flushState->drawInstanced(chunk.fCount, chunk.fBase, 4, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace skgpu::tess
|
@ -5,20 +5,22 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathCurveTessellator_DEFINED
|
||||
#define GrPathCurveTessellator_DEFINED
|
||||
#ifndef tessellate_PathCurveTessellator_DEFINED
|
||||
#define tessellate_PathCurveTessellator_DEFINED
|
||||
|
||||
#include "src/gpu/GrVertexChunkArray.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellator.h"
|
||||
#include "src/gpu/tessellate/PathTessellator.h"
|
||||
|
||||
class GrCaps;
|
||||
class GrGpuBuffer;
|
||||
class GrPipeline;
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Draws an array of "outer curve" patches and, optionally, inner fan triangles for
|
||||
// GrCubicTessellateShader. Each patch is an independent 4-point curve, representing either a cubic
|
||||
// or a conic. Quadratics are converted to cubics and triangles are converted to conics with w=Inf.
|
||||
class GrPathCurveTessellator : public GrPathTessellator {
|
||||
class PathCurveTessellator : public PathTessellator {
|
||||
public:
|
||||
// If DrawInnerFan is kNo, this class only emits the path's outer curves. In that case the
|
||||
// caller is responsible to handle the path's inner fan.
|
||||
@ -28,9 +30,13 @@ public:
|
||||
};
|
||||
|
||||
// Creates a curve tessellator with the shader type best suited for the given path description.
|
||||
static GrPathCurveTessellator* Make(SkArenaAlloc*, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f&, DrawInnerFan, int numPathVerbs,
|
||||
const GrPipeline&, const GrCaps&);
|
||||
static PathCurveTessellator* Make(SkArenaAlloc*,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f&,
|
||||
DrawInnerFan,
|
||||
int numPathVerbs,
|
||||
const GrPipeline&,
|
||||
const GrCaps&);
|
||||
|
||||
void prepare(GrMeshDrawTarget* target,
|
||||
const SkRect& cullBounds,
|
||||
@ -39,7 +45,7 @@ public:
|
||||
this->prepare(target, cullBounds, pathDrawList, totalCombinedPathVerbCnt, nullptr);
|
||||
}
|
||||
|
||||
// Implements GrPathTessellator::prepare(), also sending an additional list of breadcrumb
|
||||
// Implements PathTessellator::prepare(), also sending an additional list of breadcrumb
|
||||
// triangles to the GPU. The breadcrumb triangles are implemented as conics with w=Infinity.
|
||||
//
|
||||
// ALSO NOTE: The breadcrumb triangles do not have a matrix. These need to be pre-transformed by
|
||||
@ -60,8 +66,8 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrPathCurveTessellator(GrPathTessellationShader* shader, DrawInnerFan drawInnerFan)
|
||||
: GrPathTessellator(shader)
|
||||
PathCurveTessellator(GrPathTessellationShader* shader, DrawInnerFan drawInnerFan)
|
||||
: PathTessellator(shader)
|
||||
, fDrawInnerFan(drawInnerFan == DrawInnerFan::kYes) {}
|
||||
|
||||
const bool fDrawInnerFan;
|
||||
@ -73,4 +79,6 @@ private:
|
||||
sk_sp<const GrGpuBuffer> fFixedCountIndexBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_PathCurveTessellator_DEFINED
|
@ -5,8 +5,8 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathTessellator_DEFINED
|
||||
#define GrPathTessellator_DEFINED
|
||||
#ifndef tessellate_PathTessellator_DEFINED
|
||||
#define tessellate_PathTessellator_DEFINED
|
||||
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include "src/gpu/GrVertexWriter.h"
|
||||
@ -19,9 +19,11 @@ class GrGpuBuffer;
|
||||
class GrOpFlushState;
|
||||
class GrPathTessellationShader;
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// 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.
|
||||
class GrPathTessellator {
|
||||
class PathTessellator {
|
||||
public:
|
||||
using BreadcrumbTriangleList = GrInnerFanTriangulator::BreadcrumbTriangleList;
|
||||
|
||||
@ -45,7 +47,7 @@ public:
|
||||
Iter end() const { return {nullptr}; }
|
||||
};
|
||||
|
||||
virtual ~GrPathTessellator() {}
|
||||
virtual ~PathTessellator() {}
|
||||
|
||||
const GrPathTessellationShader* shader() const { return fShader; }
|
||||
|
||||
@ -75,9 +77,11 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
GrPathTessellator(GrPathTessellationShader* shader) : fShader(shader) {}
|
||||
PathTessellator(GrPathTessellationShader* shader) : fShader(shader) {}
|
||||
|
||||
GrPathTessellationShader* fShader;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_PathTessellator_DEFINED
|
@ -5,16 +5,22 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
|
||||
#include "src/gpu/tessellate/PathWedgeTessellator.h"
|
||||
|
||||
#include "src/gpu/GrMeshDrawTarget.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/geometry/GrPathUtils.h"
|
||||
#include "src/gpu/geometry/GrWangsFormula.h"
|
||||
#include "src/gpu/tessellate/GrCullTest.h"
|
||||
#include "src/gpu/tessellate/GrPathXform.h"
|
||||
#include "src/gpu/tessellate/CullTest.h"
|
||||
#include "src/gpu/tessellate/PathXform.h"
|
||||
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#endif
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr static float kPrecision = GrTessellationShader::kLinearizationPrecision;
|
||||
@ -108,6 +114,9 @@ private:
|
||||
int fMidpointWeight;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// Writes out wedge patches, chopping as necessary so none require more segments than are supported
|
||||
// by the hardware.
|
||||
class WedgeWriter {
|
||||
@ -132,7 +141,7 @@ public:
|
||||
fPathXform = pathMatrix;
|
||||
}
|
||||
|
||||
const GrPathXform& pathXform() const { return fPathXform; }
|
||||
const PathXform& pathXform() const { return fPathXform; }
|
||||
|
||||
SK_ALWAYS_INLINE void writeFlatWedge(const GrShaderCaps& shaderCaps,
|
||||
SkPoint p0,
|
||||
@ -249,9 +258,9 @@ private:
|
||||
}
|
||||
|
||||
GrVertexChunkBuilder fChunker;
|
||||
GrCullTest fCullTest;
|
||||
GrVectorXform fTotalVectorXform;
|
||||
GrPathXform fPathXform;
|
||||
CullTest fCullTest;
|
||||
VectorXform fTotalVectorXform;
|
||||
PathXform fPathXform;
|
||||
const float fMaxSegments_pow2;
|
||||
const float fMaxSegments_pow4;
|
||||
|
||||
@ -259,12 +268,12 @@ private:
|
||||
float fNumFixedSegments_pow4 = 1;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
GrPathTessellator* GrPathWedgeTessellator::Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color, int numPathVerbs,
|
||||
const GrPipeline& pipeline, const GrCaps& caps) {
|
||||
PathTessellator* PathWedgeTessellator::Make(SkArenaAlloc* arena,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f& color,
|
||||
int numPathVerbs,
|
||||
const GrPipeline& pipeline,
|
||||
const GrCaps& caps) {
|
||||
using PatchType = GrPathTessellationShader::PatchType;
|
||||
GrPathTessellationShader* shader;
|
||||
if (caps.shaderCaps()->tessellationSupport() &&
|
||||
@ -279,17 +288,17 @@ GrPathTessellator* GrPathWedgeTessellator::Make(SkArenaAlloc* arena, const SkMat
|
||||
PatchType::kWedges);
|
||||
}
|
||||
return arena->make([=](void* objStart) {
|
||||
return new(objStart) GrPathWedgeTessellator(shader);
|
||||
return new(objStart) PathWedgeTessellator(shader);
|
||||
});
|
||||
}
|
||||
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gFixedCountVertexBufferKey);
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gFixedCountIndexBufferKey);
|
||||
|
||||
void GrPathWedgeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkRect& cullBounds,
|
||||
const PathDrawList& pathDrawList,
|
||||
int totalCombinedPathVerbCnt) {
|
||||
void PathWedgeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkRect& cullBounds,
|
||||
const PathDrawList& pathDrawList,
|
||||
int totalCombinedPathVerbCnt) {
|
||||
SkASSERT(fVertexChunkArray.empty());
|
||||
|
||||
const GrShaderCaps& shaderCaps = *target->caps().shaderCaps();
|
||||
@ -376,9 +385,7 @@ void GrPathWedgeTessellator::prepare(GrMeshDrawTarget* target,
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
|
||||
void GrPathWedgeTessellator::draw(GrOpFlushState* flushState) const {
|
||||
void PathWedgeTessellator::draw(GrOpFlushState* flushState) const {
|
||||
if (fShader->willUseTessellationShaders()) {
|
||||
for (const GrVertexChunk& chunk : fVertexChunkArray) {
|
||||
flushState->bindBuffers(nullptr, nullptr, chunk.fBuffer);
|
||||
@ -393,3 +400,5 @@ void GrPathWedgeTessellator::draw(GrOpFlushState* flushState) const {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace skgpu::tess
|
@ -5,25 +5,31 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathWedgeTessellator_DEFINED
|
||||
#define GrPathWedgeTessellator_DEFINED
|
||||
#ifndef tessellate_PathWedgeTessellator_DEFINED
|
||||
#define tessellate_PathWedgeTessellator_DEFINED
|
||||
|
||||
#include "src/gpu/GrVertexChunkArray.h"
|
||||
#include "src/gpu/tessellate/GrPathTessellator.h"
|
||||
#include "src/gpu/tessellate/PathTessellator.h"
|
||||
|
||||
class GrCaps;
|
||||
class GrGpuBuffer;
|
||||
class GrPipeline;
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Prepares an array of "wedge" patches for GrWedgeTessellateShader. A wedge is an independent,
|
||||
// 5-point closed contour consisting of 4 control points plus an anchor point fanning from the
|
||||
// center of the curve's resident contour. A wedge can be either a cubic or a conic. Quadratics and
|
||||
// lines are converted to cubics. Once stencilled, these wedges alone define the complete path.
|
||||
class GrPathWedgeTessellator : public GrPathTessellator {
|
||||
class PathWedgeTessellator : public PathTessellator {
|
||||
public:
|
||||
// Creates a wedge tessellator with the shader type best suited for the given path description.
|
||||
static GrPathTessellator* Make(SkArenaAlloc*, const SkMatrix& viewMatrix, const SkPMColor4f&,
|
||||
int numPathVerbs, const GrPipeline&, const GrCaps&);
|
||||
static PathTessellator* Make(SkArenaAlloc*,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPMColor4f&,
|
||||
int numPathVerbs,
|
||||
const GrPipeline&,
|
||||
const GrCaps&);
|
||||
|
||||
void prepare(GrMeshDrawTarget*,
|
||||
const SkRect& cullBounds,
|
||||
@ -36,8 +42,7 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrPathWedgeTessellator(GrPathTessellationShader* shader)
|
||||
: GrPathTessellator(shader) {}
|
||||
PathWedgeTessellator(GrPathTessellationShader* shader) : PathTessellator(shader) {}
|
||||
|
||||
GrVertexChunkArray fVertexChunkArray;
|
||||
|
||||
@ -47,4 +52,6 @@ private:
|
||||
sk_sp<const GrGpuBuffer> fFixedCountIndexBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_PathWedgeTessellator_DEFINED
|
@ -5,28 +5,30 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrPathXform_DEFINED
|
||||
#define GrPathXform_DEFINED
|
||||
#ifndef tessellate_PathXform_DEFINED
|
||||
#define tessellate_PathXform_DEFINED
|
||||
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "src/gpu/GrVertexWriter.h"
|
||||
#include "src/gpu/GrVx.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Applies an affine 2d transformation to points and path components. Converts path components to
|
||||
// tessellation patches. Uses SIMD, but takes care to map points identically, regardless of which
|
||||
// method is called.
|
||||
//
|
||||
// This class stores redundant data, so it is best used only as a stack-allocated object at the
|
||||
// point of use.
|
||||
class GrPathXform {
|
||||
class PathXform {
|
||||
using float2 = grvx::float2;
|
||||
using float4 = grvx::float4;
|
||||
|
||||
public:
|
||||
GrPathXform() = default;
|
||||
GrPathXform(const SkMatrix& m) { *this = m; }
|
||||
PathXform() = default;
|
||||
PathXform(const SkMatrix& m) { *this = m; }
|
||||
|
||||
GrPathXform& operator=(const SkMatrix& m) {
|
||||
PathXform& operator=(const SkMatrix& m) {
|
||||
SkASSERT(!m.hasPerspective());
|
||||
// Duplicate the matrix in float4.lo and float4.hi so we can map two points at once.
|
||||
fScale = {m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY()};
|
||||
@ -92,4 +94,6 @@ private:
|
||||
float4 fTrans;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_PathXform_DEFINED
|
@ -5,15 +5,21 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/tessellate/GrStrokeFixedCountTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeFixedCountTessellator.h"
|
||||
|
||||
#include "src/core/SkGeometry.h"
|
||||
#include "src/gpu/GrMeshDrawTarget.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/geometry/GrPathUtils.h"
|
||||
#include "src/gpu/geometry/GrWangsFormula.h"
|
||||
#include "src/gpu/tessellate/GrCullTest.h"
|
||||
#include "src/gpu/tessellate/GrStrokeIterator.h"
|
||||
#include "src/gpu/tessellate/CullTest.h"
|
||||
#include "src/gpu/tessellate/StrokeIterator.h"
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#endif
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
namespace {
|
||||
|
||||
@ -25,7 +31,7 @@ constexpr static int8_t kMaxParametricSegments_log2 = 5; // log2(32)
|
||||
// will just add enough additional segments to handle a worst-case 180 degree stroke.)
|
||||
class InstanceWriter {
|
||||
public:
|
||||
using ShaderFlags = GrStrokeTessellator::ShaderFlags;
|
||||
using ShaderFlags = StrokeTessellator::ShaderFlags;
|
||||
|
||||
InstanceWriter(const GrShaderCaps* shaderCaps, ShaderFlags shaderFlags,
|
||||
GrMeshDrawTarget* target, float matrixMaxScale, const SkRect& strokeCullBounds,
|
||||
@ -35,7 +41,7 @@ public:
|
||||
, fShaderFlags(shaderFlags)
|
||||
, fCullTest(strokeCullBounds, viewMatrix)
|
||||
, fChunkBuilder(target, patchChunks, instanceStride, minInstancesPerChunk)
|
||||
, fParametricPrecision(GrStrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
, fParametricPrecision(StrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
}
|
||||
|
||||
float parametricPrecision() const { return fParametricPrecision; }
|
||||
@ -217,7 +223,7 @@ private:
|
||||
|
||||
const GrShaderCaps* fShaderCaps;
|
||||
const ShaderFlags fShaderFlags;
|
||||
const GrCullTest fCullTest;
|
||||
const CullTest fCullTest;
|
||||
GrVertexChunkBuilder fChunkBuilder;
|
||||
const float fParametricPrecision;
|
||||
float fMaxParametricSegments_pow4 = 1;
|
||||
@ -235,7 +241,7 @@ private:
|
||||
};
|
||||
|
||||
// Returns the worst-case number of edges we will need in order to draw a join of the given type.
|
||||
static int worst_case_edges_in_join(SkPaint::Join joinType, float numRadialSegmentsPerRadian) {
|
||||
int worst_case_edges_in_join(SkPaint::Join joinType, float numRadialSegmentsPerRadian) {
|
||||
int numEdges = GrStrokeTessellationShader::NumFixedEdgesInJoin(joinType);
|
||||
if (joinType == SkPaint::kRound_Join) {
|
||||
// For round joins we need to count the radial edges on our own. Account for a worst-case
|
||||
@ -247,21 +253,21 @@ static int worst_case_edges_in_join(SkPaint::Join joinType, float numRadialSegme
|
||||
|
||||
} // namespace
|
||||
|
||||
GrStrokeFixedCountTessellator::GrStrokeFixedCountTessellator(const GrShaderCaps& shaderCaps,
|
||||
ShaderFlags shaderFlags,
|
||||
const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds)
|
||||
: GrStrokeTessellator(shaderCaps, GrStrokeTessellationShader::Mode::kFixedCount,
|
||||
shaderFlags, kMaxParametricSegments_log2, viewMatrix,
|
||||
pathStrokeList, matrixMinMaxScales, strokeCullBounds) {
|
||||
|
||||
StrokeFixedCountTessellator::StrokeFixedCountTessellator(const GrShaderCaps& shaderCaps,
|
||||
ShaderFlags shaderFlags,
|
||||
const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds)
|
||||
: StrokeTessellator(shaderCaps, GrStrokeTessellationShader::Mode::kFixedCount, shaderFlags,
|
||||
kMaxParametricSegments_log2, viewMatrix, pathStrokeList,
|
||||
matrixMinMaxScales, strokeCullBounds) {
|
||||
}
|
||||
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gVertexIDFallbackBufferKey);
|
||||
|
||||
void GrStrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
int totalCombinedVerbCnt) {
|
||||
void StrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target, int totalCombinedVerbCnt) {
|
||||
int maxEdgesInJoin = 0;
|
||||
float maxRadialSegmentsPerRadian = 0;
|
||||
|
||||
@ -278,9 +284,9 @@ void GrStrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
if (!fShader.hasDynamicStroke()) {
|
||||
// Strokes are static. Calculate tolerances once.
|
||||
const SkStrokeRec& stroke = fPathStrokeList->fStroke;
|
||||
float localStrokeWidth = GrStrokeTolerances::GetLocalStrokeWidth(fMatrixMinMaxScales.data(),
|
||||
stroke.getWidth());
|
||||
float numRadialSegmentsPerRadian = GrStrokeTolerances::CalcNumRadialSegmentsPerRadian(
|
||||
float localStrokeWidth = StrokeTolerances::GetLocalStrokeWidth(fMatrixMinMaxScales.data(),
|
||||
stroke.getWidth());
|
||||
float numRadialSegmentsPerRadian = StrokeTolerances::CalcNumRadialSegmentsPerRadian(
|
||||
instanceWriter.parametricPrecision(), localStrokeWidth);
|
||||
maxEdgesInJoin = worst_case_edges_in_join(stroke.getJoin(), numRadialSegmentsPerRadian);
|
||||
maxRadialSegmentsPerRadian = numRadialSegmentsPerRadian;
|
||||
@ -288,7 +294,7 @@ void GrStrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
|
||||
// Fast SIMD queue that buffers up values for "numRadialSegmentsPerRadian". Only used when we
|
||||
// have dynamic stroke.
|
||||
GrStrokeToleranceBuffer toleranceBuffer(instanceWriter.parametricPrecision());
|
||||
StrokeToleranceBuffer toleranceBuffer(instanceWriter.parametricPrecision());
|
||||
|
||||
for (PathStrokeList* pathStroke = fPathStrokeList; pathStroke; pathStroke = pathStroke->fNext) {
|
||||
const SkStrokeRec& stroke = pathStroke->fStroke;
|
||||
@ -306,11 +312,11 @@ void GrStrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
if (fShader.hasDynamicColor()) {
|
||||
instanceWriter.updateDynamicColor(pathStroke->fColor);
|
||||
}
|
||||
GrStrokeIterator strokeIter(pathStroke->fPath, &pathStroke->fStroke, &fShader.viewMatrix());
|
||||
StrokeIterator strokeIter(pathStroke->fPath, &pathStroke->fStroke, &fShader.viewMatrix());
|
||||
while (strokeIter.next()) {
|
||||
const SkPoint* p = strokeIter.pts();
|
||||
switch (strokeIter.verb()) {
|
||||
using Verb = GrStrokeIterator::Verb;
|
||||
using Verb = StrokeIterator::Verb;
|
||||
int numChops;
|
||||
case Verb::kContourFinished:
|
||||
instanceWriter.finishContour();
|
||||
@ -445,9 +451,7 @@ void GrStrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
|
||||
void GrStrokeFixedCountTessellator::draw(GrOpFlushState* flushState) const {
|
||||
void StrokeFixedCountTessellator::draw(GrOpFlushState* flushState) const {
|
||||
if (fInstanceChunks.empty() || fFixedVertexCount <= 0) {
|
||||
return;
|
||||
}
|
||||
@ -457,3 +461,5 @@ void GrStrokeFixedCountTessellator::draw(GrOpFlushState* flushState) const {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace skgpu::tess
|
@ -5,19 +5,24 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrStrokeFixedCountTessellator_DEFINED
|
||||
#define GrStrokeFixedCountTessellator_DEFINED
|
||||
#ifndef tessellate_StrokeFixedCountTessellator_DEFINED
|
||||
#define tessellate_StrokeFixedCountTessellator_DEFINED
|
||||
|
||||
#include "src/gpu/GrVertexChunkArray.h"
|
||||
#include "src/gpu/tessellate/GrStrokeTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeTessellator.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Renders strokes as fixed-count triangle strip instances. Any extra triangles not needed by the
|
||||
// instance are emitted as degenerate triangles.
|
||||
class GrStrokeFixedCountTessellator : public GrStrokeTessellator {
|
||||
class StrokeFixedCountTessellator : public StrokeTessellator {
|
||||
public:
|
||||
GrStrokeFixedCountTessellator(const GrShaderCaps&, ShaderFlags, const SkMatrix&,
|
||||
PathStrokeList*, std::array<float, 2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds);
|
||||
StrokeFixedCountTessellator(const GrShaderCaps&,
|
||||
ShaderFlags,
|
||||
const SkMatrix&,
|
||||
PathStrokeList*,
|
||||
std::array<float, 2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds);
|
||||
|
||||
void prepare(GrMeshDrawTarget*, int totalCombinedVerbCnt) override;
|
||||
#if SK_GPU_V1
|
||||
@ -32,4 +37,6 @@ private:
|
||||
sk_sp<const GrGpuBuffer> fVertexBufferIfNoIDSupport;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_StrokeFixedCountTessellator_DEFINED
|
@ -5,7 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/gpu/tessellate/GrStrokeHardwareTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeHardwareTessellator.h"
|
||||
|
||||
#include "src/core/SkMathPriv.h"
|
||||
#include "src/core/SkPathPriv.h"
|
||||
@ -14,11 +14,17 @@
|
||||
#include "src/gpu/GrVx.h"
|
||||
#include "src/gpu/geometry/GrPathUtils.h"
|
||||
#include "src/gpu/geometry/GrWangsFormula.h"
|
||||
#include "src/gpu/tessellate/GrCullTest.h"
|
||||
#include "src/gpu/tessellate/CullTest.h"
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#endif
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
namespace {
|
||||
|
||||
static float num_combined_segments(float numParametricSegments, float numRadialSegments) {
|
||||
float num_combined_segments(float numParametricSegments, float numRadialSegments) {
|
||||
// The first and last edges are shared by both the parametric and radial sets of edges, so
|
||||
// the total number of edges is:
|
||||
//
|
||||
@ -37,14 +43,14 @@ static float num_combined_segments(float numParametricSegments, float numRadialS
|
||||
return numParametricSegments + numRadialSegments - 1;
|
||||
}
|
||||
|
||||
static grvx::float2 pow4(grvx::float2 x) {
|
||||
grvx::float2 pow4(grvx::float2 x) {
|
||||
auto xx = x*x;
|
||||
return xx*xx;
|
||||
}
|
||||
|
||||
class PatchWriter {
|
||||
public:
|
||||
using ShaderFlags = GrStrokeTessellator::ShaderFlags;
|
||||
using ShaderFlags = StrokeTessellator::ShaderFlags;
|
||||
|
||||
enum class JoinType {
|
||||
kMiter = SkPaint::kMiter_Join,
|
||||
@ -62,7 +68,7 @@ public:
|
||||
// Subtract 2 because the tessellation shader chops every cubic at two locations, and
|
||||
// each chop has the potential to introduce an extra segment.
|
||||
, fMaxTessellationSegments(target->caps().shaderCaps()->maxTessellationSegments() - 2)
|
||||
, fParametricPrecision(GrStrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
, fParametricPrecision(StrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
}
|
||||
|
||||
// This is the precision value, adjusted for the view matrix, to use with Wang's formulas when
|
||||
@ -626,7 +632,7 @@ private:
|
||||
}
|
||||
|
||||
const ShaderFlags fShaderFlags;
|
||||
const GrCullTest fCullTest;
|
||||
const CullTest fCullTest;
|
||||
GrVertexChunkBuilder fChunkBuilder;
|
||||
|
||||
// The maximum number of tessellation segments the hardware can emit for a single patch.
|
||||
@ -668,7 +674,7 @@ private:
|
||||
GrVertexColor fDynamicColor;
|
||||
};
|
||||
|
||||
SK_ALWAYS_INLINE static bool cubic_has_cusp(const SkPoint p[4]) {
|
||||
SK_ALWAYS_INLINE bool cubic_has_cusp(const SkPoint p[4]) {
|
||||
using grvx::float2;
|
||||
|
||||
float2 p0 = skvx::bit_pun<float2>(p[0]);
|
||||
@ -704,18 +710,19 @@ SK_ALWAYS_INLINE static bool cubic_has_cusp(const SkPoint p[4]) {
|
||||
|
||||
} // namespace
|
||||
|
||||
GrStrokeHardwareTessellator::GrStrokeHardwareTessellator(const GrShaderCaps& shaderCaps,
|
||||
ShaderFlags shaderFlags,
|
||||
const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds)
|
||||
: GrStrokeTessellator(shaderCaps, GrStrokeTessellationShader::Mode::kHardwareTessellation,
|
||||
shaderFlags, SkNextLog2(shaderCaps.maxTessellationSegments()),
|
||||
viewMatrix, pathStrokeList, matrixMinMaxScales, strokeCullBounds) {
|
||||
|
||||
StrokeHardwareTessellator::StrokeHardwareTessellator(const GrShaderCaps& shaderCaps,
|
||||
ShaderFlags shaderFlags,
|
||||
const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds)
|
||||
: StrokeTessellator(shaderCaps, GrStrokeTessellationShader::Mode::kHardwareTessellation,
|
||||
shaderFlags, SkNextLog2(shaderCaps.maxTessellationSegments()),
|
||||
viewMatrix, pathStrokeList, matrixMinMaxScales, strokeCullBounds) {
|
||||
}
|
||||
|
||||
void GrStrokeHardwareTessellator::prepare(GrMeshDrawTarget* target, int totalCombinedVerbCnt) {
|
||||
void StrokeHardwareTessellator::prepare(GrMeshDrawTarget* target, int totalCombinedVerbCnt) {
|
||||
using JoinType = PatchWriter::JoinType;
|
||||
|
||||
// Over-allocate enough patches for 1 in 4 strokes to chop and for 8 extra caps.
|
||||
@ -729,16 +736,16 @@ void GrStrokeHardwareTessellator::prepare(GrMeshDrawTarget* target, int totalCom
|
||||
if (!fShader.hasDynamicStroke()) {
|
||||
// Strokes are static. Calculate tolerances once.
|
||||
const SkStrokeRec& stroke = fPathStrokeList->fStroke;
|
||||
float localStrokeWidth = GrStrokeTolerances::GetLocalStrokeWidth(fMatrixMinMaxScales.data(),
|
||||
stroke.getWidth());
|
||||
float numRadialSegmentsPerRadian = GrStrokeTolerances::CalcNumRadialSegmentsPerRadian(
|
||||
float localStrokeWidth = StrokeTolerances::GetLocalStrokeWidth(fMatrixMinMaxScales.data(),
|
||||
stroke.getWidth());
|
||||
float numRadialSegmentsPerRadian = StrokeTolerances::CalcNumRadialSegmentsPerRadian(
|
||||
patchWriter.parametricPrecision(), localStrokeWidth);
|
||||
patchWriter.updateTolerances(numRadialSegmentsPerRadian, stroke.getJoin());
|
||||
}
|
||||
|
||||
// Fast SIMD queue that buffers up values for "numRadialSegmentsPerRadian". Only used when we
|
||||
// have dynamic strokes.
|
||||
GrStrokeToleranceBuffer toleranceBuffer(patchWriter.parametricPrecision());
|
||||
StrokeToleranceBuffer toleranceBuffer(patchWriter.parametricPrecision());
|
||||
|
||||
for (PathStrokeList* pathStroke = fPathStrokeList; pathStroke; pathStroke = pathStroke->fNext) {
|
||||
const SkStrokeRec& stroke = pathStroke->fStroke;
|
||||
@ -898,13 +905,12 @@ void GrStrokeHardwareTessellator::prepare(GrMeshDrawTarget* target, int totalCom
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
|
||||
void GrStrokeHardwareTessellator::draw(GrOpFlushState* flushState) const {
|
||||
void StrokeHardwareTessellator::draw(GrOpFlushState* flushState) const {
|
||||
for (const auto& vertexChunk : fPatchChunks) {
|
||||
flushState->bindBuffers(nullptr, nullptr, vertexChunk.fBuffer);
|
||||
flushState->draw(vertexChunk.fCount, vertexChunk.fBase);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace skgpu::tess
|
39
src/gpu/tessellate/StrokeHardwareTessellator.h
Normal file
39
src/gpu/tessellate/StrokeHardwareTessellator.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 tessellate_StrokeHardwareTessellator_DEFINED
|
||||
#define tessellate_StrokeHardwareTessellator_DEFINED
|
||||
|
||||
#include "src/gpu/GrVertexChunkArray.h"
|
||||
#include "src/gpu/tessellate/StrokeTessellator.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Renders opaque, constant-color strokes by decomposing them into standalone tessellation patches.
|
||||
// Each patch is either a "cubic" (single stroked bezier curve with butt caps) or a "join". Requires
|
||||
// MSAA if antialiasing is desired.
|
||||
class StrokeHardwareTessellator : public StrokeTessellator {
|
||||
public:
|
||||
StrokeHardwareTessellator(const GrShaderCaps& shaderCaps,
|
||||
ShaderFlags shaderFlags,
|
||||
const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds);
|
||||
|
||||
void prepare(GrMeshDrawTarget*, int totalCombinedVerbCnt) override;
|
||||
#if SK_GPU_V1
|
||||
void draw(GrOpFlushState*) const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrVertexChunkArray fPatchChunks;
|
||||
};
|
||||
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_StrokeHardwareTessellator_DEFINED
|
@ -5,20 +5,22 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrStrokeIterator_DEFINED
|
||||
#define GrStrokeIterator_DEFINED
|
||||
#ifndef tessellate_StrokeIterator_DEFINED
|
||||
#define tessellate_StrokeIterator_DEFINED
|
||||
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkStrokeRec.h"
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include <array>
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// This class iterates over the stroke geometry defined by a path and stroke. It automatically
|
||||
// converts closes and square caps to lines, and round caps to circles so the user doesn't have to
|
||||
// worry about it. At each location it provides a verb and "prevVerb" so there is context about the
|
||||
// preceding join. Usage:
|
||||
//
|
||||
// GrStrokeIterator iter(path, stroke);
|
||||
// StrokeIterator iter(path, stroke);
|
||||
// while (iter.next()) { // Call next() first.
|
||||
// iter.verb();
|
||||
// iter.pts();
|
||||
@ -27,9 +29,9 @@
|
||||
// iter.prevPts();
|
||||
// }
|
||||
//
|
||||
class GrStrokeIterator {
|
||||
class StrokeIterator {
|
||||
public:
|
||||
GrStrokeIterator(const SkPath& path, const SkStrokeRec* stroke, const SkMatrix* viewMatrix)
|
||||
StrokeIterator(const SkPath& path, const SkStrokeRec* stroke, const SkMatrix* viewMatrix)
|
||||
: fViewMatrix(viewMatrix), fStroke(stroke) {
|
||||
SkPathPriv::Iterate it(path);
|
||||
fIter = it.begin();
|
||||
@ -364,4 +366,8 @@ private:
|
||||
std::array<SkPoint, 2> fBeginningCapPts;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_StrokeIterator_DEFINED
|
||||
|
||||
|
@ -5,8 +5,8 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrStrokeTessellator_DEFINED
|
||||
#define GrStrokeTessellator_DEFINED
|
||||
#ifndef tessellate_StrokeTessellator_DEFINED
|
||||
#define tessellate_StrokeTessellator_DEFINED
|
||||
|
||||
#include "src/gpu/GrVx.h"
|
||||
#include "src/gpu/tessellate/shaders/GrStrokeTessellationShader.h"
|
||||
@ -14,8 +14,10 @@
|
||||
class GrMeshDrawTarget;
|
||||
class GrOpFlushState;
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Prepares GPU data for, and then draws a stroke's tessellated geometry.
|
||||
class GrStrokeTessellator {
|
||||
class StrokeTessellator {
|
||||
public:
|
||||
using ShaderFlags = GrStrokeTessellationShader::ShaderFlags;
|
||||
|
||||
@ -28,10 +30,14 @@ public:
|
||||
PathStrokeList* fNext = nullptr;
|
||||
};
|
||||
|
||||
GrStrokeTessellator(const GrShaderCaps& shaderCaps, GrStrokeTessellationShader::Mode shaderMode,
|
||||
ShaderFlags shaderFlags, int8_t maxParametricSegments_log2,
|
||||
const SkMatrix& viewMatrix, PathStrokeList* pathStrokeList,
|
||||
std::array<float, 2> matrixMinMaxScales, const SkRect& strokeCullBounds)
|
||||
StrokeTessellator(const GrShaderCaps& shaderCaps,
|
||||
GrStrokeTessellationShader::Mode shaderMode,
|
||||
ShaderFlags shaderFlags,
|
||||
int8_t maxParametricSegments_log2,
|
||||
const SkMatrix& viewMatrix,
|
||||
PathStrokeList* pathStrokeList,
|
||||
std::array<float, 2> matrixMinMaxScales,
|
||||
const SkRect& strokeCullBounds)
|
||||
: fShader(shaderCaps, shaderMode, shaderFlags, viewMatrix, pathStrokeList->fStroke,
|
||||
pathStrokeList->fColor, maxParametricSegments_log2)
|
||||
, fPathStrokeList(pathStrokeList)
|
||||
@ -50,7 +56,7 @@ public:
|
||||
virtual void draw(GrOpFlushState*) const = 0;
|
||||
#endif
|
||||
|
||||
virtual ~GrStrokeTessellator() {}
|
||||
virtual ~StrokeTessellator() {}
|
||||
|
||||
protected:
|
||||
GrStrokeTessellationShader fShader;
|
||||
@ -61,7 +67,7 @@ protected:
|
||||
|
||||
// These tolerances decide the number of parametric and radial segments the tessellator will
|
||||
// linearize strokes into. These decisions are made in (pre-viewMatrix) local path space.
|
||||
struct GrStrokeTolerances {
|
||||
struct StrokeTolerances {
|
||||
// Decides the number of parametric segments the tessellator adds for each curve. (Uniform
|
||||
// steps in parametric space.) The tessellator will add enough parametric segments so that,
|
||||
// once transformed into device space, they never deviate by more than
|
||||
@ -109,11 +115,11 @@ struct GrStrokeTolerances {
|
||||
}
|
||||
return localStrokeWidth;
|
||||
}
|
||||
static GrStrokeTolerances Make(const float matrixMinMaxScales[2], float strokeWidth) {
|
||||
static StrokeTolerances Make(const float matrixMinMaxScales[2], float strokeWidth) {
|
||||
return MakeNonHairline(matrixMinMaxScales[1],
|
||||
GetLocalStrokeWidth(matrixMinMaxScales, strokeWidth));
|
||||
}
|
||||
static GrStrokeTolerances MakeNonHairline(float matrixMaxScale, float strokeWidth) {
|
||||
static StrokeTolerances MakeNonHairline(float matrixMaxScale, float strokeWidth) {
|
||||
SkASSERT(strokeWidth > 0);
|
||||
float parametricPrecision = CalcParametricPrecision(matrixMaxScale);
|
||||
return {parametricPrecision,
|
||||
@ -124,17 +130,15 @@ struct GrStrokeTolerances {
|
||||
};
|
||||
|
||||
// Calculates and buffers up future values for "numRadialSegmentsPerRadian" using SIMD.
|
||||
class alignas(sizeof(float) * 4) GrStrokeToleranceBuffer {
|
||||
class alignas(sizeof(float) * 4) StrokeToleranceBuffer {
|
||||
public:
|
||||
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
|
||||
using PathStrokeList = StrokeTessellator::PathStrokeList;
|
||||
|
||||
GrStrokeToleranceBuffer(float parametricPrecision)
|
||||
: fParametricPrecision(parametricPrecision) {
|
||||
}
|
||||
StrokeToleranceBuffer(float parametricPrecision) : fParametricPrecision(parametricPrecision) {}
|
||||
|
||||
float fetchRadialSegmentsPerRadian(PathStrokeList* head) {
|
||||
// StrokeTessellateOp::onCombineIfPossible does not allow hairlines to become dynamic. If
|
||||
// this changes, we will need to call GrStrokeTolerances::GetLocalStrokeWidth() for each
|
||||
// this changes, we will need to call StrokeTolerances::GetLocalStrokeWidth() for each
|
||||
// stroke.
|
||||
SkASSERT(!head->fStroke.isHairlineStyle());
|
||||
if (fBufferIdx == 4) {
|
||||
@ -144,8 +148,8 @@ public:
|
||||
do {
|
||||
fStrokeWidths[i++] = peekAhead->fStroke.getWidth();
|
||||
} while ((peekAhead = peekAhead->fNext) && i < 4);
|
||||
auto tol = GrStrokeTolerances::ApproxNumRadialSegmentsPerRadian(fParametricPrecision,
|
||||
fStrokeWidths);
|
||||
auto tol = StrokeTolerances::ApproxNumRadialSegmentsPerRadian(fParametricPrecision,
|
||||
fStrokeWidths);
|
||||
tol.store(fNumRadialSegmentsPerRadian);
|
||||
fBufferIdx = 0;
|
||||
}
|
||||
@ -161,4 +165,6 @@ private:
|
||||
int fBufferIdx = 4; // Initialize the buffer as "empty";
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_StrokeTessellator_DEFINED
|
@ -5,18 +5,22 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrTessTypes_DEFINED
|
||||
#define GrTessTypes_DEFINED
|
||||
#ifndef tessellate_TessTypes_DEFINED
|
||||
#define tessellate_TessTypes_DEFINED
|
||||
|
||||
#include "include/gpu/GrTypes.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// We send these flags to the internal path filling Ops to control how a path gets rendered.
|
||||
enum class GrTessellationPathFlags {
|
||||
enum class TessellationPathFlags {
|
||||
kNone = 0,
|
||||
kStencilOnly = (1 << 0),
|
||||
kWireframe = (1 << 1)
|
||||
};
|
||||
|
||||
GR_MAKE_BITFIELD_CLASS_OPS(GrTessellationPathFlags)
|
||||
GR_MAKE_BITFIELD_CLASS_OPS(TessellationPathFlags)
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_TessTypes_DEFINED
|
@ -5,23 +5,25 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrVectorXform_DEFINED
|
||||
#define GrVectorXform_DEFINED
|
||||
#ifndef tessellate_VectorXform_DEFINED
|
||||
#define tessellate_VectorXform_DEFINED
|
||||
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "include/private/SkVx.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
// Represents the upper-left 2x2 matrix of an affine transform for applying to vectors:
|
||||
//
|
||||
// VectorXform(p1 - p0) == M * float3(p1, 1) - M * float3(p0, 1)
|
||||
//
|
||||
class GrVectorXform {
|
||||
class VectorXform {
|
||||
public:
|
||||
using float2 = skvx::Vec<2, float>;
|
||||
using float4 = skvx::Vec<4, float>;
|
||||
explicit GrVectorXform() : fType(Type::kIdentity) {}
|
||||
explicit GrVectorXform(const SkMatrix& m) { *this = m; }
|
||||
GrVectorXform& operator=(const SkMatrix& m) {
|
||||
explicit VectorXform() : fType(Type::kIdentity) {}
|
||||
explicit VectorXform(const SkMatrix& m) { *this = m; }
|
||||
VectorXform& operator=(const SkMatrix& m) {
|
||||
SkASSERT(!m.hasPerspective());
|
||||
if (m.getType() & SkMatrix::kAffine_Mask) {
|
||||
fType = Type::kAffine;
|
||||
@ -69,4 +71,6 @@ private:
|
||||
float4 fSkewXYXY;
|
||||
};
|
||||
|
||||
#endif
|
||||
} // namespace skgpu::tess
|
||||
|
||||
#endif // tessellate_VectorXform_DEFINED
|
@ -56,9 +56,9 @@ GrPathTessellationShader* GrPathTessellationShader::MakeSimpleTriangleShader(
|
||||
const GrPipeline* GrPathTessellationShader::MakeStencilOnlyPipeline(
|
||||
const ProgramArgs& args,
|
||||
GrAAType aaType,
|
||||
GrTessellationPathFlags pathFlags,
|
||||
skgpu::tess::TessellationPathFlags pathFlags,
|
||||
const GrAppliedHardClip& hardClip) {
|
||||
using PathFlags = GrTessellationPathFlags;
|
||||
using PathFlags = skgpu::tess::TessellationPathFlags;
|
||||
GrPipeline::InitArgs pipelineArgs;
|
||||
if (args.fCaps->wireframeSupport() && (pathFlags & PathFlags::kWireframe)) {
|
||||
pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef GrPathTessellationShader_DEFINED
|
||||
#define GrPathTessellationShader_DEFINED
|
||||
|
||||
#include "src/gpu/tessellate/GrTessTypes.h"
|
||||
#include "src/gpu/tessellate/TessTypes.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
// This is the base class for shaders in the GPU tessellator that fill paths.
|
||||
@ -154,7 +154,7 @@ public:
|
||||
// Creates a pipeline that does not write to the color buffer.
|
||||
static const GrPipeline* MakeStencilOnlyPipeline(const ProgramArgs&,
|
||||
GrAAType,
|
||||
GrTessellationPathFlags,
|
||||
skgpu::tess::TessellationPathFlags,
|
||||
const GrAppliedHardClip&);
|
||||
|
||||
protected:
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
||||
#include "src/gpu/tessellate/GrStrokeTessellator.h"
|
||||
#include "src/gpu/tessellate/StrokeTessellator.h"
|
||||
|
||||
GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shaderCaps, Mode mode,
|
||||
ShaderFlags shaderFlags,
|
||||
@ -349,14 +349,14 @@ void GrStrokeTessellationShader::Impl::setData(const GrGLSLProgramDataManager& p
|
||||
|
||||
if (!shader.hasDynamicStroke()) {
|
||||
// Set up the tessellation control uniforms.
|
||||
GrStrokeTolerances tolerances;
|
||||
skgpu::tess::StrokeTolerances tolerances;
|
||||
if (!stroke.isHairlineStyle()) {
|
||||
tolerances = GrStrokeTolerances::MakeNonHairline(shader.viewMatrix().getMaxScale(),
|
||||
stroke.getWidth());
|
||||
tolerances = skgpu::tess::StrokeTolerances::MakeNonHairline(
|
||||
shader.viewMatrix().getMaxScale(), stroke.getWidth());
|
||||
} else {
|
||||
// In the hairline case we transform prior to tessellation. Set up tolerances for an
|
||||
// identity viewMatrix and a strokeWidth of 1.
|
||||
tolerances = GrStrokeTolerances::MakeNonHairline(1, 1);
|
||||
tolerances = skgpu::tess::StrokeTolerances::MakeNonHairline(1, 1);
|
||||
}
|
||||
float strokeRadius = (stroke.isHairlineStyle()) ? .5f : stroke.getWidth() * .5;
|
||||
pdman.set4f(fTessControlArgsUniform,
|
||||
@ -368,7 +368,7 @@ void GrStrokeTessellationShader::Impl::setData(const GrGLSLProgramDataManager& p
|
||||
SkASSERT(!stroke.isHairlineStyle());
|
||||
float maxScale = shader.viewMatrix().getMaxScale();
|
||||
pdman.set1f(fTessControlArgsUniform,
|
||||
GrStrokeTolerances::CalcParametricPrecision(maxScale));
|
||||
skgpu::tess::StrokeTolerances::CalcParametricPrecision(maxScale));
|
||||
}
|
||||
|
||||
if (shader.mode() == GrStrokeTessellationShader::Mode::kFixedCount) {
|
||||
|
@ -8,7 +8,9 @@
|
||||
#include "tests/Test.h"
|
||||
|
||||
#include "include/utils/SkRandom.h"
|
||||
#include "src/gpu/tessellate/GrCullTest.h"
|
||||
#include "src/gpu/tessellate/CullTest.h"
|
||||
|
||||
namespace skgpu::tess {
|
||||
|
||||
const SkMatrix gMatrices[] = {
|
||||
SkMatrix::I(),
|
||||
@ -34,7 +36,7 @@ DEF_TEST(CullTestTest, reporter) {
|
||||
float valuesR[4] = {r+20, r+10, r-10, r-20};
|
||||
float valuesB[4] = {b+20, b+10, b-10, b-20};
|
||||
for (SkMatrix m : gMatrices) {
|
||||
GrCullTest cullTest(viewportRect, m);
|
||||
CullTest cullTest(viewportRect, m);
|
||||
SkMatrix inverse;
|
||||
SkAssertResult(m.invert(&inverse));
|
||||
for (const float* y : {valuesT, valuesB}) {
|
||||
@ -75,3 +77,5 @@ DEF_TEST(CullTestTest, reporter) {
|
||||
}}}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace skgpu::tess
|
||||
|
@ -280,7 +280,7 @@ DEF_TEST(WangsFormula_vectorXforms, r) {
|
||||
SkPoint ptsXformed[4];
|
||||
m.mapPoints(ptsXformed, pts, 4);
|
||||
int expected = GrWangsFormula::cubic_log2(kPrecision, ptsXformed);
|
||||
int actual = GrWangsFormula::cubic_log2(kPrecision, pts, GrVectorXform(m));
|
||||
int actual = GrWangsFormula::cubic_log2(kPrecision, pts, skgpu::tess::VectorXform(m));
|
||||
REPORTER_ASSERT(r, actual == expected);
|
||||
};
|
||||
|
||||
@ -288,7 +288,7 @@ DEF_TEST(WangsFormula_vectorXforms, r) {
|
||||
SkPoint ptsXformed[3];
|
||||
m.mapPoints(ptsXformed, pts, 3);
|
||||
int expected = GrWangsFormula::quadratic_log2(kPrecision, ptsXformed);
|
||||
int actual = GrWangsFormula::quadratic_log2(kPrecision, pts, GrVectorXform(m));
|
||||
int actual = GrWangsFormula::quadratic_log2(kPrecision, pts, skgpu::tess::VectorXform(m));
|
||||
REPORTER_ASSERT(r, actual == expected);
|
||||
};
|
||||
|
||||
@ -494,7 +494,7 @@ DEF_TEST(WangsFormula_conic_vectorXforms, r) {
|
||||
SkPoint ptsXformed[3];
|
||||
m.mapPoints(ptsXformed, pts, 3);
|
||||
float expected = GrWangsFormula::conic(kPrecision, ptsXformed, w);
|
||||
float actual = GrWangsFormula::conic(kPrecision, pts, w, GrVectorXform(m));
|
||||
float actual = GrWangsFormula::conic(kPrecision, pts, w, skgpu::tess::VectorXform(m));
|
||||
REPORTER_ASSERT(r, SkScalarNearlyEqual(actual, expected));
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user