Move Ganesh-specific bits of StrokeTessellator into an #ifdef
Bug: skia:12524 Change-Id: I31ddee40fed6e57caafe7a51fdd90459bd29cd6a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/474356 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
1ce70dc2ce
commit
5cf4ed47f4
@ -247,7 +247,7 @@ using PathStrokeList = StrokeTessellator::PathStrokeList;
|
||||
using MakeTessellatorFn = std::unique_ptr<StrokeTessellator>(*)(PatchAttribs);
|
||||
|
||||
static std::unique_ptr<StrokeTessellator> make_hw_tessellator(PatchAttribs attribs) {
|
||||
return std::make_unique<StrokeHardwareTessellator>(attribs);
|
||||
return std::make_unique<StrokeHardwareTessellator>(attribs, 64);
|
||||
}
|
||||
|
||||
static std::unique_ptr<StrokeTessellator> make_fixed_count_tessellator(PatchAttribs attribs) {
|
||||
|
@ -193,7 +193,8 @@ 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<StrokeHardwareTessellator>(fPatchAttribs);
|
||||
fTessellator = arena->make<StrokeHardwareTessellator>(
|
||||
fPatchAttribs, caps.shaderCaps()->maxTessellationSegments());
|
||||
shaderMode = GrStrokeTessellationShader::Mode::kHardwareTessellation;
|
||||
// This sets a limit on the number of binary search iterations inside the shader, so we
|
||||
// round up to the next log2 to guarantee it makes enough.
|
||||
|
@ -8,8 +8,6 @@
|
||||
#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/tessellate/PatchWriter.h"
|
||||
#include "src/gpu/tessellate/StrokeIterator.h"
|
||||
@ -17,7 +15,9 @@
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrMeshDrawTarget.h"
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#endif
|
||||
|
||||
namespace skgpu {
|
||||
@ -190,23 +190,22 @@ int worst_case_edges_in_join(SkPaint::Join joinType, float numRadialSegmentsPerR
|
||||
} // namespace
|
||||
|
||||
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gVertexIDFallbackBufferKey);
|
||||
|
||||
int StrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList* pathStrokeList,
|
||||
int totalCombinedVerbCnt) {
|
||||
int maxEdgesInJoin = 0;
|
||||
float maxRadialSegmentsPerRadian = 0;
|
||||
|
||||
int StrokeFixedCountTessellator::patchPreallocCount(int totalCombinedStrokeVerbCnt) const {
|
||||
// Over-allocate enough patches for each stroke to chop once, and for 8 extra caps. Since we
|
||||
// have to chop at inflections, points of 180 degree rotation, and anywhere a stroke requires
|
||||
// too many parametric segments, many strokes will end up getting choppped.
|
||||
int strokePreallocCount = totalCombinedVerbCnt * 2;
|
||||
int strokePreallocCount = totalCombinedStrokeVerbCnt * 2;
|
||||
int capPreallocCount = 8;
|
||||
int minInstancesPerChunk = strokePreallocCount + capPreallocCount;
|
||||
PatchWriter patchWriter(target, this, minInstancesPerChunk);
|
||||
return strokePreallocCount + capPreallocCount;
|
||||
}
|
||||
|
||||
int StrokeFixedCountTessellator::writePatches(PatchWriter& patchWriter,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList* pathStrokeList) {
|
||||
int maxEdgesInJoin = 0;
|
||||
float maxRadialSegmentsPerRadian = 0;
|
||||
|
||||
InstanceWriter instanceWriter(patchWriter, matrixMinMaxScales[1]);
|
||||
|
||||
if (!(fAttribs & PatchAttribs::kStrokeParams)) {
|
||||
@ -352,7 +351,33 @@ int StrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
// number of edges in an instance is the sum of edges from the join and stroke sections both.
|
||||
// NOTE: The final join edge and the first stroke edge are co-located, however we still need to
|
||||
// emit both because the join's edge is half-width and the stroke's is full-width.
|
||||
fFixedEdgeCount = maxEdgesInJoin + maxEdgesInStroke;
|
||||
return maxEdgesInJoin + maxEdgesInStroke;
|
||||
}
|
||||
|
||||
void StrokeFixedCountTessellator::InitializeVertexIDFallbackBuffer(VertexWriter vertexWriter,
|
||||
size_t bufferSize) {
|
||||
SkASSERT(bufferSize % (sizeof(float) * 2) == 0);
|
||||
int edgeCount = bufferSize / (sizeof(float) * 2);
|
||||
for (int i = 0; i < edgeCount; ++i) {
|
||||
vertexWriter << (float)i << (float)-i;
|
||||
}
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
|
||||
GR_DECLARE_STATIC_UNIQUE_KEY(gVertexIDFallbackBufferKey);
|
||||
|
||||
int StrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList* pathStrokeList,
|
||||
int totalCombinedStrokeVerbCnt) {
|
||||
PatchWriter patchWriter(target, this, this->patchPreallocCount(totalCombinedStrokeVerbCnt));
|
||||
|
||||
fFixedEdgeCount = this->writePatches(patchWriter,
|
||||
shaderMatrix,
|
||||
matrixMinMaxScales,
|
||||
pathStrokeList);
|
||||
|
||||
// Don't draw more vertices than can be indexed by a signed short. We just have to draw the line
|
||||
// somewhere and this seems reasonable enough. (There are two vertices per edge, so 2^14 edges
|
||||
@ -377,16 +402,6 @@ int StrokeFixedCountTessellator::prepare(GrMeshDrawTarget* target,
|
||||
return fFixedEdgeCount;
|
||||
}
|
||||
|
||||
void StrokeFixedCountTessellator::InitializeVertexIDFallbackBuffer(VertexWriter vertexWriter,
|
||||
size_t bufferSize) {
|
||||
SkASSERT(bufferSize % (sizeof(float) * 2) == 0);
|
||||
int edgeCount = bufferSize / (sizeof(float) * 2);
|
||||
for (int i = 0; i < edgeCount; ++i) {
|
||||
vertexWriter << (float)i << (float)-i;
|
||||
}
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
void StrokeFixedCountTessellator::draw(GrOpFlushState* flushState) const {
|
||||
if (fVertexChunkArray.empty() || fFixedEdgeCount <= 0) {
|
||||
return;
|
||||
@ -403,6 +418,7 @@ void StrokeFixedCountTessellator::draw(GrOpFlushState* flushState) const {
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -16,21 +16,28 @@ namespace skgpu {
|
||||
|
||||
// Renders strokes as fixed-count triangle strip instances. Any extra triangles not needed by the
|
||||
// instance are emitted as degenerate triangles.
|
||||
class StrokeFixedCountTessellator : public StrokeTessellator {
|
||||
class StrokeFixedCountTessellator final : public StrokeTessellator {
|
||||
public:
|
||||
constexpr static float kMaxParametricSegments_pow4 = 32*32*32*32; // 32^4
|
||||
constexpr static int8_t kMaxParametricSegments_log2 = 5; // log2(32)
|
||||
|
||||
StrokeFixedCountTessellator(PatchAttribs attribs) : StrokeTessellator(attribs) {}
|
||||
|
||||
int patchPreallocCount(int totalCombinedStrokeVerbCnt) const final;
|
||||
|
||||
int writePatches(PatchWriter&,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList*) final;
|
||||
|
||||
#if SK_GPU_V1
|
||||
int prepare(GrMeshDrawTarget*,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList*,
|
||||
int totalCombinedVerbCnt) override;
|
||||
int totalCombinedStrokeVerbCnt) final;
|
||||
|
||||
#if SK_GPU_V1
|
||||
void draw(GrOpFlushState*) const override;
|
||||
void draw(GrOpFlushState*) const final;
|
||||
#endif
|
||||
|
||||
// Initializes the fallback vertex buffer that should be bound when sk_VertexID is not
|
||||
@ -67,10 +74,12 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
#if SK_GPU_V1
|
||||
int fFixedEdgeCount = 0;
|
||||
|
||||
// Only used if sk_VertexID is not supported.
|
||||
sk_sp<const GrGpuBuffer> fVertexBufferIfNoIDSupport;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -8,14 +8,13 @@
|
||||
#include "src/gpu/tessellate/StrokeHardwareTessellator.h"
|
||||
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include "src/gpu/GrMeshDrawTarget.h"
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/geometry/GrPathUtils.h"
|
||||
#include "src/gpu/tessellate/PatchWriter.h"
|
||||
#include "src/gpu/tessellate/WangsFormula.h"
|
||||
#include "src/gpu/tessellate/shaders/GrTessellationShader.h"
|
||||
|
||||
#if SK_GPU_V1
|
||||
#include "src/gpu/GrMeshDrawTarget.h"
|
||||
#include "src/gpu/GrOpFlushState.h"
|
||||
#endif
|
||||
|
||||
@ -56,11 +55,11 @@ public:
|
||||
kBowtie = SkPaint::kLast_Join + 1 // Double sided round join.
|
||||
};
|
||||
|
||||
HwPatchWriter(PatchWriter& patchWriter, const GrShaderCaps& shaderCaps, float matrixMaxScale)
|
||||
HwPatchWriter(PatchWriter& patchWriter, int maxTessellationSegments, float matrixMaxScale)
|
||||
: fPatchWriter(patchWriter)
|
||||
// Subtract 2 because the tessellation shader chops every cubic at two locations, and
|
||||
// each chop has the potential to introduce an extra segment.
|
||||
, fMaxTessellationSegments(shaderCaps.maxTessellationSegments() - 2)
|
||||
, fMaxTessellationSegments(std::max(maxTessellationSegments - 2, 1))
|
||||
, fParametricPrecision(StrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
}
|
||||
|
||||
@ -664,19 +663,20 @@ SK_ALWAYS_INLINE bool cubic_has_cusp(const SkPoint p[4]) {
|
||||
} // namespace
|
||||
|
||||
|
||||
int StrokeHardwareTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList* pathStrokeList,
|
||||
int totalCombinedVerbCnt) {
|
||||
int StrokeHardwareTessellator::patchPreallocCount(int totalCombinedStrokeVerbCnt) const {
|
||||
// Over-allocate enough patches for 1 in 4 strokes to chop and for 8 extra caps.
|
||||
int strokePreallocCount = (totalCombinedStrokeVerbCnt * 5) / 4;
|
||||
int capPreallocCount = 8;
|
||||
return strokePreallocCount + capPreallocCount;
|
||||
}
|
||||
|
||||
int StrokeHardwareTessellator::writePatches(PatchWriter& patchWriter,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList* pathStrokeList) {
|
||||
using JoinType = HwPatchWriter::JoinType;
|
||||
|
||||
// Over-allocate enough patches for 1 in 4 strokes to chop and for 8 extra caps.
|
||||
int strokePreallocCount = totalCombinedVerbCnt * 5/4;
|
||||
int capPreallocCount = 8;
|
||||
int minPatchesPerChunk = strokePreallocCount + capPreallocCount;
|
||||
PatchWriter patchWriter(target, this, minPatchesPerChunk);
|
||||
HwPatchWriter hwPatchWriter(patchWriter, *target->caps().shaderCaps(), matrixMinMaxScales[1]);
|
||||
HwPatchWriter hwPatchWriter(patchWriter, fMaxTessellationSegments, matrixMinMaxScales[1]);
|
||||
|
||||
if (!(fAttribs & PatchAttribs::kStrokeParams)) {
|
||||
// Strokes are static. Calculate tolerances once.
|
||||
@ -851,12 +851,23 @@ int StrokeHardwareTessellator::prepare(GrMeshDrawTarget* target,
|
||||
}
|
||||
|
||||
#if SK_GPU_V1
|
||||
|
||||
int StrokeHardwareTessellator::prepare(GrMeshDrawTarget* target,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList* pathStrokeList,
|
||||
int totalCombinedStrokeVerbCnt) {
|
||||
PatchWriter patchWriter(target, this, this->patchPreallocCount(totalCombinedStrokeVerbCnt));
|
||||
return this->writePatches(patchWriter, shaderMatrix, matrixMinMaxScales, pathStrokeList);
|
||||
}
|
||||
|
||||
void StrokeHardwareTessellator::draw(GrOpFlushState* flushState) const {
|
||||
for (const auto& vertexChunk : fVertexChunkArray) {
|
||||
flushState->bindBuffers(nullptr, nullptr, vertexChunk.fBuffer);
|
||||
flushState->draw(vertexChunk.fCount, vertexChunk.fBase);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -16,18 +16,30 @@ namespace skgpu {
|
||||
// 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 {
|
||||
class StrokeHardwareTessellator final : public StrokeTessellator {
|
||||
public:
|
||||
StrokeHardwareTessellator(PatchAttribs attribs) : StrokeTessellator(attribs) {}
|
||||
StrokeHardwareTessellator(PatchAttribs attribs, int maxTessellationSegments)
|
||||
: StrokeTessellator(attribs), fMaxTessellationSegments(maxTessellationSegments) {}
|
||||
|
||||
int patchPreallocCount(int totalCombinedStrokeVerbCnt) const final;
|
||||
|
||||
int writePatches(PatchWriter&,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList*) final;
|
||||
|
||||
#if SK_GPU_V1
|
||||
int prepare(GrMeshDrawTarget*,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList*,
|
||||
int totalCombinedVerbCnt) override;
|
||||
#if SK_GPU_V1
|
||||
void draw(GrOpFlushState*) const override;
|
||||
int totalCombinedStrokeVerbCnt) final;
|
||||
|
||||
void draw(GrOpFlushState*) const final;
|
||||
#endif
|
||||
|
||||
private:
|
||||
const int fMaxTessellationSegments;
|
||||
};
|
||||
|
||||
} // namespace skgpu
|
||||
|
@ -22,6 +22,8 @@ class GrOpFlushState;
|
||||
|
||||
namespace skgpu {
|
||||
|
||||
class PatchWriter;
|
||||
|
||||
// Prepares GPU data for, and then draws a stroke's tessellated geometry.
|
||||
class StrokeTessellator {
|
||||
public:
|
||||
@ -36,6 +38,21 @@ public:
|
||||
|
||||
StrokeTessellator(PatchAttribs attribs) : fAttribs(attribs) {}
|
||||
|
||||
// Gives an approximate initial buffer size for this class to write patches into. Ideally the
|
||||
// whole stroke will fit into this initial buffer, but if it requires a lot of chopping, the
|
||||
// PatchWriter will allocate more buffer(s).
|
||||
virtual int patchPreallocCount(int totalCombinedStrokeVerbCnt) const = 0;
|
||||
|
||||
// Writes out patches to the given PatchWriter, chopping as necessary.
|
||||
//
|
||||
// Returns the fixed number of edges the tessellator will draw per patch, if using fixed-count
|
||||
// rendering, otherwise 0.
|
||||
virtual int writePatches(PatchWriter&,
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList*) = 0;
|
||||
|
||||
#if SK_GPU_V1
|
||||
// Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
|
||||
//
|
||||
// Returns the fixed number of edges the tessellator will draw per patch, if using fixed-count
|
||||
@ -44,9 +61,8 @@ public:
|
||||
const SkMatrix& shaderMatrix,
|
||||
std::array<float,2> matrixMinMaxScales,
|
||||
PathStrokeList*,
|
||||
int totalCombinedVerbCnt) = 0;
|
||||
int totalCombinedStrokeVerbCnt) = 0;
|
||||
|
||||
#if SK_GPU_V1
|
||||
// Issues draw calls for the tessellated stroke. The caller is responsible for creating and
|
||||
// binding a pipeline that uses this class's shader() before calling draw().
|
||||
virtual void draw(GrOpFlushState*) const = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user