Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Unified Diff: src/gpu/GrAAConvexPathRenderer.cpp

Issue 1306143005: Move Pathrenderers to batches folder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: rebase Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/GrAAConvexPathRenderer.h ('k') | src/gpu/GrAAConvexTessellator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrAAConvexPathRenderer.cpp
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
deleted file mode 100644
index 6023f188df8535127180c8480227068d59315d13..0000000000000000000000000000000000000000
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ /dev/null
@@ -1,1022 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrAAConvexPathRenderer.h"
-
-#include "GrAAConvexTessellator.h"
-#include "GrBatchFlushState.h"
-#include "GrBatchTest.h"
-#include "GrCaps.h"
-#include "GrContext.h"
-#include "GrDefaultGeoProcFactory.h"
-#include "GrGeometryProcessor.h"
-#include "GrInvariantOutput.h"
-#include "GrPathUtils.h"
-#include "GrProcessor.h"
-#include "GrPipelineBuilder.h"
-#include "GrStrokeInfo.h"
-#include "SkGeometry.h"
-#include "SkPathPriv.h"
-#include "SkString.h"
-#include "SkTraceEvent.h"
-#include "batches/GrVertexBatch.h"
-#include "gl/GrGLProcessor.h"
-#include "gl/GrGLGeometryProcessor.h"
-#include "gl/builders/GrGLProgramBuilder.h"
-
-GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
-}
-
-struct Segment {
- enum {
- // These enum values are assumed in member functions below.
- kLine = 0,
- kQuad = 1,
- } fType;
-
- // line uses one pt, quad uses 2 pts
- SkPoint fPts[2];
- // normal to edge ending at each pt
- SkVector fNorms[2];
- // is the corner where the previous segment meets this segment
- // sharp. If so, fMid is a normalized bisector facing outward.
- SkVector fMid;
-
- int countPoints() {
- GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
- return fType + 1;
- }
- const SkPoint& endPt() const {
- GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
- return fPts[fType];
- };
- const SkPoint& endNorm() const {
- GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
- return fNorms[fType];
- };
-};
-
-typedef SkTArray<Segment, true> SegmentArray;
-
-static void center_of_mass(const SegmentArray& segments, SkPoint* c) {
- SkScalar area = 0;
- SkPoint center = {0, 0};
- int count = segments.count();
- SkPoint p0 = {0, 0};
- if (count > 2) {
- // We translate the polygon so that the first point is at the origin.
- // This avoids some precision issues with small area polygons far away
- // from the origin.
- p0 = segments[0].endPt();
- SkPoint pi;
- SkPoint pj;
- // the first and last iteration of the below loop would compute
- // zeros since the starting / ending point is (0,0). So instead we start
- // at i=1 and make the last iteration i=count-2.
- pj = segments[1].endPt() - p0;
- for (int i = 1; i < count - 1; ++i) {
- pi = pj;
- const SkPoint pj = segments[i + 1].endPt() - p0;
-
- SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
- area += t;
- center.fX += (pi.fX + pj.fX) * t;
- center.fY += (pi.fY + pj.fY) * t;
-
- }
- }
- // If the poly has no area then we instead return the average of
- // its points.
- if (SkScalarNearlyZero(area)) {
- SkPoint avg;
- avg.set(0, 0);
- for (int i = 0; i < count; ++i) {
- const SkPoint& pt = segments[i].endPt();
- avg.fX += pt.fX;
- avg.fY += pt.fY;
- }
- SkScalar denom = SK_Scalar1 / count;
- avg.scale(denom);
- *c = avg;
- } else {
- area *= 3;
- area = SkScalarInvert(area);
- center.fX = SkScalarMul(center.fX, area);
- center.fY = SkScalarMul(center.fY, area);
- // undo the translate of p0 to the origin.
- *c = center + p0;
- }
- SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
-}
-
-static void compute_vectors(SegmentArray* segments,
- SkPoint* fanPt,
- SkPathPriv::FirstDirection dir,
- int* vCount,
- int* iCount) {
- center_of_mass(*segments, fanPt);
- int count = segments->count();
-
- // Make the normals point towards the outside
- SkPoint::Side normSide;
- if (dir == SkPathPriv::kCCW_FirstDirection) {
- normSide = SkPoint::kRight_Side;
- } else {
- normSide = SkPoint::kLeft_Side;
- }
-
- *vCount = 0;
- *iCount = 0;
- // compute normals at all points
- for (int a = 0; a < count; ++a) {
- Segment& sega = (*segments)[a];
- int b = (a + 1) % count;
- Segment& segb = (*segments)[b];
-
- const SkPoint* prevPt = &sega.endPt();
- int n = segb.countPoints();
- for (int p = 0; p < n; ++p) {
- segb.fNorms[p] = segb.fPts[p] - *prevPt;
- segb.fNorms[p].normalize();
- segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
- prevPt = &segb.fPts[p];
- }
- if (Segment::kLine == segb.fType) {
- *vCount += 5;
- *iCount += 9;
- } else {
- *vCount += 6;
- *iCount += 12;
- }
- }
-
- // compute mid-vectors where segments meet. TODO: Detect shallow corners
- // and leave out the wedges and close gaps by stitching segments together.
- for (int a = 0; a < count; ++a) {
- const Segment& sega = (*segments)[a];
- int b = (a + 1) % count;
- Segment& segb = (*segments)[b];
- segb.fMid = segb.fNorms[0] + sega.endNorm();
- segb.fMid.normalize();
- // corner wedges
- *vCount += 4;
- *iCount += 6;
- }
-}
-
-struct DegenerateTestData {
- DegenerateTestData() { fStage = kInitial; }
- bool isDegenerate() const { return kNonDegenerate != fStage; }
- enum {
- kInitial,
- kPoint,
- kLine,
- kNonDegenerate
- } fStage;
- SkPoint fFirstPoint;
- SkVector fLineNormal;
- SkScalar fLineC;
-};
-
-static const SkScalar kClose = (SK_Scalar1 / 16);
-static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
-
-static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
- switch (data->fStage) {
- case DegenerateTestData::kInitial:
- data->fFirstPoint = pt;
- data->fStage = DegenerateTestData::kPoint;
- break;
- case DegenerateTestData::kPoint:
- if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
- data->fLineNormal = pt - data->fFirstPoint;
- data->fLineNormal.normalize();
- data->fLineNormal.setOrthog(data->fLineNormal);
- data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
- data->fStage = DegenerateTestData::kLine;
- }
- break;
- case DegenerateTestData::kLine:
- if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
- data->fStage = DegenerateTestData::kNonDegenerate;
- }
- case DegenerateTestData::kNonDegenerate:
- break;
- default:
- SkFAIL("Unexpected degenerate test stage.");
- }
-}
-
-static inline bool get_direction(const SkPath& path, const SkMatrix& m,
- SkPathPriv::FirstDirection* dir) {
- if (!SkPathPriv::CheapComputeFirstDirection(path, dir)) {
- return false;
- }
- // check whether m reverses the orientation
- SkASSERT(!m.hasPerspective());
- SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
- SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
- if (det2x2 < 0) {
- *dir = SkPathPriv::OppositeFirstDirection(*dir);
- }
- return true;
-}
-
-static inline void add_line_to_segment(const SkPoint& pt,
- SegmentArray* segments) {
- segments->push_back();
- segments->back().fType = Segment::kLine;
- segments->back().fPts[0] = pt;
-}
-
-static inline void add_quad_segment(const SkPoint pts[3],
- SegmentArray* segments) {
- if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
- if (pts[0] != pts[2]) {
- add_line_to_segment(pts[2], segments);
- }
- } else {
- segments->push_back();
- segments->back().fType = Segment::kQuad;
- segments->back().fPts[0] = pts[1];
- segments->back().fPts[1] = pts[2];
- }
-}
-
-static inline void add_cubic_segments(const SkPoint pts[4],
- SkPathPriv::FirstDirection dir,
- SegmentArray* segments) {
- SkSTArray<15, SkPoint, true> quads;
- GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
- int count = quads.count();
- for (int q = 0; q < count; q += 3) {
- add_quad_segment(&quads[q], segments);
- }
-}
-
-static bool get_segments(const SkPath& path,
- const SkMatrix& m,
- SegmentArray* segments,
- SkPoint* fanPt,
- int* vCount,
- int* iCount) {
- SkPath::Iter iter(path, true);
- // This renderer over-emphasizes very thin path regions. We use the distance
- // to the path from the sample to compute coverage. Every pixel intersected
- // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
- // notice that the sample may be close to a very thin area of the path and
- // thus should be very light. This is particularly egregious for degenerate
- // line paths. We detect paths that are very close to a line (zero area) and
- // draw nothing.
- DegenerateTestData degenerateData;
- SkPathPriv::FirstDirection dir;
- // get_direction can fail for some degenerate paths.
- if (!get_direction(path, m, &dir)) {
- return false;
- }
-
- for (;;) {
- SkPoint pts[4];
- SkPath::Verb verb = iter.next(pts);
- switch (verb) {
- case SkPath::kMove_Verb:
- m.mapPoints(pts, 1);
- update_degenerate_test(&degenerateData, pts[0]);
- break;
- case SkPath::kLine_Verb: {
- m.mapPoints(&pts[1], 1);
- update_degenerate_test(&degenerateData, pts[1]);
- add_line_to_segment(pts[1], segments);
- break;
- }
- case SkPath::kQuad_Verb:
- m.mapPoints(pts, 3);
- update_degenerate_test(&degenerateData, pts[1]);
- update_degenerate_test(&degenerateData, pts[2]);
- add_quad_segment(pts, segments);
- break;
- case SkPath::kConic_Verb: {
- m.mapPoints(pts, 3);
- SkScalar weight = iter.conicWeight();
- SkAutoConicToQuads converter;
- const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.5f);
- for (int i = 0; i < converter.countQuads(); ++i) {
- update_degenerate_test(&degenerateData, quadPts[2*i + 1]);
- update_degenerate_test(&degenerateData, quadPts[2*i + 2]);
- add_quad_segment(quadPts + 2*i, segments);
- }
- break;
- }
- case SkPath::kCubic_Verb: {
- m.mapPoints(pts, 4);
- update_degenerate_test(&degenerateData, pts[1]);
- update_degenerate_test(&degenerateData, pts[2]);
- update_degenerate_test(&degenerateData, pts[3]);
- add_cubic_segments(pts, dir, segments);
- break;
- };
- case SkPath::kDone_Verb:
- if (degenerateData.isDegenerate()) {
- return false;
- } else {
- compute_vectors(segments, fanPt, dir, vCount, iCount);
- return true;
- }
- default:
- break;
- }
- }
-}
-
-struct QuadVertex {
- SkPoint fPos;
- SkPoint fUV;
- SkScalar fD0;
- SkScalar fD1;
-};
-
-struct Draw {
- Draw() : fVertexCnt(0), fIndexCnt(0) {}
- int fVertexCnt;
- int fIndexCnt;
-};
-
-typedef SkTArray<Draw, true> DrawArray;
-
-static void create_vertices(const SegmentArray& segments,
- const SkPoint& fanPt,
- DrawArray* draws,
- QuadVertex* verts,
- uint16_t* idxs) {
- Draw* draw = &draws->push_back();
- // alias just to make vert/index assignments easier to read.
- int* v = &draw->fVertexCnt;
- int* i = &draw->fIndexCnt;
-
- int count = segments.count();
- for (int a = 0; a < count; ++a) {
- const Segment& sega = segments[a];
- int b = (a + 1) % count;
- const Segment& segb = segments[b];
-
- // Check whether adding the verts for this segment to the current draw would cause index
- // values to overflow.
- int vCount = 4;
- if (Segment::kLine == segb.fType) {
- vCount += 5;
- } else {
- vCount += 6;
- }
- if (draw->fVertexCnt + vCount > (1 << 16)) {
- verts += *v;
- idxs += *i;
- draw = &draws->push_back();
- v = &draw->fVertexCnt;
- i = &draw->fIndexCnt;
- }
-
- // FIXME: These tris are inset in the 1 unit arc around the corner
- verts[*v + 0].fPos = sega.endPt();
- verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
- verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
- verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
- verts[*v + 0].fUV.set(0,0);
- verts[*v + 1].fUV.set(0,-SK_Scalar1);
- verts[*v + 2].fUV.set(0,-SK_Scalar1);
- verts[*v + 3].fUV.set(0,-SK_Scalar1);
- verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
- verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
- verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
- verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
-
- idxs[*i + 0] = *v + 0;
- idxs[*i + 1] = *v + 2;
- idxs[*i + 2] = *v + 1;
- idxs[*i + 3] = *v + 0;
- idxs[*i + 4] = *v + 3;
- idxs[*i + 5] = *v + 2;
-
- *v += 4;
- *i += 6;
-
- if (Segment::kLine == segb.fType) {
- verts[*v + 0].fPos = fanPt;
- verts[*v + 1].fPos = sega.endPt();
- verts[*v + 2].fPos = segb.fPts[0];
-
- verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
- verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
-
- // we draw the line edge as a degenerate quad (u is 0, v is the
- // signed distance to the edge)
- SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
- verts[*v + 2].fPos);
- verts[*v + 0].fUV.set(0, dist);
- verts[*v + 1].fUV.set(0, 0);
- verts[*v + 2].fUV.set(0, 0);
- verts[*v + 3].fUV.set(0, -SK_Scalar1);
- verts[*v + 4].fUV.set(0, -SK_Scalar1);
-
- verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
- verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
- verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
- verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
- verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
-
- idxs[*i + 0] = *v + 3;
- idxs[*i + 1] = *v + 1;
- idxs[*i + 2] = *v + 2;
-
- idxs[*i + 3] = *v + 4;
- idxs[*i + 4] = *v + 3;
- idxs[*i + 5] = *v + 2;
-
- *i += 6;
-
- // Draw the interior fan if it exists.
- // TODO: Detect and combine colinear segments. This will ensure we catch every case
- // with no interior, and that the resulting shared edge uses the same endpoints.
- if (count >= 3) {
- idxs[*i + 0] = *v + 0;
- idxs[*i + 1] = *v + 2;
- idxs[*i + 2] = *v + 1;
-
- *i += 3;
- }
-
- *v += 5;
- } else {
- SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
-
- SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
- midVec.normalize();
-
- verts[*v + 0].fPos = fanPt;
- verts[*v + 1].fPos = qpts[0];
- verts[*v + 2].fPos = qpts[2];
- verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
- verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
- verts[*v + 5].fPos = qpts[1] + midVec;
-
- SkScalar c = segb.fNorms[0].dot(qpts[0]);
- verts[*v + 0].fD0 = -segb.fNorms[0].dot(fanPt) + c;
- verts[*v + 1].fD0 = 0.f;
- verts[*v + 2].fD0 = -segb.fNorms[0].dot(qpts[2]) + c;
- verts[*v + 3].fD0 = -SK_ScalarMax/100;
- verts[*v + 4].fD0 = -SK_ScalarMax/100;
- verts[*v + 5].fD0 = -SK_ScalarMax/100;
-
- c = segb.fNorms[1].dot(qpts[2]);
- verts[*v + 0].fD1 = -segb.fNorms[1].dot(fanPt) + c;
- verts[*v + 1].fD1 = -segb.fNorms[1].dot(qpts[0]) + c;
- verts[*v + 2].fD1 = 0.f;
- verts[*v + 3].fD1 = -SK_ScalarMax/100;
- verts[*v + 4].fD1 = -SK_ScalarMax/100;
- verts[*v + 5].fD1 = -SK_ScalarMax/100;
-
- GrPathUtils::QuadUVMatrix toUV(qpts);
- toUV.apply<6, sizeof(QuadVertex), sizeof(SkPoint)>(verts + *v);
-
- idxs[*i + 0] = *v + 3;
- idxs[*i + 1] = *v + 1;
- idxs[*i + 2] = *v + 2;
- idxs[*i + 3] = *v + 4;
- idxs[*i + 4] = *v + 3;
- idxs[*i + 5] = *v + 2;
-
- idxs[*i + 6] = *v + 5;
- idxs[*i + 7] = *v + 3;
- idxs[*i + 8] = *v + 4;
-
- *i += 9;
-
- // Draw the interior fan if it exists.
- // TODO: Detect and combine colinear segments. This will ensure we catch every case
- // with no interior, and that the resulting shared edge uses the same endpoints.
- if (count >= 3) {
- idxs[*i + 0] = *v + 0;
- idxs[*i + 1] = *v + 2;
- idxs[*i + 2] = *v + 1;
-
- *i += 3;
- }
-
- *v += 6;
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-/*
- * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
- * two components of the vertex attribute. Coverage is based on signed
- * distance with negative being inside, positive outside. The edge is specified in
- * window space (y-down). If either the third or fourth component of the interpolated
- * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
- * attempt to trim to a portion of the infinite quad.
- * Requires shader derivative instruction support.
- */
-
-class QuadEdgeEffect : public GrGeometryProcessor {
-public:
-
- static GrGeometryProcessor* Create(GrColor color, const SkMatrix& localMatrix,
- bool usesLocalCoords) {
- return new QuadEdgeEffect(color, localMatrix, usesLocalCoords);
- }
-
- virtual ~QuadEdgeEffect() {}
-
- const char* name() const override { return "QuadEdge"; }
-
- const Attribute* inPosition() const { return fInPosition; }
- const Attribute* inQuadEdge() const { return fInQuadEdge; }
- GrColor color() const { return fColor; }
- bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
- const SkMatrix& localMatrix() const { return fLocalMatrix; }
- bool usesLocalCoords() const { return fUsesLocalCoords; }
-
- class GLProcessor : public GrGLGeometryProcessor {
- public:
- GLProcessor(const GrGeometryProcessor&,
- const GrBatchTracker&)
- : fColor(GrColor_ILLEGAL) {}
-
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
- const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
- GrGLGPBuilder* pb = args.fPB;
- GrGLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder();
-
- // emit attributes
- vsBuilder->emitAttributes(qe);
-
- GrGLVertToFrag v(kVec4f_GrSLType);
- args.fPB->addVarying("QuadEdge", &v);
- vsBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName);
-
- // Setup pass through color
- if (!qe.colorIgnored()) {
- this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
- }
-
- // Setup position
- this->setupPosition(pb, gpArgs, qe.inPosition()->fName);
-
- // emit transforms
- this->emitTransforms(args.fPB, gpArgs->fPositionVar, qe.inPosition()->fName,
- qe.localMatrix(), args.fTransformsIn, args.fTransformsOut);
-
- GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-
- SkAssertResult(fsBuilder->enableFeature(
- GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
- fsBuilder->codeAppendf("float edgeAlpha;");
-
- // keep the derivative instructions outside the conditional
- fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
- fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
- fsBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
- // today we know z and w are in device space. We could use derivatives
- fsBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(),
- v.fsIn());
- fsBuilder->codeAppendf ("} else {");
- fsBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,"
- " 2.0*%s.x*duvdy.x - duvdy.y);",
- v.fsIn(), v.fsIn());
- fsBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
- v.fsIn());
- fsBuilder->codeAppendf("edgeAlpha = "
- "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}");
-
- fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
- }
-
- static inline void GenKey(const GrGeometryProcessor& gp,
- const GrBatchTracker& bt,
- const GrGLSLCaps&,
- GrProcessorKeyBuilder* b) {
- const QuadEdgeEffect& qee = gp.cast<QuadEdgeEffect>();
- uint32_t key = 0;
- key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
- key |= qee.colorIgnored() ? 0x2 : 0x0;
- b->add32(key);
- }
-
- virtual void setData(const GrGLProgramDataManager& pdman,
- const GrPrimitiveProcessor& gp,
- const GrBatchTracker& bt) override {
- const QuadEdgeEffect& qe = gp.cast<QuadEdgeEffect>();
- if (qe.color() != fColor) {
- GrGLfloat c[4];
- GrColorToRGBAFloat(qe.color(), c);
- pdman.set4fv(fColorUniform, 1, c);
- fColor = qe.color();
- }
- }
-
- void setTransformData(const GrPrimitiveProcessor& primProc,
- const GrGLProgramDataManager& pdman,
- int index,
- const SkTArray<const GrCoordTransform*, true>& transforms) override {
- this->setTransformDataHelper<QuadEdgeEffect>(primProc, pdman, index, transforms);
- }
-
- private:
- GrColor fColor;
- UniformHandle fColorUniform;
-
- typedef GrGLGeometryProcessor INHERITED;
- };
-
- virtual void getGLProcessorKey(const GrBatchTracker& bt,
- const GrGLSLCaps& caps,
- GrProcessorKeyBuilder* b) const override {
- GLProcessor::GenKey(*this, bt, caps, b);
- }
-
- virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
- const GrGLSLCaps&) const override {
- return new GLProcessor(*this, bt);
- }
-
-private:
- QuadEdgeEffect(GrColor color, const SkMatrix& localMatrix, bool usesLocalCoords)
- : fColor(color)
- , fLocalMatrix(localMatrix)
- , fUsesLocalCoords(usesLocalCoords) {
- this->initClassID<QuadEdgeEffect>();
- fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
- fInQuadEdge = &this->addVertexAttrib(Attribute("inQuadEdge", kVec4f_GrVertexAttribType));
- }
-
- const Attribute* fInPosition;
- const Attribute* fInQuadEdge;
- GrColor fColor;
- SkMatrix fLocalMatrix;
- bool fUsesLocalCoords;
-
- GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
-
- typedef GrGeometryProcessor INHERITED;
-};
-
-GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
-
-const GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
- // Doesn't work without derivative instructions.
- return d->fCaps->shaderCaps()->shaderDerivativeSupport() ?
- QuadEdgeEffect::Create(GrRandomColor(d->fRandom),
- GrTest::TestMatrix(d->fRandom),
- d->fRandom->nextBool()) : nullptr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
- return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
- args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
- args.fPath->isConvex());
-}
-
-// extract the result vertices and indices from the GrAAConvexTessellator
-static void extract_verts(const GrAAConvexTessellator& tess,
- void* vertices,
- size_t vertexStride,
- GrColor color,
- uint16_t* idxs,
- bool tweakAlphaForCoverage) {
- intptr_t verts = reinterpret_cast<intptr_t>(vertices);
-
- for (int i = 0; i < tess.numPts(); ++i) {
- *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
- }
-
- // Make 'verts' point to the colors
- verts += sizeof(SkPoint);
- for (int i = 0; i < tess.numPts(); ++i) {
- if (tweakAlphaForCoverage) {
- SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255);
- unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i));
- GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
- } else {
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
- *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
- tess.coverage(i);
- }
- }
-
- for (int i = 0; i < tess.numIndices(); ++i) {
- idxs[i] = tess.index(i);
- }
-}
-
-static const GrGeometryProcessor* create_fill_gp(bool tweakAlphaForCoverage,
- const SkMatrix& viewMatrix,
- bool usesLocalCoords,
- bool coverageIgnored) {
- using namespace GrDefaultGeoProcFactory;
-
- Color color(Color::kAttribute_Type);
- Coverage::Type coverageType;
- // TODO remove coverage if coverage is ignored
- /*if (coverageIgnored) {
- coverageType = Coverage::kNone_Type;
- } else*/ if (tweakAlphaForCoverage) {
- coverageType = Coverage::kSolid_Type;
- } else {
- coverageType = Coverage::kAttribute_Type;
- }
- Coverage coverage(coverageType);
- LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type :
- LocalCoords::kUnused_Type);
- return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
-}
-
-class AAConvexPathBatch : public GrVertexBatch {
-public:
- struct Geometry {
- GrColor fColor;
- SkMatrix fViewMatrix;
- SkPath fPath;
- };
-
- static GrDrawBatch* Create(const Geometry& geometry) { return new AAConvexPathBatch(geometry); }
-
- const char* name() const override { return "AAConvexBatch"; }
-
- void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
- // When this is called on a batch, there is only one geometry bundle
- out->setKnownFourComponents(fGeoData[0].fColor);
- }
- void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
- out->setUnknownSingleComponent();
- }
-
-private:
-
- void initBatchTracker(const GrPipelineOptimizations& opt) override {
- // Handle any color overrides
- if (!opt.readsColor()) {
- fGeoData[0].fColor = GrColor_ILLEGAL;
- }
- opt.getOverrideColorIfSet(&fGeoData[0].fColor);
-
- // setup batch properties
- fBatch.fColorIgnored = !opt.readsColor();
- fBatch.fColor = fGeoData[0].fColor;
- fBatch.fUsesLocalCoords = opt.readsLocalCoords();
- fBatch.fCoverageIgnored = !opt.readsCoverage();
- fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSegmentMasks();
- fBatch.fCanTweakAlphaForCoverage = opt.canTweakAlphaForCoverage();
- }
-
- void prepareLinesOnlyDraws(Target* target) {
- bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
-
- // Setup GrGeometryProcessor
- SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_gp(canTweakAlphaForCoverage,
- this->viewMatrix(),
- this->usesLocalCoords(),
- this->coverageIgnored()));
- if (!gp) {
- SkDebugf("Could not create GrGeometryProcessor\n");
- return;
- }
-
- target->initDraw(gp, this->pipeline());
-
- size_t vertexStride = gp->getVertexStride();
-
- SkASSERT(canTweakAlphaForCoverage ?
- vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
- vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
-
- GrAAConvexTessellator tess;
-
- int instanceCount = fGeoData.count();
-
- for (int i = 0; i < instanceCount; i++) {
- tess.rewind();
-
- Geometry& args = fGeoData[i];
-
- if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
- continue;
- }
-
- const GrVertexBuffer* vertexBuffer;
- int firstVertex;
-
- void* verts = target->makeVertexSpace(vertexStride, tess.numPts(), &vertexBuffer,
- &firstVertex);
- if (!verts) {
- SkDebugf("Could not allocate vertices\n");
- return;
- }
-
- const GrIndexBuffer* indexBuffer;
- int firstIndex;
-
- uint16_t* idxs = target->makeIndexSpace(tess.numIndices(), &indexBuffer, &firstIndex);
- if (!idxs) {
- SkDebugf("Could not allocate indices\n");
- return;
- }
-
- extract_verts(tess, verts, vertexStride, args.fColor, idxs, canTweakAlphaForCoverage);
-
- GrVertices info;
- info.initIndexed(kTriangles_GrPrimitiveType,
- vertexBuffer, indexBuffer,
- firstVertex, firstIndex,
- tess.numPts(), tess.numIndices());
- target->draw(info);
- }
- }
-
- void onPrepareDraws(Target* target) override {
-#ifndef SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS
- if (this->linesOnly()) {
- this->prepareLinesOnlyDraws(target);
- return;
- }
-#endif
-
- int instanceCount = fGeoData.count();
-
- SkMatrix invert;
- if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
- SkDebugf("Could not invert viewmatrix\n");
- return;
- }
-
- // Setup GrGeometryProcessor
- SkAutoTUnref<GrGeometryProcessor> quadProcessor(
- QuadEdgeEffect::Create(this->color(), invert, this->usesLocalCoords()));
-
- target->initDraw(quadProcessor, this->pipeline());
-
- // TODO generate all segments for all paths and use one vertex buffer
- for (int i = 0; i < instanceCount; i++) {
- Geometry& args = fGeoData[i];
-
- // We use the fact that SkPath::transform path does subdivision based on
- // perspective. Otherwise, we apply the view matrix when copying to the
- // segment representation.
- const SkMatrix* viewMatrix = &args.fViewMatrix;
- if (viewMatrix->hasPerspective()) {
- args.fPath.transform(*viewMatrix);
- viewMatrix = &SkMatrix::I();
- }
-
- int vertexCount;
- int indexCount;
- enum {
- kPreallocSegmentCnt = 512 / sizeof(Segment),
- kPreallocDrawCnt = 4,
- };
- SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
- SkPoint fanPt;
-
- if (!get_segments(args.fPath, *viewMatrix, &segments, &fanPt, &vertexCount,
- &indexCount)) {
- continue;
- }
-
- const GrVertexBuffer* vertexBuffer;
- int firstVertex;
-
- size_t vertexStride = quadProcessor->getVertexStride();
- QuadVertex* verts = reinterpret_cast<QuadVertex*>(target->makeVertexSpace(
- vertexStride, vertexCount, &vertexBuffer, &firstVertex));
-
- if (!verts) {
- SkDebugf("Could not allocate vertices\n");
- return;
- }
-
- const GrIndexBuffer* indexBuffer;
- int firstIndex;
-
- uint16_t *idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
- if (!idxs) {
- SkDebugf("Could not allocate indices\n");
- return;
- }
-
- SkSTArray<kPreallocDrawCnt, Draw, true> draws;
- create_vertices(segments, fanPt, &draws, verts, idxs);
-
- GrVertices vertices;
-
- for (int i = 0; i < draws.count(); ++i) {
- const Draw& draw = draws[i];
- vertices.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer,
- firstVertex, firstIndex, draw.fVertexCnt, draw.fIndexCnt);
- target->draw(vertices);
- firstVertex += draw.fVertexCnt;
- firstIndex += draw.fIndexCnt;
- }
- }
- }
-
- SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
-
- AAConvexPathBatch(const Geometry& geometry) {
- this->initClassID<AAConvexPathBatch>();
- fGeoData.push_back(geometry);
-
- // compute bounds
- fBounds = geometry.fPath.getBounds();
- geometry.fViewMatrix.mapRect(&fBounds);
- }
-
- bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
- AAConvexPathBatch* that = t->cast<AAConvexPathBatch>();
- if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
- that->bounds(), caps)) {
- return false;
- }
-
- if (this->color() != that->color()) {
- return false;
- }
-
- SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
- if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return false;
- }
-
- if (this->linesOnly() != that->linesOnly()) {
- return false;
- }
-
- // In the event of two batches, one who can tweak, one who cannot, we just fall back to
- // not tweaking
- if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
- fBatch.fCanTweakAlphaForCoverage = false;
- }
-
- fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
- this->joinBounds(that->bounds());
- return true;
- }
-
- GrColor color() const { return fBatch.fColor; }
- bool linesOnly() const { return fBatch.fLinesOnly; }
- bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
- bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
- const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
- bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
-
- struct BatchTracker {
- GrColor fColor;
- bool fUsesLocalCoords;
- bool fColorIgnored;
- bool fCoverageIgnored;
- bool fLinesOnly;
- bool fCanTweakAlphaForCoverage;
- };
-
- BatchTracker fBatch;
- SkSTArray<1, Geometry, true> fGeoData;
-};
-
-bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
- if (args.fPath->isEmpty()) {
- return true;
- }
-
- AAConvexPathBatch::Geometry geometry;
- geometry.fColor = args.fColor;
- geometry.fViewMatrix = *args.fViewMatrix;
- geometry.fPath = *args.fPath;
-
- SkAutoTUnref<GrDrawBatch> batch(AAConvexPathBatch::Create(geometry));
- args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
-
- return true;
-
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef GR_TEST_UTILS
-
-DRAW_BATCH_TEST_DEFINE(AAConvexPathBatch) {
- AAConvexPathBatch::Geometry geometry;
- geometry.fColor = GrRandomColor(random);
- geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
- geometry.fPath = GrTest::TestPathConvex(random);
-
- return AAConvexPathBatch::Create(geometry);
-}
-
-#endif
« no previous file with comments | « src/gpu/GrAAConvexPathRenderer.h ('k') | src/gpu/GrAAConvexTessellator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698