Flutter Engine
The Flutter Engine
Classes | Public Member Functions | Friends | List of all members
GrQuadUtils::TessellationHelper Class Reference

#include <GrQuadUtils.h>

Public Member Functions

void reset (const GrQuad &deviceQuad, const GrQuad *localQuad)
 
skvx::float4 inset (const skvx::float4 &edgeDistances, GrQuad *deviceInset, GrQuad *localInset)
 
void outset (const skvx::float4 &edgeDistances, GrQuad *deviceOutset, GrQuad *localOutset)
 
void getEdgeEquations (skvx::float4 *a, skvx::float4 *b, skvx::float4 *c)
 
skvx::float4 getEdgeLengths ()
 
bool isSubpixel ()
 

Friends

int ClipToW0 (DrawQuad *, DrawQuad *)
 

Detailed Description

Definition at line 55 of file GrQuadUtils.h.

Member Function Documentation

◆ getEdgeEquations()

void GrQuadUtils::TessellationHelper::getEdgeEquations ( skvx::float4 a,
skvx::float4 b,
skvx::float4 c 
)

Definition at line 1178 of file GrQuadUtils.cpp.

1180 {
1181 SkASSERT(a && b && c);
1182 SkASSERT(fVerticesValid);
1183 const EdgeEquations& eq = this->getEdgeEquations();
1184 *a = eq.fA;
1185 *b = eq.fB;
1186 *c = eq.fC;
1187}
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
Definition: M44Test.cpp:18
#define SkASSERT(cond)
Definition: SkAssert.h:116
void getEdgeEquations(skvx::float4 *a, skvx::float4 *b, skvx::float4 *c)
static bool b
struct MyStruct a[10]

◆ getEdgeLengths()

skvx::Vec< 4, float > GrQuadUtils::TessellationHelper::getEdgeLengths ( )

Definition at line 1189 of file GrQuadUtils.cpp.

1189 {
1190 SkASSERT(fVerticesValid);
1191 return 1.f / fEdgeVectors.fInvLengths;
1192}

◆ inset()

float4 GrQuadUtils::TessellationHelper::inset ( const skvx::float4 edgeDistances,
GrQuad deviceInset,
GrQuad localInset 
)

Definition at line 1138 of file GrQuadUtils.cpp.

1139 {
1140 SkASSERT(fVerticesValid);
1141
1142 Vertices inset = fOriginal;
1143 const OutsetRequest& request = this->getOutsetRequest(edgeDistances);
1144 int vertexCount;
1145 if (request.fInsetDegenerate) {
1146 vertexCount = this->adjustDegenerateVertices(-request.fEdgeDistances, &inset);
1147 } else {
1148 this->adjustVertices(-request.fEdgeDistances, &inset);
1149 vertexCount = 4;
1150 }
1151
1152 inset.asGrQuads(deviceInset, fDeviceType, localInset, fLocalType);
1153 if (vertexCount < 3) {
1154 // The interior has less than a full pixel's area so estimate reduced coverage using
1155 // the distance of the inset's projected corners to the original edges.
1156 return this->getEdgeEquations().estimateCoverage(inset.fX / inset.fW,
1157 inset.fY / inset.fW);
1158 } else {
1159 return 1.f;
1160 }
1161}
skvx::float4 inset(const skvx::float4 &edgeDistances, GrQuad *deviceInset, GrQuad *localInset)

◆ isSubpixel()

bool GrQuadUtils::TessellationHelper::isSubpixel ( )

Definition at line 1208 of file GrQuadUtils.cpp.

1208 {
1209 SkASSERT(fVerticesValid);
1210 if (fDeviceType <= GrQuad::Type::kRectilinear) {
1211 // Check the edge lengths, if the shortest is less than 1px it's degenerate, which is the
1212 // same as if the max 1/length is greater than 1px.
1213 return any(fEdgeVectors.fInvLengths > 1.f);
1214 } else {
1215 // Compute edge equations and then distance from each vertex to the opposite edges.
1216 return this->getEdgeEquations().isSubpixel(fEdgeVectors.fX2D, fEdgeVectors.fY2D);
1217 }
1218}
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530

◆ outset()

void GrQuadUtils::TessellationHelper::outset ( const skvx::float4 edgeDistances,
GrQuad deviceOutset,
GrQuad localOutset 
)

Definition at line 1163 of file GrQuadUtils.cpp.

1164 {
1165 SkASSERT(fVerticesValid);
1166
1167 Vertices outset = fOriginal;
1168 const OutsetRequest& request = this->getOutsetRequest(edgeDistances);
1169 if (request.fOutsetDegenerate) {
1170 this->adjustDegenerateVertices(request.fEdgeDistances, &outset);
1171 } else {
1172 this->adjustVertices(request.fEdgeDistances, &outset);
1173 }
1174
1175 outset.asGrQuads(deviceOutset, fDeviceType, localOutset, fLocalType);
1176}
void outset(const skvx::float4 &edgeDistances, GrQuad *deviceOutset, GrQuad *localOutset)

◆ reset()

void GrQuadUtils::TessellationHelper::reset ( const GrQuad deviceQuad,
const GrQuad localQuad 
)

Definition at line 1122 of file GrQuadUtils.cpp.

1122 {
1123 // Record basic state that isn't recorded on the Vertices struct itself
1124 fDeviceType = deviceQuad.quadType();
1125 fLocalType = localQuad ? localQuad->quadType() : GrQuad::Type::kAxisAligned;
1126
1127 // Reset metadata validity
1128 fOutsetRequestValid = false;
1129 fEdgeEquationsValid = false;
1130
1131 // Compute vertex properties that are always needed for a quad, so no point in doing it lazily.
1132 fOriginal.reset(deviceQuad, localQuad);
1133 fEdgeVectors.reset(fOriginal.fX, fOriginal.fY, fOriginal.fW, fDeviceType);
1134
1135 fVerticesValid = true;
1136}
Type quadType() const
Definition: GrQuad.h:118

Friends And Related Function Documentation

◆ ClipToW0

int ClipToW0 ( DrawQuad ,
DrawQuad  
)
friend

Clip the device vertices of 'quad' to be in front of the W = 0 plane (w/in epsilon). The local coordinates will be updated to match the new clipped vertices. This returns the number of clipped quads that need to be drawn: 0 if 'quad' was entirely behind the plane, 1 if 'quad' did not need to be clipped or if 2 or 3 vertices were clipped, or 2 if 'quad' had one vertex clipped (producing a pentagonal shape spanned by 'quad' and 'extraVertices').

Definition at line 399 of file GrQuadUtils.cpp.

399 {
400 using Vertices = TessellationHelper::Vertices;
401
402 SkASSERT(quad && extraVertices);
403
405 // W implicitly 1s for each vertex, so nothing to do but draw unmodified 'quad'
406 return 1;
407 }
408
409 mask4 validW = quad->fDevice.w4f() >= SkPathPriv::kW0PlaneDistance;
410 if (all(validW)) {
411 // Nothing to clip, can proceed normally drawing just 'quad'
412 return 1;
413 } else if (!any(validW)) {
414 // Everything is clipped, so draw nothing
415 return 0;
416 }
417
418 // The clipped local coordinates will most likely not remain rectilinear
419 GrQuad::Type localType = quad->fLocal.quadType();
420 if (localType < GrQuad::Type::kGeneral) {
421 localType = GrQuad::Type::kGeneral;
422 }
423
424 // If we got here, there are 1, 2, or 3 points behind the w = 0 plane. If 2 or 3 points are
425 // clipped we can define a new quad that covers the clipped shape directly. If there's 1 clipped
426 // out, the new geometry is a pentagon.
427 Vertices v;
428 v.reset(quad->fDevice, &quad->fLocal);
429
430 int clipCount = (validW[0] ? 0 : 1) + (validW[1] ? 0 : 1) +
431 (validW[2] ? 0 : 1) + (validW[3] ? 0 : 1);
432 SkASSERT(clipCount >= 1 && clipCount <= 3);
433
434 // FIXME de-duplicate from the projectedBounds() calculations.
435 float4 t = (SkPathPriv::kW0PlaneDistance - v.fW) / (next_ccw(v.fW) - v.fW);
436
437 Vertices clip;
438 clip.fX = (t * next_ccw(v.fX) + (1.f - t) * v.fX);
439 clip.fY = (t * next_ccw(v.fY) + (1.f - t) * v.fY);
441
442 clip.fU = (t * next_ccw(v.fU) + (1.f - t) * v.fU);
443 clip.fV = (t * next_ccw(v.fV) + (1.f - t) * v.fV);
444 clip.fR = (t * next_ccw(v.fR) + (1.f - t) * v.fR);
445
446 mask4 ccwValid = next_ccw(v.fW) >= SkPathPriv::kW0PlaneDistance;
447 mask4 cwValid = next_cw(v.fW) >= SkPathPriv::kW0PlaneDistance;
448
449 if (clipCount != 1) {
450 // Simplest case, replace behind-w0 points with their clipped points by following CCW edge
451 // or CW edge, depending on if the edge crosses from neg. to pos. w or pos. to neg.
452 SkASSERT(clipCount == 2 || clipCount == 3);
453
454 // NOTE: when 3 vertices are clipped, this results in a degenerate quad where one vertex
455 // is replicated. This is preferably to inserting a 3rd vertex on the w = 0 intersection
456 // line because two parallel edges make inset/outset math unstable for large quads.
457 v.fX = if_then_else(validW, v.fX,
458 if_then_else((!ccwValid) & (!cwValid), next_ccw(clip.fX),
459 if_then_else(ccwValid, clip.fX, /* cwValid */ next_cw(clip.fX))));
460 v.fY = if_then_else(validW, v.fY,
461 if_then_else((!ccwValid) & (!cwValid), next_ccw(clip.fY),
462 if_then_else(ccwValid, clip.fY, /* cwValid */ next_cw(clip.fY))));
463 v.fW = if_then_else(validW, v.fW, clip.fW);
464
465 v.fU = if_then_else(validW, v.fU,
466 if_then_else((!ccwValid) & (!cwValid), next_ccw(clip.fU),
467 if_then_else(ccwValid, clip.fU, /* cwValid */ next_cw(clip.fU))));
468 v.fV = if_then_else(validW, v.fV,
469 if_then_else((!ccwValid) & (!cwValid), next_ccw(clip.fV),
470 if_then_else(ccwValid, clip.fV, /* cwValid */ next_cw(clip.fV))));
471 v.fR = if_then_else(validW, v.fR,
472 if_then_else((!ccwValid) & (!cwValid), next_ccw(clip.fR),
473 if_then_else(ccwValid, clip.fR, /* cwValid */ next_cw(clip.fR))));
474
475 // For 2 or 3 clipped vertices, the resulting shape is a quad or a triangle, so it can be
476 // entirely represented in 'quad'.
477 v.asGrQuads(&quad->fDevice, GrQuad::Type::kPerspective,
478 &quad->fLocal, localType);
479 return 1;
480 } else {
481 // The clipped geometry is a pentagon, so it will be represented as two quads connected by
482 // a new non-AA edge. Use the midpoint along one of the unclipped edges as a split vertex.
483 Vertices mid;
484 mid.fX = 0.5f * (v.fX + next_ccw(v.fX));
485 mid.fY = 0.5f * (v.fY + next_ccw(v.fY));
486 mid.fW = 0.5f * (v.fW + next_ccw(v.fW));
487
488 mid.fU = 0.5f * (v.fU + next_ccw(v.fU));
489 mid.fV = 0.5f * (v.fV + next_ccw(v.fV));
490 mid.fR = 0.5f * (v.fR + next_ccw(v.fR));
491
492 // Make a quad formed by the 2 clipped points, the inserted mid point, and the good vertex
493 // that is CCW rotated from the clipped vertex.
494 Vertices v2;
495 v2.fUVRCount = v.fUVRCount;
496 v2.fX = if_then_else((!validW) | (!ccwValid), clip.fX,
497 if_then_else(cwValid, next_cw(mid.fX), v.fX));
498 v2.fY = if_then_else((!validW) | (!ccwValid), clip.fY,
499 if_then_else(cwValid, next_cw(mid.fY), v.fY));
500 v2.fW = if_then_else((!validW) | (!ccwValid), clip.fW,
501 if_then_else(cwValid, next_cw(mid.fW), v.fW));
502
503 v2.fU = if_then_else((!validW) | (!ccwValid), clip.fU,
504 if_then_else(cwValid, next_cw(mid.fU), v.fU));
505 v2.fV = if_then_else((!validW) | (!ccwValid), clip.fV,
506 if_then_else(cwValid, next_cw(mid.fV), v.fV));
507 v2.fR = if_then_else((!validW) | (!ccwValid), clip.fR,
508 if_then_else(cwValid, next_cw(mid.fR), v.fR));
509 // The non-AA edge for this quad is the opposite of the clipped vertex's edge
510 GrQuadAAFlags v2EdgeFlag = (!validW[0] ? GrQuadAAFlags::kRight : // left clipped -> right
511 (!validW[1] ? GrQuadAAFlags::kTop : // bottom clipped -> top
512 (!validW[2] ? GrQuadAAFlags::kBottom : // top clipped -> bottom
513 GrQuadAAFlags::kLeft))); // right clipped -> left
514 extraVertices->fEdgeFlags = quad->fEdgeFlags & ~v2EdgeFlag;
515
516 // Make a quad formed by the remaining two good vertices, one clipped point, and the
517 // inserted mid point.
518 v.fX = if_then_else(!validW, next_cw(clip.fX),
519 if_then_else(!cwValid, mid.fX, v.fX));
520 v.fY = if_then_else(!validW, next_cw(clip.fY),
521 if_then_else(!cwValid, mid.fY, v.fY));
522 v.fW = if_then_else(!validW, clip.fW,
523 if_then_else(!cwValid, mid.fW, v.fW));
524
525 v.fU = if_then_else(!validW, next_cw(clip.fU),
526 if_then_else(!cwValid, mid.fU, v.fU));
527 v.fV = if_then_else(!validW, next_cw(clip.fV),
528 if_then_else(!cwValid, mid.fV, v.fV));
529 v.fR = if_then_else(!validW, next_cw(clip.fR),
530 if_then_else(!cwValid, mid.fR, v.fR));
531 // The non-AA edge for this quad is the clipped vertex's edge
532 GrQuadAAFlags v1EdgeFlag = (!validW[0] ? GrQuadAAFlags::kLeft :
533 (!validW[1] ? GrQuadAAFlags::kBottom :
534 (!validW[2] ? GrQuadAAFlags::kTop :
536
537 v.asGrQuads(&quad->fDevice, GrQuad::Type::kPerspective,
538 &quad->fLocal, localType);
539 quad->fEdgeFlags &= ~v1EdgeFlag;
540
541 v2.asGrQuads(&extraVertices->fDevice, GrQuad::Type::kPerspective,
542 &extraVertices->fLocal, localType);
543 // Caller must draw both 'quad' and 'extraVertices' to cover the clipped geometry
544 return 2;
545 }
546}
static AI skvx::Vec< 4, T > next_ccw(const skvx::Vec< 4, T > &v)
Definition: GrQuadUtils.cpp:43
static AI skvx::Vec< 4, T > next_cw(const skvx::Vec< 4, T > &v)
Definition: GrQuadUtils.cpp:38
GrQuadAAFlags
Definition: GrTypesPriv.h:247
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
SI T if_then_else(C cond, T t, T e)
Vec2Value v2
Type
Definition: GrQuad.h:35
skvx::Vec< 4, float > w4f() const
Definition: GrQuad.h:115
static constexpr SkScalar kW0PlaneDistance
Definition: SkPathPriv.h:41
SIT bool all(const Vec< 1, T > &x)
Definition: SkVx.h:582
GrQuad fLocal
Definition: GrQuad.h:186
GrQuad fDevice
Definition: GrQuad.h:185
GrQuadAAFlags fEdgeFlags
Definition: GrQuad.h:187
Definition: SkVx.h:83

The documentation for this class was generated from the following files: