Move last join control point storage into PatchWriter
Change-Id: I916c23778e04911ea122720b8e48850caab4df64 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/501437 Reviewed-by: John Stiles <johnstiles@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
ff94e373a3
commit
1f1270f8ac
@ -33,7 +33,7 @@ PatchWriter::PatchWriter(GrMeshDrawTarget* target,
|
||||
: PatchWriter(target,
|
||||
&tessellator->fVertexChunkArray,
|
||||
tessellator->fAttribs,
|
||||
sizeof(SkPoint) * 5 + PatchAttribsStride(tessellator->fAttribs),
|
||||
sizeof(SkPoint) * 4 + PatchAttribsStride(tessellator->fAttribs),
|
||||
initialPatchAllocCount) {
|
||||
}
|
||||
#endif
|
||||
|
@ -41,23 +41,46 @@ public:
|
||||
|
||||
PatchAttribs attribs() const { return fAttribs; }
|
||||
|
||||
// Updates the stroke's join control point that will be written out with each patch. This is
|
||||
// automatically adjusted when appending various geometries (e.g. Conic/Cubic), but sometimes
|
||||
// must be set explicitly.
|
||||
//
|
||||
// PatchAttribs::kJoinControlPoint must be enabled.
|
||||
void updateJoinControlPointAttrib(SkPoint lastControlPoint) {
|
||||
SkASSERT(fAttribs & PatchAttribs::kJoinControlPoint);
|
||||
fJoinControlPointAttrib = lastControlPoint;
|
||||
fHasJoinControlPoint = true;
|
||||
}
|
||||
// Completes a closed contour of a stroke by rewriting a deferred patch with the now-available
|
||||
// join control point information defined by the last verb of the contour (now already written).
|
||||
//
|
||||
// PatchAttribs::kJoinControlPoint must be enabled.
|
||||
void writeDeferredStrokePatch() {
|
||||
SkASSERT(fAttribs & PatchAttribs::kJoinControlPoint);
|
||||
// TODO: This will also handle writing a deferred patch when that is moved into PatchWriter
|
||||
fHasJoinControlPoint = false;
|
||||
}
|
||||
// TODO: This is only used while migrating from InstanceWriter
|
||||
const SkPoint& joinControlPoint() const { return fJoinControlPointAttrib; }
|
||||
bool hasJoinControlPoint() const { return fHasJoinControlPoint; }
|
||||
|
||||
// Updates the fan point that will be written out with each patch (i.e., the point that wedges
|
||||
// fan around).
|
||||
// PathPatchAttrib::kFanPoint must be enabled.
|
||||
// PatchAttribs::kFanPoint must be enabled.
|
||||
void updateFanPointAttrib(SkPoint fanPoint) {
|
||||
SkASSERT(fAttribs & PatchAttribs::kFanPoint);
|
||||
fFanPointAttrib = fanPoint;
|
||||
}
|
||||
|
||||
// Updates the stroke params that are written out with each patch.
|
||||
// PathPatchAttrib::kStrokeParams must be enabled.
|
||||
// PatchAttribs::kStrokeParams must be enabled.
|
||||
void updateStrokeParamsAttrib(StrokeParams strokeParams) {
|
||||
SkASSERT(fAttribs & PatchAttribs::kStrokeParams);
|
||||
fStrokeParamsAttrib = strokeParams;
|
||||
}
|
||||
|
||||
// Updates the color that will be written out with each patch.
|
||||
// PathPatchAttrib::kColor must be enabled.
|
||||
// PatchAttribs::kColor must be enabled.
|
||||
void updateColorAttrib(const SkPMColor4f& color) {
|
||||
SkASSERT(fAttribs & PatchAttribs::kColor);
|
||||
fColorAttrib.set(color, fAttribs & PatchAttribs::kWideColorIfEnabled);
|
||||
@ -151,18 +174,27 @@ private:
|
||||
static VertexWriter::Conditional<T> If(bool c, const T& v) { return VertexWriter::If(c,v); }
|
||||
|
||||
void emitPatchAttribs(VertexWriter vertexWriter, float explicitCurveType) {
|
||||
vertexWriter << If((fAttribs & PatchAttribs::kFanPoint), fFanPointAttrib)
|
||||
// TODO: For now, the join control point must be explicitly provided by caller *before*
|
||||
// they write any patch, and are responsible for deferring data on their own. This assert
|
||||
// will relax when PatchWriter automates the deferring.
|
||||
SkASSERT(!(fAttribs & PatchAttribs::kJoinControlPoint) ||
|
||||
fJoinControlPointAttrib.isFinite());
|
||||
vertexWriter << If((fAttribs & PatchAttribs::kJoinControlPoint), fJoinControlPointAttrib)
|
||||
<< If((fAttribs & PatchAttribs::kFanPoint), fFanPointAttrib)
|
||||
<< If((fAttribs & PatchAttribs::kStrokeParams), fStrokeParamsAttrib)
|
||||
<< If((fAttribs & PatchAttribs::kColor), fColorAttrib)
|
||||
<< If((fAttribs & PatchAttribs::kExplicitCurveType), explicitCurveType);
|
||||
}
|
||||
|
||||
const PatchAttribs fAttribs;
|
||||
GrVertexChunkBuilder fChunker;
|
||||
|
||||
SkPoint fJoinControlPointAttrib;
|
||||
SkPoint fFanPointAttrib;
|
||||
StrokeParams fStrokeParamsAttrib;
|
||||
VertexColor fColorAttrib;
|
||||
|
||||
GrVertexChunkBuilder fChunker;
|
||||
bool fHasJoinControlPoint = false;
|
||||
|
||||
// For when fChunker fails to allocate a patch in GPU memory.
|
||||
SkAutoTMalloc<char> fFallbackPatchStorage;
|
||||
|
@ -33,6 +33,8 @@ public:
|
||||
InstanceWriter(PatchWriter& patchWriter, float matrixMaxScale)
|
||||
: fPatchWriter(patchWriter)
|
||||
, fParametricPrecision(StrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
SkASSERT(fPatchWriter.attribs() & PatchAttribs::kJoinControlPoint);
|
||||
SkASSERT(!fPatchWriter.hasJoinControlPoint());
|
||||
}
|
||||
|
||||
float parametricPrecision() const { return fParametricPrecision; }
|
||||
@ -90,8 +92,7 @@ public:
|
||||
// Called when we encounter the verb "kMoveWithinContour". Moves invalidate the previous control
|
||||
// point. The stroke iterator tells us the new value to use for the previous control point.
|
||||
void setLastControlPoint(SkPoint newLastControlPoint) {
|
||||
fLastControlPoint = newLastControlPoint;
|
||||
fHasLastControlPoint = true;
|
||||
fPatchWriter.updateJoinControlPointAttrib(newLastControlPoint);
|
||||
}
|
||||
|
||||
// Draws a circle whose diameter is equal to the stroke width. We emit circles at cusp points
|
||||
@ -99,19 +100,24 @@ public:
|
||||
void writeCircle(SkPoint location) {
|
||||
// The shader interprets an empty stroke + empty join as a special case that denotes a
|
||||
// circle, or 180-degree point stroke.
|
||||
PatchWriter::CubicPatch(fPatchWriter) << VertexWriter::Repeat<5>(location);
|
||||
// TODO: This is a little awkward right now, but will be simplified as more of
|
||||
// InstanceWriter is pulled into PatchWriter.
|
||||
SkPoint joinPoint = fPatchWriter.joinControlPoint();
|
||||
fPatchWriter.updateJoinControlPointAttrib(location);
|
||||
PatchWriter::CubicPatch(fPatchWriter) << VertexWriter::Repeat<4>(location);
|
||||
fPatchWriter.updateJoinControlPointAttrib(joinPoint);
|
||||
}
|
||||
|
||||
void finishContour() {
|
||||
if (fHasDeferredFirstStroke) {
|
||||
// We deferred the first stroke because we didn't know the previous control point to use
|
||||
// for its join. We write it out now.
|
||||
SkASSERT(fHasLastControlPoint);
|
||||
SkASSERT(fPatchWriter.hasJoinControlPoint());
|
||||
this->writeStroke(fDeferredFirstStroke, SkPoint(),
|
||||
fDeferredCurveTypeIfUnsupportedInfinity);
|
||||
fHasDeferredFirstStroke = false;
|
||||
}
|
||||
fHasLastControlPoint = false;
|
||||
fPatchWriter.writeDeferredStrokePatch();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -140,25 +146,17 @@ private:
|
||||
|
||||
SK_ALWAYS_INLINE void writeStroke(const SkPoint p[4], SkPoint endControlPoint,
|
||||
float curveTypeIfUnsupportedInfinity) {
|
||||
if (fHasLastControlPoint) {
|
||||
if (fPatchWriter.hasJoinControlPoint()) {
|
||||
PatchWriter::Patch(fPatchWriter, curveTypeIfUnsupportedInfinity)
|
||||
<< VertexWriter::Array(p, 4) << fLastControlPoint;
|
||||
<< VertexWriter::Array(p, 4);
|
||||
} else {
|
||||
// We don't know the previous control point yet to use for the join. Defer writing out
|
||||
// this stroke until the end.
|
||||
memcpy(fDeferredFirstStroke, p, sizeof(fDeferredFirstStroke));
|
||||
fDeferredCurveTypeIfUnsupportedInfinity = curveTypeIfUnsupportedInfinity;
|
||||
fHasDeferredFirstStroke = true;
|
||||
fHasLastControlPoint = true;
|
||||
}
|
||||
fLastControlPoint = endControlPoint;
|
||||
}
|
||||
|
||||
void discardStroke(const SkPoint p[], int numPts) {
|
||||
// Set fLastControlPoint to the next stroke's p0 (which will be equal to the final point of
|
||||
// this stroke). This has the effect of disabling the next stroke's join.
|
||||
fLastControlPoint = p[numPts - 1];
|
||||
fHasLastControlPoint = true;
|
||||
fPatchWriter.updateJoinControlPointAttrib(endControlPoint);
|
||||
}
|
||||
|
||||
PatchWriter& fPatchWriter;
|
||||
@ -168,9 +166,7 @@ private:
|
||||
// We can't write out the first stroke until we know the previous control point for its join.
|
||||
SkPoint fDeferredFirstStroke[4];
|
||||
float fDeferredCurveTypeIfUnsupportedInfinity;
|
||||
SkPoint fLastControlPoint; // Used to configure the joins in the instance data.
|
||||
bool fHasDeferredFirstStroke = false;
|
||||
bool fHasLastControlPoint = false;
|
||||
};
|
||||
|
||||
// Returns the worst-case number of edges we will need in order to draw a join of the given type.
|
||||
|
@ -60,6 +60,8 @@ public:
|
||||
// each chop has the potential to introduce an extra segment.
|
||||
, fMaxTessellationSegments(std::max(maxTessellationSegments - 2, 1))
|
||||
, fParametricPrecision(StrokeTolerances::CalcParametricPrecision(matrixMaxScale)) {
|
||||
SkASSERT(fPatchWriter.attribs() & PatchAttribs::kJoinControlPoint);
|
||||
SkASSERT(!fPatchWriter.hasJoinControlPoint());
|
||||
}
|
||||
|
||||
// This is the precision value, adjusted for the view matrix, to use with Wang's formulas when
|
||||
@ -132,7 +134,9 @@ public:
|
||||
|
||||
void moveTo(SkPoint pt) {
|
||||
fCurrContourStartPoint = pt;
|
||||
fHasLastControlPoint = false;
|
||||
// Either the first contour, or the prior strokes should have had verbs explicitly writing
|
||||
// caps, which resets the join control point.
|
||||
SkASSERT(!fPatchWriter.hasJoinControlPoint());
|
||||
}
|
||||
|
||||
// Writes out the given line, possibly chopping its previous join until the segments fit in
|
||||
@ -197,28 +201,29 @@ public:
|
||||
SkPoint endControlPoint) {
|
||||
SkASSERT(fStrokeJoinType != JoinType::kBowtie);
|
||||
|
||||
if (!fHasLastControlPoint) {
|
||||
if (!fPatchWriter.hasJoinControlPoint()) {
|
||||
// The first stroke doesn't have a previous join (yet). If the current contour ends up
|
||||
// closing itself, we will add that join as its own patch. TODO: Consider deferring the
|
||||
// first stroke until we know whether the contour will close. This will allow us to use
|
||||
// the closing join as the first patch's previous join.
|
||||
fHasLastControlPoint = true;
|
||||
fCurrContourFirstControlPoint = (p[1] != p[0]) ? p[1] : p[2];
|
||||
fLastControlPoint = p[0]; // Disables the join section of this patch.
|
||||
// Disables the join section of this patch.
|
||||
fPatchWriter.updateJoinControlPointAttrib(p[0]);
|
||||
} else if (!prevJoinFitsInPatch) {
|
||||
// There aren't enough guaranteed segments to fold the previous join into this patch.
|
||||
// Emit the join in its own separate patch.
|
||||
this->internalJoinTo(fStrokeJoinType, p[0], (p[1] != p[0]) ? p[1] : p[2]);
|
||||
fLastControlPoint = p[0]; // Disables the join section of this patch.
|
||||
// Disables the join section of this patch.
|
||||
fPatchWriter.updateJoinControlPointAttrib(p[0]);
|
||||
}
|
||||
|
||||
HwPatch(fPatchWriter) << fLastControlPoint << VertexWriter::Array(p, 4);
|
||||
fLastControlPoint = endControlPoint;
|
||||
HwPatch(fPatchWriter) << VertexWriter::Array(p, 4);
|
||||
fPatchWriter.updateJoinControlPointAttrib(endControlPoint);
|
||||
}
|
||||
|
||||
void writeClose(SkPoint contourEndpoint, const SkMatrix& viewMatrix,
|
||||
const SkStrokeRec& stroke) {
|
||||
if (!fHasLastControlPoint) {
|
||||
if (!fPatchWriter.hasJoinControlPoint()) {
|
||||
// Draw caps instead of closing if the subpath is zero length:
|
||||
//
|
||||
// "Any zero length subpath ... shall be stroked if the 'stroke-linecap' property has
|
||||
@ -234,12 +239,11 @@ public:
|
||||
// contourEndpoint == fCurrContourStartPoint.)
|
||||
this->writeLineTo(contourEndpoint, fCurrContourStartPoint);
|
||||
this->internalJoinTo(fStrokeJoinType, fCurrContourStartPoint, fCurrContourFirstControlPoint);
|
||||
|
||||
fHasLastControlPoint = false;
|
||||
fPatchWriter.writeDeferredStrokePatch();
|
||||
}
|
||||
|
||||
void writeCaps(SkPoint contourEndpoint, const SkMatrix& viewMatrix, const SkStrokeRec& stroke) {
|
||||
if (!fHasLastControlPoint) {
|
||||
if (!fPatchWriter.hasJoinControlPoint()) {
|
||||
// We don't have any control points to orient the caps. In this case, square and round
|
||||
// caps are specified to be drawn as an axis-aligned square or circle respectively.
|
||||
// Assign default control points that achieve this.
|
||||
@ -269,9 +273,8 @@ public:
|
||||
outset = {d, -c};
|
||||
}
|
||||
fCurrContourFirstControlPoint = fCurrContourStartPoint - outset;
|
||||
fLastControlPoint = fCurrContourStartPoint + outset;
|
||||
fHasLastControlPoint = true;
|
||||
contourEndpoint = fCurrContourStartPoint;
|
||||
fPatchWriter.updateJoinControlPointAttrib(fCurrContourStartPoint + outset);
|
||||
}
|
||||
|
||||
switch (stroke.getCap()) {
|
||||
@ -282,7 +285,8 @@ public:
|
||||
// If our join type isn't round we can alternatively use a bowtie.
|
||||
JoinType roundCapJoinType = (stroke.getJoin() == SkPaint::kRound_Join)
|
||||
? JoinType::kRound : JoinType::kBowtie;
|
||||
this->internalJoinTo(roundCapJoinType, contourEndpoint, fLastControlPoint);
|
||||
this->internalJoinTo(roundCapJoinType, contourEndpoint,
|
||||
fPatchWriter.joinControlPoint());
|
||||
this->internalMoveTo(fCurrContourStartPoint, fCurrContourFirstControlPoint);
|
||||
this->internalJoinTo(roundCapJoinType, fCurrContourStartPoint,
|
||||
fCurrContourFirstControlPoint);
|
||||
@ -291,7 +295,7 @@ public:
|
||||
case SkPaint::kSquare_Cap: {
|
||||
// A square cap is the same as appending lineTos.
|
||||
auto strokeJoinType = JoinType(stroke.getJoin());
|
||||
SkVector lastTangent = contourEndpoint - fLastControlPoint;
|
||||
SkVector lastTangent = contourEndpoint - fPatchWriter.joinControlPoint();
|
||||
if (!stroke.isHairlineStyle()) {
|
||||
// Extend the cap by 1/2 stroke width.
|
||||
lastTangent *= (.5f * stroke.getWidth()) / lastTangent.length();
|
||||
@ -317,7 +321,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
fHasLastControlPoint = false;
|
||||
fPatchWriter.writeDeferredStrokePatch();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -329,8 +333,8 @@ private:
|
||||
|
||||
void internalMoveTo(SkPoint pt, SkPoint lastControlPoint) {
|
||||
fCurrContourStartPoint = pt;
|
||||
fCurrContourFirstControlPoint = fLastControlPoint = lastControlPoint;
|
||||
fHasLastControlPoint = true;
|
||||
fCurrContourFirstControlPoint = lastControlPoint;
|
||||
fPatchWriter.updateJoinControlPointAttrib(lastControlPoint);
|
||||
}
|
||||
|
||||
// Recursively chops the given conic and its previous join until the segments fit in
|
||||
@ -470,14 +474,14 @@ private:
|
||||
void internalPatchTo(JoinType prevJoinType, bool prevJoinFitsInPatch, const SkPoint p[4],
|
||||
SkPoint endPt) {
|
||||
if (prevJoinType == JoinType::kBowtie) {
|
||||
SkASSERT(fHasLastControlPoint);
|
||||
SkASSERT(fPatchWriter.hasJoinControlPoint());
|
||||
// Bowtie joins are only used on internal chops, and internal chops almost always have
|
||||
// continuous tangent angles (i.e., the ending tangent of the first chop and the
|
||||
// beginning tangent of the second both point in the same direction). The tangents will
|
||||
// only ever not point in the same direction if we chopped at a cusp point, so that's
|
||||
// the only time we actually need a bowtie.
|
||||
SkPoint nextControlPoint = (p[1] == p[0]) ? p[2] : p[1];
|
||||
SkVector a = p[0] - fLastControlPoint;
|
||||
SkVector a = p[0] - fPatchWriter.joinControlPoint();
|
||||
SkVector b = nextControlPoint - p[0];
|
||||
float ab_cosTheta = a.dot(b);
|
||||
float ab_pow2 = a.dot(a) * b.dot(b);
|
||||
@ -500,7 +504,6 @@ private:
|
||||
if (!SkScalarNearlyEqual(ab_pow2, ab_cosTheta * fabsf(ab_cosTheta),
|
||||
ab_pow2 * SK_ScalarNearlyZero)) {
|
||||
this->internalJoinTo(JoinType::kBowtie, p[0], nextControlPoint);
|
||||
fLastControlPoint = p[0]; // Disables the join section of this patch.
|
||||
prevJoinFitsInPatch = true;
|
||||
}
|
||||
}
|
||||
@ -511,14 +514,14 @@ private:
|
||||
// Recursively chops the given join until the segments fit in tessellation patches.
|
||||
void internalJoinTo(JoinType joinType, SkPoint junctionPoint, SkPoint nextControlPoint,
|
||||
int maxDepth = -1) {
|
||||
if (!fHasLastControlPoint) {
|
||||
if (!fPatchWriter.hasJoinControlPoint()) {
|
||||
// The first stroke doesn't have a previous join.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fSoloRoundJoinAlwaysFitsInPatch && maxDepth != 0 &&
|
||||
(joinType == JoinType::kRound || joinType == JoinType::kBowtie)) {
|
||||
SkVector tan0 = junctionPoint - fLastControlPoint;
|
||||
SkVector tan0 = junctionPoint - fPatchWriter.joinControlPoint();
|
||||
SkVector tan1 = nextControlPoint - junctionPoint;
|
||||
float rotation = SkMeasureAngleBetweenVectors(tan0, tan1);
|
||||
float numRadialSegments = rotation * fNumRadialSegmentsPerRadian;
|
||||
@ -548,7 +551,7 @@ private:
|
||||
} while (c0 - junctionPoint != -(c1 - junctionPoint) && --maxAttempts);
|
||||
// First join half.
|
||||
this->internalJoinTo(joinType, junctionPoint, c0, maxDepth - 1);
|
||||
fLastControlPoint = c1;
|
||||
fPatchWriter.updateJoinControlPointAttrib(c1);
|
||||
// Second join half.
|
||||
this->internalJoinTo(joinType, junctionPoint, nextControlPoint, maxDepth - 1);
|
||||
return;
|
||||
@ -556,11 +559,11 @@ private:
|
||||
}
|
||||
|
||||
// We should never write out joins before the first curve.
|
||||
SkASSERT(fHasLastControlPoint);
|
||||
SkASSERT(fPatchWriter.hasJoinControlPoint());
|
||||
|
||||
{
|
||||
HwPatch patch(fPatchWriter);
|
||||
patch << fLastControlPoint << junctionPoint;
|
||||
patch << junctionPoint;
|
||||
if (joinType == JoinType::kBowtie) {
|
||||
// {prevControlPoint, [p0, p0, p0, p3]} is a reserved patch pattern that means this
|
||||
// patch is a bowtie. The bowtie is anchored on p0 and its tangent angles go from
|
||||
@ -575,20 +578,7 @@ private:
|
||||
patch << (nextControlPoint);
|
||||
}
|
||||
|
||||
fLastControlPoint = nextControlPoint;
|
||||
}
|
||||
|
||||
void discardStroke(const SkPoint p[], int numPoints) {
|
||||
if (!fHasLastControlPoint) {
|
||||
// This disables the first join, if any. (The first join gets added as a standalone
|
||||
// patch during close(), but setting fCurrContourFirstControlPoint to p[0] causes us to
|
||||
// skip that join if we attempt to add it later.)
|
||||
fCurrContourFirstControlPoint = p[0];
|
||||
fHasLastControlPoint = true;
|
||||
}
|
||||
// Set fLastControlPoint to the next stroke's p0 (which will be equal to the final point of
|
||||
// this stroke). This has the effect of disabling the next stroke's join.
|
||||
fLastControlPoint = p[numPoints - 1];
|
||||
fPatchWriter.updateJoinControlPointAttrib(nextControlPoint);
|
||||
}
|
||||
|
||||
PatchWriter& fPatchWriter;
|
||||
@ -622,10 +612,8 @@ private:
|
||||
|
||||
// Variables related to the specific contour that we are currently iterating during
|
||||
// prepareBuffers().
|
||||
bool fHasLastControlPoint = false;
|
||||
SkPoint fCurrContourStartPoint;
|
||||
SkPoint fCurrContourFirstControlPoint;
|
||||
SkPoint fLastControlPoint;
|
||||
};
|
||||
|
||||
SK_ALWAYS_INLINE bool cubic_has_cusp(const SkPoint p[4]) {
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
PathStrokeList* fNext = nullptr;
|
||||
};
|
||||
|
||||
StrokeTessellator(PatchAttribs attribs) : fAttribs(attribs) {}
|
||||
StrokeTessellator(PatchAttribs attribs) : fAttribs(attribs | PatchAttribs::kJoinControlPoint) {}
|
||||
|
||||
// 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
|
||||
|
@ -72,13 +72,14 @@ SK_MAYBE_UNUSED constexpr static float kTessellationPrecision = 4;
|
||||
enum class PatchAttribs {
|
||||
// Attribs.
|
||||
kNone = 0,
|
||||
kFanPoint = 1 << 0, // [float2] Used by wedges. This is the center point the wedges fan around.
|
||||
kStrokeParams = 1 << 1, // [float2] Used when strokes have different widths or join types.
|
||||
kColor = 1 << 2, // [ubyte4 or float4] Used when patches have different colors.
|
||||
kExplicitCurveType = 1 << 3, // [float] Used when GPU can't infer curve type based on infinity.
|
||||
kJoinControlPoint = 1 << 0, // [float2] Used by strokes. This defines tangent direction.
|
||||
kFanPoint = 1 << 1, // [float2] Used by wedges. This is the center point the wedges fan around.
|
||||
kStrokeParams = 1 << 2, // [float2] Used when strokes have different widths or join types.
|
||||
kColor = 1 << 3, // [ubyte4 or float4] Used when patches have different colors.
|
||||
kExplicitCurveType = 1 << 4, // [float] Used when GPU can't infer curve type based on infinity.
|
||||
|
||||
// Extra flags.
|
||||
kWideColorIfEnabled = 1 << 4, // If kColor is set, specifies it to be float4 wide color.
|
||||
kWideColorIfEnabled = 1 << 5, // If kColor is set, specifies it to be float4 wide color.
|
||||
};
|
||||
|
||||
GR_MAKE_BITFIELD_CLASS_OPS(PatchAttribs)
|
||||
@ -125,7 +126,8 @@ constexpr static float kTriangularConicCurveType SK_MAYBE_UNUSED = 2; // Conic
|
||||
// Returns the packed size in bytes of the attribs portion of tessellation patches (or instances) in
|
||||
// GPU buffers.
|
||||
constexpr size_t PatchAttribsStride(PatchAttribs attribs) {
|
||||
return (attribs & PatchAttribs::kFanPoint ? sizeof(float) * 2 : 0) +
|
||||
return (attribs & PatchAttribs::kJoinControlPoint ? sizeof(float) * 2 : 0) +
|
||||
(attribs & PatchAttribs::kFanPoint ? sizeof(float) * 2 : 0) +
|
||||
(attribs & PatchAttribs::kStrokeParams ? sizeof(float) * 2 : 0) +
|
||||
(attribs & PatchAttribs::kColor
|
||||
? (attribs & PatchAttribs::kWideColorIfEnabled ? sizeof(float)
|
||||
|
@ -26,7 +26,7 @@ GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shade
|
||||
: GrPrimitiveType::kTriangleStrip,
|
||||
(mode == Mode::kHardwareTessellation) ? 1 : 0, viewMatrix, color)
|
||||
, fMode(mode)
|
||||
, fPatchAttribs(attribs)
|
||||
, fPatchAttribs(attribs | PatchAttribs::kJoinControlPoint)
|
||||
, fStroke(stroke)
|
||||
, fMaxParametricSegments_log2(maxParametricSegments_log2) {
|
||||
// We should use explicit curve type when, and only when, there isn't infinity support.
|
||||
@ -37,8 +37,6 @@ GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shade
|
||||
SkASSERT(!(attribs & PatchAttribs::kExplicitCurveType));
|
||||
}
|
||||
if (fMode == Mode::kHardwareTessellation) {
|
||||
// A join calculates its starting angle using prevCtrlPtAttr.
|
||||
fAttribs.emplace_back("prevCtrlPtAttr", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
|
||||
// pts 0..3 define the stroke as a cubic bezier. If p3.y is infinity, then it's a conic
|
||||
// with w=p3.x.
|
||||
//
|
||||
@ -52,6 +50,8 @@ GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shade
|
||||
// (p3 - p0).
|
||||
fAttribs.emplace_back("pts01Attr", kFloat4_GrVertexAttribType, SkSLType::kFloat4);
|
||||
fAttribs.emplace_back("pts23Attr", kFloat4_GrVertexAttribType, SkSLType::kFloat4);
|
||||
// A join calculates its starting angle using prevCtrlPtAttr.
|
||||
fAttribs.emplace_back("prevCtrlPtAttr", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
|
||||
} else {
|
||||
// pts 0..3 define the stroke as a cubic bezier. If p3.y is infinity, then it's a conic
|
||||
// with w=p3.x.
|
||||
@ -93,10 +93,10 @@ GrStrokeTessellationShader::GrStrokeTessellationShader(const GrShaderCaps& shade
|
||||
}
|
||||
if (fMode == Mode::kHardwareTessellation) {
|
||||
this->setVertexAttributesWithImplicitOffsets(fAttribs.data(), fAttribs.count());
|
||||
SkASSERT(this->vertexStride() == sizeof(SkPoint) * 5 + PatchAttribsStride(fPatchAttribs));
|
||||
SkASSERT(this->vertexStride() == sizeof(SkPoint) * 4 + PatchAttribsStride(fPatchAttribs));
|
||||
} else {
|
||||
this->setInstanceAttributesWithImplicitOffsets(fAttribs.data(), fAttribs.count());
|
||||
SkASSERT(this->instanceStride() == sizeof(SkPoint) * 5 + PatchAttribsStride(fPatchAttribs));
|
||||
SkASSERT(this->instanceStride() == sizeof(SkPoint) * 4 + PatchAttribsStride(fPatchAttribs));
|
||||
if (!shaderCaps.vertexIDSupport()) {
|
||||
constexpr static Attribute kVertexAttrib("edgeID", kFloat_GrVertexAttribType,
|
||||
SkSLType::kFloat);
|
||||
|
Loading…
Reference in New Issue
Block a user