aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ccpr
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-08-01 15:36:01 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-08-02 05:40:36 +0000
commit21171e50f486a7234e1d8edeb0977719c81d5d3b (patch)
treeade0cc2f702f9d6c8e7f26036d143865a02023db /src/gpu/ccpr
parent19391ac4d393874797e1d34970fecf0f0182bf98 (diff)
CCPR: Transform path points before handling curves
Does the transform before handling curves. This way all curves can be carefully chopped in device space in order two avoid msaa. Bug: skia: Change-Id: I0508668142cda3fe3fda41f8475c408288aa4a47 Reviewed-on: https://skia-review.googlesource.com/29720 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'src/gpu/ccpr')
-rw-r--r--src/gpu/ccpr/GrCCPRCoverageOpsBuilder.cpp160
-rw-r--r--src/gpu/ccpr/GrCCPRCoverageOpsBuilder.h15
2 files changed, 85 insertions, 90 deletions
diff --git a/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.cpp b/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.cpp
index 5beba4cf76..93e81ae0e0 100644
--- a/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.cpp
+++ b/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.cpp
@@ -66,7 +66,7 @@ private:
* and "45 degree" device-space bounds (| 1 -1 | * devCoords).
* | 1 1 |
*/
-class GrCCPRCoverageOpsBuilder::AccumulatingViewMatrix {
+class AccumulatingViewMatrix {
public:
AccumulatingViewMatrix(const SkMatrix& m, const SkPoint& initialPoint);
@@ -158,6 +158,59 @@ bool GrCCPRCoverageOpsBuilder::init(GrOnFlushResourceProvider* onFlushRP,
return true;
}
+using MaxBufferItems = GrCCPRCoverageOpsBuilder::MaxBufferItems;
+
+void MaxBufferItems::countPathItems(GrCCPRCoverageOpsBuilder::ScissorMode scissorMode,
+ const SkPath& path) {
+ MaxPrimitives& maxPrimitives = fMaxPrimitives[(int)scissorMode];
+ int currFanPts = 0;
+
+ for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ case SkPath::kClose_Verb:
+ fMaxFanPoints += currFanPts;
+ maxPrimitives.fMaxTriangles += SkTMax(0, currFanPts - 2);
+ currFanPts = SkPath::kMove_Verb == verb ? 1 : 0;
+ continue;
+ case SkPath::kLine_Verb:
+ SkASSERT(currFanPts > 0);
+ ++currFanPts;
+ continue;
+ case SkPath::kQuad_Verb:
+ SkASSERT(currFanPts > 0);
+ ++currFanPts;
+ ++fMaxControlPoints;
+ ++maxPrimitives.fMaxQuadratics;
+ continue;
+ case SkPath::kCubic_Verb:
+ SkASSERT(currFanPts > 0);
+ // Over-allocate for the worst case when the cubic is chopped into 3 segments.
+ enum { kMaxSegments = 3 };
+ currFanPts += kMaxSegments;
+ // Each cubic segment has two control points.
+ fMaxControlPoints += kMaxSegments * 2;
+ // Each cubic segment also emits two root t,s values as "control points".
+ fMaxControlPoints += kMaxSegments * 2;
+ maxPrimitives.fMaxCubics += kMaxSegments;
+ // The cubic may also turn out to be a quadratic. While we over-allocate by a fair
+ // amount, this is still a relatively small amount of space.
+ ++maxPrimitives.fMaxQuadratics;
+ continue;
+ case SkPath::kConic_Verb:
+ SkASSERT(currFanPts > 0);
+ SkFAIL("Conics are not supported.");
+ default:
+ SkFAIL("Unexpected path verb.");
+ }
+ }
+
+ fMaxFanPoints += currFanPts;
+ maxPrimitives.fMaxTriangles += SkTMax(0, currFanPts - 2);
+
+ ++fMaxPaths;
+}
+
void GrCCPRCoverageOpsBuilder::parsePath(ScissorMode scissorMode, const SkMatrix& viewMatrix,
const SkPath& path, SkRect* devBounds,
SkRect* devBounds45) {
@@ -179,21 +232,22 @@ void GrCCPRCoverageOpsBuilder::parsePath(ScissorMode scissorMode, const SkMatrix
for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
switch (verb) {
case SkPath::kMove_Verb:
- this->startContour(m, pts[ptsIdx++]);
+ this->startContour(m.transform(pts[ptsIdx++]));
continue;
case SkPath::kClose_Verb:
this->closeContour();
continue;
case SkPath::kLine_Verb:
- this->fanTo(m, pts[ptsIdx]);
+ this->fanTo(m.transform(pts[ptsIdx]));
break;
case SkPath::kQuad_Verb:
SkASSERT(ptsIdx >= 1); // SkPath should have inserted an implicit moveTo if needed.
- this->quadraticTo(m, &pts[ptsIdx - 1]);
+ this->quadraticTo(m.transform(pts[ptsIdx]), m.transform(pts[ptsIdx + 1]));
break;
case SkPath::kCubic_Verb:
SkASSERT(ptsIdx >= 1); // SkPath should have inserted an implicit moveTo if needed.
- this->cubicTo(m, &pts[ptsIdx - 1]);
+ this->cubicTo(m.transform(pts[ptsIdx]), m.transform(pts[ptsIdx + 1]),
+ m.transform(pts[ptsIdx + 2]));
break;
case SkPath::kConic_Verb:
SkFAIL("Conics are not supported.");
@@ -235,27 +289,26 @@ void GrCCPRCoverageOpsBuilder::saveParsedPath(const SkIRect& clippedDevIBounds,
fInstanceIndices[(int)fCurrScissorMode] = fCurrPathIndices;
}
-void GrCCPRCoverageOpsBuilder::startContour(AccumulatingViewMatrix& m, const SkPoint& anchorPoint) {
+void GrCCPRCoverageOpsBuilder::startContour(const SkPoint& anchorPoint) {
this->closeContour();
- fCurrPathSpaceAnchorPoint = anchorPoint;
- fPointsData[fFanPtsIdx++] = m.transform(anchorPoint);
+ fPointsData[fFanPtsIdx++] = fCurrAnchorPoint = fCurrFanPoint = anchorPoint;
SkASSERT(fCurrContourStartIdx == fFanPtsIdx - 1);
}
-void GrCCPRCoverageOpsBuilder::fanTo(AccumulatingViewMatrix& m, const SkPoint& pt) {
+void GrCCPRCoverageOpsBuilder::fanTo(const SkPoint& pt) {
SkASSERT(fCurrContourStartIdx < fFanPtsIdx);
- if (pt == fCurrPathSpaceAnchorPoint) {
- this->startContour(m, pt);
+ if (pt == fCurrAnchorPoint) {
+ this->startContour(pt);
return;
}
- fPointsData[fFanPtsIdx++] = m.transform(pt);
+ fPointsData[fFanPtsIdx++] = fCurrFanPoint = pt;
}
-void GrCCPRCoverageOpsBuilder::quadraticTo(AccumulatingViewMatrix& m, const SkPoint P[3]) {
+void GrCCPRCoverageOpsBuilder::quadraticTo(SkPoint controlPt, SkPoint endPt) {
SkASSERT(fCurrPathIndices.fQuadratics < fBaseInstances[(int)fCurrScissorMode].fSerpentines);
- this->fanTo(m, P[2]);
- fPointsData[fControlPtsIdx++] = m.transform(P[1]);
+ this->fanTo(endPt);
+ fPointsData[fControlPtsIdx++] = controlPt;
fInstanceData[fCurrPathIndices.fQuadratics++].fQuadraticData = {
fControlPtsIdx - 1,
@@ -263,12 +316,13 @@ void GrCCPRCoverageOpsBuilder::quadraticTo(AccumulatingViewMatrix& m, const SkPo
};
}
-void GrCCPRCoverageOpsBuilder::cubicTo(AccumulatingViewMatrix& m, const SkPoint P[4]) {
+void GrCCPRCoverageOpsBuilder::cubicTo(SkPoint controlPt1, SkPoint controlPt2, SkPoint endPt) {
+ SkPoint P[4] = {fCurrFanPoint, controlPt1, controlPt2, endPt};
double t[2], s[2];
SkCubicType type = SkClassifyCubic(P, t, s);
if (SkCubicType::kLineOrPoint == type) {
- this->fanTo(m, P[3]);
+ this->fanTo(P[3]);
return;
}
@@ -278,8 +332,7 @@ void GrCCPRCoverageOpsBuilder::cubicTo(AccumulatingViewMatrix& m, const SkPoint
SkScalar x2 = P[2].y() - P[3].y(), y2 = P[3].x() - P[2].x(),
k2 = x2 * P[3].x() + y2 * P[3].y();
SkScalar rdet = 1 / (x1*y2 - y1*x2);
- SkPoint Q[3] = {P[0], {(y2*k1 - y1*k2) * rdet, (x1*k2 - x2*k1) * rdet}, P[3]};
- this->quadraticTo(m, Q);
+ this->quadraticTo({(y2*k1 - y1*k2) * rdet, (x1*k2 - x2*k1) * rdet}, P[3]);
return;
}
@@ -310,7 +363,7 @@ void GrCCPRCoverageOpsBuilder::cubicTo(AccumulatingViewMatrix& m, const SkPoint
}
// (This might put ts0/ts1 out of order, but it doesn't matter anymore at this point.)
- this->emitCubicSegment(m, type, chopped.first(),
+ this->emitCubicSegment(type, chopped.first(),
to_skpoint(t[1 - x], s[1 - x] * chopT), to_skpoint(1, 1));
t[x] = 0;
s[x] = 1;
@@ -322,17 +375,16 @@ void GrCCPRCoverageOpsBuilder::cubicTo(AccumulatingViewMatrix& m, const SkPoint
C = chopped.second();
}
- this->emitCubicSegment(m, type, C, to_skpoint(t[0], s[0]), to_skpoint(t[1], s[1]));
+ this->emitCubicSegment(type, C, to_skpoint(t[0], s[0]), to_skpoint(t[1], s[1]));
}
-void GrCCPRCoverageOpsBuilder::emitCubicSegment(AccumulatingViewMatrix& m,
- SkCubicType type, const SkDCubic& C,
+void GrCCPRCoverageOpsBuilder::emitCubicSegment(SkCubicType type, const SkDCubic& C,
const SkPoint& ts0, const SkPoint& ts1) {
SkASSERT(fCurrPathIndices.fSerpentines < fCurrPathIndices.fLoops);
- fPointsData[fControlPtsIdx++] = m.transform(to_skpoint(C[1]));
- fPointsData[fControlPtsIdx++] = m.transform(to_skpoint(C[2]));
- this->fanTo(m, to_skpoint(C[3]));
+ fPointsData[fControlPtsIdx++] = to_skpoint(C[1]);
+ fPointsData[fControlPtsIdx++] = to_skpoint(C[2]);
+ this->fanTo(to_skpoint(C[3]));
// Also emit the cubic's root t,s values as "control points".
fPointsData[fControlPtsIdx++] = ts0;
@@ -420,60 +472,6 @@ void GrCCPRCoverageOpsBuilder::validate() {
#endif
-using MaxBufferItems = GrCCPRCoverageOpsBuilder::MaxBufferItems;
-
-void MaxBufferItems::countPathItems(GrCCPRCoverageOpsBuilder::ScissorMode scissorMode,
- const SkPath& path) {
- MaxPrimitives& maxPrimitives = fMaxPrimitives[(int)scissorMode];
- int currFanPts = 0;
-
- for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
- switch (verb) {
- case SkPath::kMove_Verb:
- case SkPath::kClose_Verb:
- fMaxFanPoints += currFanPts;
- maxPrimitives.fMaxTriangles += SkTMax(0, currFanPts - 2);
- currFanPts = SkPath::kMove_Verb == verb ? 1 : 0;
- continue;
- case SkPath::kLine_Verb:
- SkASSERT(currFanPts > 0);
- ++currFanPts;
- continue;
- case SkPath::kQuad_Verb:
- SkASSERT(currFanPts > 0);
- ++currFanPts;
- ++fMaxControlPoints;
- ++maxPrimitives.fMaxQuadratics;
- continue;
- case SkPath::kCubic_Verb: {
- SkASSERT(currFanPts > 0);
- // Over-allocate for the worst case when the cubic is chopped into 3 segments.
- static constexpr int kMaxSegments = 3;
- currFanPts += kMaxSegments;
- // Each cubic segment has two control points.
- fMaxControlPoints += kMaxSegments * 2;
- // Each cubic segment also emits two root t,s values as "control points".
- fMaxControlPoints += kMaxSegments * 2;
- maxPrimitives.fMaxCubics += kMaxSegments;
- // The cubic may also turn out to be a quadratic. While we over-allocate by a fair
- // amount, this is still a relatively small amount of space.
- ++maxPrimitives.fMaxQuadratics;
- continue;
- }
- case SkPath::kConic_Verb:
- SkASSERT(currFanPts > 0);
- SkFAIL("Conics are not supported.");
- default:
- SkFAIL("Unexpected path verb.");
- }
- }
-
- fMaxFanPoints += currFanPts;
- maxPrimitives.fMaxTriangles += SkTMax(0, currFanPts - 2);
-
- ++fMaxPaths;
-}
-
using CoverageOp = GrCCPRCoverageOpsBuilder::CoverageOp;
GrCCPRCoverageOpsBuilder::CoverageOp::CoverageOp(const SkISize& drawBounds,
@@ -597,8 +595,6 @@ inline int PrimitiveTallies::sum() const {
return fTriangles + fQuadratics + fSerpentines + fLoops;
}
-using AccumulatingViewMatrix = GrCCPRCoverageOpsBuilder::AccumulatingViewMatrix;
-
inline AccumulatingViewMatrix::AccumulatingViewMatrix(const SkMatrix& m,
const SkPoint& initialPoint) {
// m45 transforms into 45 degree space in order to find the octagon's diagonals. We could
diff --git a/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.h b/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.h
index 92d0203e8f..710ee88206 100644
--- a/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.h
+++ b/src/gpu/ccpr/GrCCPRCoverageOpsBuilder.h
@@ -95,7 +95,6 @@ public:
std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT finalize(SkISize drawBounds);
class CoverageOp;
- class AccumulatingViewMatrix;
private:
using PrimitiveInstance = GrCCPRCoverageProcessor::PrimitiveInstance;
@@ -116,12 +115,11 @@ private:
SkIRect fScissor;
};
- void startContour(AccumulatingViewMatrix&, const SkPoint& anchorPoint);
- void fanTo(AccumulatingViewMatrix&, const SkPoint& pt);
- void quadraticTo(AccumulatingViewMatrix&, const SkPoint P[3]);
- void cubicTo(AccumulatingViewMatrix&, const SkPoint P[4]);
- void emitCubicSegment(AccumulatingViewMatrix&, SkCubicType, const SkDCubic&,
- const SkPoint& ts0, const SkPoint& ts1);
+ void startContour(const SkPoint& anchorPoint);
+ void fanTo(const SkPoint& pt);
+ void quadraticTo(SkPoint controlPt, SkPoint endPt);
+ void cubicTo(SkPoint controlPt1, SkPoint controlPt2, SkPoint endPt);
+ void emitCubicSegment(SkCubicType, const SkDCubic&, const SkPoint& ts0, const SkPoint& ts1);
void closeContour();
void emitHierarchicalFan(int32_t indices[], int count);
SkDEBUGCODE(void validate();)
@@ -129,7 +127,8 @@ private:
ScissorMode fCurrScissorMode;
PrimitiveTallies fCurrPathIndices;
int32_t fCurrContourStartIdx;
- SkPoint fCurrPathSpaceAnchorPoint;
+ SkPoint fCurrAnchorPoint;
+ SkPoint fCurrFanPoint;
sk_sp<GrBuffer> fPointsBuffer;
SkPoint* fPointsData;