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

Side by Side Diff: src/gpu/effects/GrDashingEffect.cpp

Issue 925673002: Dash batch (Closed) Base URL: https://skia.googlesource.com/skia.git@default
Patch Set: adding some comments Created 5 years, 9 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrDashingEffect.h" 8 #include "GrDashingEffect.h"
9 9
10 #include "../GrAARectRenderer.h" 10 #include "GrBatch.h"
11 11 #include "GrBatchTarget.h"
12 #include "GrBufferAllocPool.h"
12 #include "GrGeometryProcessor.h" 13 #include "GrGeometryProcessor.h"
13 #include "GrContext.h" 14 #include "GrContext.h"
14 #include "GrCoordTransform.h" 15 #include "GrCoordTransform.h"
15 #include "GrDefaultGeoProcFactory.h" 16 #include "GrDefaultGeoProcFactory.h"
16 #include "GrDrawTarget.h" 17 #include "GrDrawTarget.h"
17 #include "GrDrawTargetCaps.h" 18 #include "GrDrawTargetCaps.h"
18 #include "GrInvariantOutput.h" 19 #include "GrInvariantOutput.h"
19 #include "GrProcessor.h" 20 #include "GrProcessor.h"
20 #include "GrStrokeInfo.h" 21 #include "GrStrokeInfo.h"
21 #include "SkGr.h" 22 #include "SkGr.h"
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 vec.scale(inv); 108 vec.scale(inv);
108 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 109 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
109 if (ptsRot) { 110 if (ptsRot) {
110 rotMatrix->mapPoints(ptsRot, pts, 2); 111 rotMatrix->mapPoints(ptsRot, pts, 2);
111 // correction for numerical issues if map doesn't make ptsRot exactly ho rizontal 112 // correction for numerical issues if map doesn't make ptsRot exactly ho rizontal
112 ptsRot[1].fY = pts[0].fY; 113 ptsRot[1].fY = pts[0].fY;
113 } 114 }
114 } 115 }
115 116
116 // Assumes phase < sum of all intervals 117 // Assumes phase < sum of all intervals
117 static SkScalar calc_start_adjustment(const SkPathEffect::DashInfo& info) { 118 static SkScalar calc_start_adjustment(const SkScalar intervals[2], SkScalar phas e) {
118 SkASSERT(info.fPhase < info.fIntervals[0] + info.fIntervals[1]); 119 SkASSERT(phase < intervals[0] + intervals[1]);
119 if (info.fPhase >= info.fIntervals[0] && info.fPhase != 0) { 120 if (phase >= intervals[0] && phase != 0) {
120 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; 121 SkScalar srcIntervalLen = intervals[0] + intervals[1];
121 return srcIntervalLen - info.fPhase; 122 return srcIntervalLen - phase;
122 } 123 }
123 return 0; 124 return 0;
124 } 125 }
125 126
126 static SkScalar calc_end_adjustment(const SkPathEffect::DashInfo& info, const Sk Point pts[2], 127 static SkScalar calc_end_adjustment(const SkScalar intervals[2], const SkPoint p ts[2],
127 SkScalar phase, SkScalar* endingInt) { 128 SkScalar phase, SkScalar* endingInt) {
128 if (pts[1].fX <= pts[0].fX) { 129 if (pts[1].fX <= pts[0].fX) {
129 return 0; 130 return 0;
130 } 131 }
131 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; 132 SkScalar srcIntervalLen = intervals[0] + intervals[1];
132 SkScalar totalLen = pts[1].fX - pts[0].fX; 133 SkScalar totalLen = pts[1].fX - pts[0].fX;
133 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen); 134 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen);
134 SkScalar numFullIntervals = SkScalarFloorToScalar(temp); 135 SkScalar numFullIntervals = SkScalarFloorToScalar(temp);
135 *endingInt = totalLen - numFullIntervals * srcIntervalLen + phase; 136 *endingInt = totalLen - numFullIntervals * srcIntervalLen + phase;
136 temp = SkScalarDiv(*endingInt, srcIntervalLen); 137 temp = SkScalarDiv(*endingInt, srcIntervalLen);
137 *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen; 138 *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen;
138 if (0 == *endingInt) { 139 if (0 == *endingInt) {
139 *endingInt = srcIntervalLen; 140 *endingInt = srcIntervalLen;
140 } 141 }
141 if (*endingInt > info.fIntervals[0]) { 142 if (*endingInt > intervals[0]) {
142 if (0 == info.fIntervals[0]) { 143 if (0 == intervals[0]) {
143 *endingInt -= 0.01f; // make sure we capture the last zero size pnt (used if has caps) 144 *endingInt -= 0.01f; // make sure we capture the last zero size pnt (used if has caps)
144 } 145 }
145 return *endingInt - info.fIntervals[0]; 146 return *endingInt - intervals[0];
146 } 147 }
147 return 0; 148 return 0;
148 } 149 }
149 150
150 enum DashCap { 151 enum DashCap {
151 kRound_DashCap, 152 kRound_DashCap,
152 kNonRound_DashCap, 153 kNonRound_DashCap,
153 }; 154 };
154 155
155 static int kDashVertices = 4; 156 static int kDashVertices = 4;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 * An GrGeometryProcessor that renders a dashed line. 231 * An GrGeometryProcessor that renders a dashed line.
231 * This GrGeometryProcessor is meant for dashed lines that only have a single on /off interval pair. 232 * This GrGeometryProcessor is meant for dashed lines that only have a single on /off interval pair.
232 * Bounding geometry is rendered and the effect computes coverage based on the f ragment's 233 * Bounding geometry is rendered and the effect computes coverage based on the f ragment's
233 * position relative to the dashed line. 234 * position relative to the dashed line.
234 */ 235 */
235 static GrGeometryProcessor* create_dash_gp(GrColor, 236 static GrGeometryProcessor* create_dash_gp(GrColor,
236 GrPrimitiveEdgeType edgeType, 237 GrPrimitiveEdgeType edgeType,
237 DashCap cap, 238 DashCap cap,
238 const SkMatrix& localMatrix); 239 const SkMatrix& localMatrix);
239 240
241 class DashBatch : public GrBatch {
242 public:
243 struct Geometry {
244 GrColor fColor;
245 SkMatrix fViewMatrix;
246 SkMatrix fSrcRotInv;
247 SkPoint fPtsRot[2];
248 SkScalar fSrcStrokeWidth;
249 SkScalar fPhase;
250 SkScalar fIntervals[2];
251 SkDEBUGCODE(SkRect fDevBounds;)
252 };
253
254 static GrBatch* Create(const Geometry& geometry, SkPaint::Cap cap, bool useA A, bool fullDash) {
255 return SkNEW_ARGS(DashBatch, (geometry, cap, useAA, fullDash));
256 }
257
258 const char* name() const SK_OVERRIDE { return "DashBatch"; }
259
260 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
261 // When this is called on a batch, there is only one geometry bundle
262 out->setKnownFourComponents(fGeoData[0].fColor);
263 }
264 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
265 out->setUnknownSingleComponent();
266 }
267
268 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
269 // Handle any color overrides
270 if (init.fColorIgnored) {
271 fGeoData[0].fColor = GrColor_ILLEGAL;
272 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
273 fGeoData[0].fColor = init.fOverrideColor;
274 }
275
276 // setup batch properties
277 fBatch.fColorIgnored = init.fColorIgnored;
278 fBatch.fColor = fGeoData[0].fColor;
279 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
280 fBatch.fCoverageIgnored = init.fCoverageIgnored;
281 }
282
283 struct DashDraw {
284 SkScalar fStartOffset;
285 SkScalar fStrokeWidth;
286 SkScalar fLineLength;
287 SkScalar fHalfDevStroke;
288 SkScalar fDevBloat;
289 bool fLineDone;
290 bool fHasStartRect;
291 bool fHasEndRect;
292 };
293
294 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
295 int instanceCount = fGeoData.count();
296
297 SkMatrix invert;
298 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
299 SkDebugf("Failed to invert\n");
300 return;
301 }
302
303 SkPaint::Cap cap = this->cap();
304
305 SkAutoTUnref<const GrGeometryProcessor> gp;
306
307 bool isRoundCap = SkPaint::kRound_Cap == cap;
308 DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap;
309 if (this->fullDash()) {
310 GrPrimitiveEdgeType edgeType = this->useAA() ? kFillAA_GrProcessorEd geType :
311 kFillBW_GrProcessorEd geType;
312 gp.reset(create_dash_gp(this->color(), edgeType, capType, invert));
313 } else {
314 // Set up the vertex data for the line and start/end dashes
315 gp.reset(GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kP osition_GPType,
316 this->color(),
317 SkMatrix::I(),
318 invert));
319 }
320
321 batchTarget->initDraw(gp, pipeline);
322
323 // TODO remove this when batch is everywhere
324 GrPipelineInfo init;
325 init.fColorIgnored = fBatch.fColorIgnored;
326 init.fOverrideColor = GrColor_ILLEGAL;
327 init.fCoverageIgnored = fBatch.fCoverageIgnored;
328 init.fUsesLocalCoords = this->usesLocalCoords();
329 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
330
331 bool useAA = this->useAA();
332 bool fullDash = this->fullDash();
333
334 // We do two passes over all of the dashes. First we setup the start, e nd, and bounds,
335 // rectangles. We preserve all of this work in the rects / draws arrays below. Then we
336 // iterate again over these decomposed dashes to generate vertices
337 SkSTArray<128, SkRect, true> rects;
338 SkSTArray<128, DashDraw, true> draws;
339
340 int totalRectCount = 0;
341 for (int i = 0; i < instanceCount; i++) {
342 Geometry& args = fGeoData[i];
343
344 // Scale corrections of intervals and stroke from view matrix
345 SkScalar parallelScale;
346 SkScalar perpScale;
347 calc_dash_scaling(&parallelScale, &perpScale, args.fViewMatrix, args .fPtsRot);
egdaniel 2015/02/27 15:13:18 do we really want recalculate this for all the das
348
349 bool hasCap = SkPaint::kButt_Cap != cap && 0 != args.fSrcStrokeWidth ;
350
351 // We always want to at least stroke out half a pixel on each side i n device space
352 // so 0.5f / perpScale gives us this min in src space
353 SkScalar halfSrcStroke = SkMaxScalar(args.fSrcStrokeWidth * 0.5f, 0. 5f / perpScale);
354
355 SkScalar strokeAdj;
356 if (!hasCap) {
357 strokeAdj = 0.f;
358 } else {
359 strokeAdj = halfSrcStroke;
360 }
361
362 SkScalar startAdj = 0;
363
364 SkMatrix& combinedMatrix = args.fSrcRotInv;
365 combinedMatrix.postConcat(args.fViewMatrix);
366
367 bool lineDone = false;
368
369 // Too simplify the algorithm, we always push back rects for start a nd end rect.
370 // Otherwise we'd have to track start / end rects for each individua l geometry
371 SkRect& bounds = rects.push_back();
372 SkRect& startRect = rects.push_back();
373 SkRect& endRect = rects.push_back();
374
375 bool hasStartRect = false;
376 // If we are using AA, check to see if we are drawing a partial dash at the start. If so
377 // draw it separately here and adjust our start point accordingly
378 if (useAA) {
379 if (args.fPhase > 0 && args.fPhase < args.fIntervals[0]) {
380 SkPoint startPts[2];
381 startPts[0] = args.fPtsRot[0];
382 startPts[1].fY = startPts[0].fY;
383 startPts[1].fX = SkMinScalar(startPts[0].fX + args.fInterval s[0] - args.fPhase,
384 args.fPtsRot[1].fX);
385 startRect.set(startPts, 2);
386 startRect.outset(strokeAdj, halfSrcStroke);
387
388 hasStartRect = true;
389 startAdj = args.fIntervals[0] + args.fIntervals[1] - args.fP hase;
390 }
391 }
392
393 // adjustments for start and end of bounding rect so we only draw da sh intervals
394 // contained in the original line segment.
395 startAdj += calc_start_adjustment(args.fIntervals, args.fPhase);
396 if (startAdj != 0) {
397 args.fPtsRot[0].fX += startAdj;
398 args.fPhase = 0;
399 }
400 SkScalar endingInterval = 0;
401 SkScalar endAdj = calc_end_adjustment(args.fIntervals, args.fPtsRot, args.fPhase,
402 &endingInterval);
403 args.fPtsRot[1].fX -= endAdj;
404 if (args.fPtsRot[0].fX >= args.fPtsRot[1].fX) {
405 lineDone = true;
406 }
407
408 bool hasEndRect = false;
409 // If we are using AA, check to see if we are drawing a partial dash at then end. If so
410 // draw it separately here and adjust our end point accordingly
411 if (useAA && !lineDone) {
412 // If we adjusted the end then we will not be drawing a partial dash at the end.
413 // If we didn't adjust the end point then we just need to make s ure the ending
414 // dash isn't a full dash
415 if (0 == endAdj && endingInterval != args.fIntervals[0]) {
416 SkPoint endPts[2];
417 endPts[1] = args.fPtsRot[1];
418 endPts[0].fY = endPts[1].fY;
419 endPts[0].fX = endPts[1].fX - endingInterval;
420
421 endRect.set(endPts, 2);
422 endRect.outset(strokeAdj, halfSrcStroke);
423
424 hasEndRect = true;
425 endAdj = endingInterval + args.fIntervals[1];
426
427 args.fPtsRot[1].fX -= endAdj;
428 if (args.fPtsRot[0].fX >= args.fPtsRot[1].fX) {
429 lineDone = true;
430 }
431 }
432 }
433
434 if (startAdj != 0) {
435 args.fPhase = 0;
436 }
437
438 // Change the dashing info from src space into device space
439 SkScalar* devIntervals = args.fIntervals;
440 devIntervals[0] = args.fIntervals[0] * parallelScale;
441 devIntervals[1] = args.fIntervals[1] * parallelScale;
442 SkScalar devPhase = args.fPhase * parallelScale;
443 SkScalar strokeWidth = args.fSrcStrokeWidth * perpScale;
444
445 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) {
446 strokeWidth = 1.f;
447 }
448
449 SkScalar halfDevStroke = strokeWidth * 0.5f;
450
451 if (SkPaint::kSquare_Cap == cap && 0 != args.fSrcStrokeWidth) {
452 // add cap to on interval and remove from off interval
453 devIntervals[0] += strokeWidth;
454 devIntervals[1] -= strokeWidth;
455 }
456 SkScalar startOffset = devIntervals[1] * 0.5f + devPhase;
457
458 SkScalar bloatX = useAA ? 0.5f / parallelScale : 0.f;
459 SkScalar bloatY = useAA ? 0.5f / perpScale : 0.f;
460
461 SkScalar devBloat = useAA ? 0.5f : 0.f;
462
463 if (devIntervals[1] <= 0.f && useAA) {
464 // Case when we end up drawing a solid AA rect
465 // Reset the start rect to draw this single solid rect
466 // but it requires to upload a new intervals uniform so we can m imic
467 // one giant dash
468 args.fPtsRot[0].fX -= hasStartRect ? startAdj : 0;
469 args.fPtsRot[1].fX += hasEndRect ? endAdj : 0;
470 startRect.set(args.fPtsRot, 2);
471 startRect.outset(strokeAdj, halfSrcStroke);
472 hasStartRect = true;
473 hasEndRect = false;
474 lineDone = true;
475
476 SkPoint devicePts[2];
477 args.fViewMatrix.mapPoints(devicePts, args.fPtsRot, 2);
478 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[ 1]);
479 if (hasCap) {
480 lineLength += 2.f * halfDevStroke;
481 }
482 devIntervals[0] = lineLength;
483 }
484
485 totalRectCount += !lineDone ? 1 : 0;
486 totalRectCount += hasStartRect ? 1 : 0;
487 totalRectCount += hasEndRect ? 1 : 0;
488
489 if (SkPaint::kRound_Cap == cap && 0 != args.fSrcStrokeWidth) {
490 // need to adjust this for round caps to correctly set the dashP os attrib on
491 // vertices
492 startOffset -= halfDevStroke;
493 }
494
495 DashDraw& draw = draws.push_back();
496 if (!lineDone) {
497 SkPoint devicePts[2];
498 args.fViewMatrix.mapPoints(devicePts, args.fPtsRot, 2);
499 draw.fLineLength = SkPoint::Distance(devicePts[0], devicePts[1]) ;
500 if (hasCap) {
501 draw.fLineLength += 2.f * halfDevStroke;
502 }
503
504 bounds.set(args.fPtsRot[0].fX, args.fPtsRot[0].fY,
505 args.fPtsRot[1].fX, args.fPtsRot[1].fY);
506 bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
507 }
508
509 if (hasStartRect) {
510 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
511 startRect.outset(bloatX, bloatY);
512 }
513
514 if (hasEndRect) {
515 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
516 endRect.outset(bloatX, bloatY);
517 }
518
519 draw.fStartOffset = startOffset;
520 draw.fDevBloat = devBloat;
521 draw.fHalfDevStroke = halfDevStroke;
522 draw.fStrokeWidth = strokeWidth;
523 draw.fHasStartRect = hasStartRect;
524 draw.fLineDone = lineDone;
525 draw.fHasEndRect = hasEndRect;
526 }
527
528 const GrVertexBuffer* vertexBuffer;
529 int firstVertex;
530
531 size_t vertexStride = gp->getVertexStride();
532 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
533 totalRectCount * k VertsPerDash,
534 &vertexBuffer,
535 &firstVertex);
536
537 int curVIdx = 0;
538 int rectIndex = 0;
539 for (int i = 0; i < instanceCount; i++) {
540 Geometry& args = fGeoData[i];
541
542 if (!draws[i].fLineDone) {
543 if (fullDash) {
544 setup_dashed_rect(rects[rectIndex], vertices, curVIdx, args. fSrcRotInv,
545 draws[i].fStartOffset, draws[i].fDevBloat,
546 draws[i].fLineLength, draws[i].fHalfDevStr oke,
547 args.fIntervals[0], args.fIntervals[1], dr aws[i].fStrokeWidth,
548 capType, gp->getVertexStride());
549 } else {
550 SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
551 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
552 setup_dashed_rect_pos(rects[rectIndex], curVIdx, args.fSrcRo tInv, verts);
553 }
554 curVIdx += 4;
555 }
556 rectIndex++;
557
558 if (draws[i].fHasStartRect) {
559 if (fullDash) {
560 setup_dashed_rect(rects[rectIndex], vertices, curVIdx, args. fSrcRotInv,
561 draws[i].fStartOffset, draws[i].fDevBloat, args.fIntervals[0],
562 draws[i].fHalfDevStroke, args.fIntervals[0 ],
563 args.fIntervals[1], draws[i].fStrokeWidth, capType,
564 gp->getVertexStride());
565 } else {
566 SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
567 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
568 setup_dashed_rect_pos(rects[rectIndex], curVIdx, args.fSrcRo tInv, verts);
569 }
570
571 curVIdx += 4;
572 }
573 rectIndex++;
574
575 if (draws[i].fHasEndRect) {
576 if (fullDash) {
577 setup_dashed_rect(rects[rectIndex], vertices, curVIdx, args. fSrcRotInv,
578 draws[i].fStartOffset, draws[i].fDevBloat, args.fIntervals[0],
579 draws[i].fHalfDevStroke, args.fIntervals[0 ],
580 args.fIntervals[1], draws[i].fStrokeWidth, capType,
581 gp->getVertexStride());
582 } else {
583 SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
584 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
585 setup_dashed_rect_pos(rects[rectIndex], curVIdx, args.fSrcRo tInv, verts);
586 }
587 curVIdx += 4;
588 }
589 rectIndex++;
590 }
591
592 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
egdaniel 2015/02/27 15:13:18 rename from quad
593
594 GrDrawTarget::DrawInfo drawInfo;
595 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
596 drawInfo.setStartVertex(0);
597 drawInfo.setStartIndex(0);
598 drawInfo.setVerticesPerInstance(kVertsPerDash);
599 drawInfo.setIndicesPerInstance(kIndicesPerDash);
600 drawInfo.adjustStartVertex(firstVertex);
601 drawInfo.setVertexBuffer(vertexBuffer);
602 drawInfo.setIndexBuffer(quadIndexBuffer);
egdaniel 2015/02/27 15:13:18 quad
603
604 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
egdaniel 2015/02/27 15:13:18 quads
605 while (totalRectCount) {
606 drawInfo.setInstanceCount(SkTMin(totalRectCount, maxInstancesPerDraw ));
607 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices PerInstance());
608 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe rInstance());
609
610 batchTarget->draw(drawInfo);
611
612 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun t());
613 totalRectCount -= drawInfo.instanceCount();
614 }
615 }
616
617 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
618
619 private:
620 DashBatch(const Geometry& geometry, SkPaint::Cap cap, bool useAA, bool fullD ash) {
621 this->initClassID<DashBatch>();
622 fGeoData.push_back(geometry);
623
624 fBatch.fUseAA = useAA;
625 fBatch.fCap = cap;
626 fBatch.fFullDash = fullDash;
627 }
628
629 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
630 DashBatch* that = t->cast<DashBatch>();
631
632 if (this->useAA() != that->useAA()) {
633 return false;
634 }
635
636 if (this->fullDash() != that->fullDash()) {
637 return false;
638 }
639
640 if (this->cap() != that->cap()) {
641 return false;
642 }
643
644 // TODO vertex color
645 if (this->color() != that->color()) {
646 return false;
647 }
648
649 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
650 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
651 return false;
652 }
653
654 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
655 return true;
656 }
657
658 GrColor color() const { return fBatch.fColor; }
659 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
660 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
661 bool useAA() const { return fBatch.fUseAA; }
662 bool fullDash() const { return fBatch.fFullDash; }
663 SkPaint::Cap cap() const { return fBatch.fCap; }
664
665 struct BatchTracker {
666 GrColor fColor;
667 bool fUsesLocalCoords;
668 bool fColorIgnored;
669 bool fCoverageIgnored;
670 SkPaint::Cap fCap;
671 bool fUseAA;
672 bool fFullDash;
673 };
674
675 static const int kVertsPerDash = 4;
676 static const int kIndicesPerDash = 6;
677
678 BatchTracker fBatch;
679 SkSTArray<1, Geometry, true> fGeoData;
680 };
681
682
240 bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, 683 bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
241 GrPipelineBuilder* pipelineBuilder, GrColor c olor, 684 GrPipelineBuilder* pipelineBuilder, GrColor c olor,
242 const SkMatrix& viewMatrix, const SkPoint pts [2], 685 const SkMatrix& viewMatrix, const SkPoint pts [2],
243 const GrPaint& paint, const GrStrokeInfo& str okeInfo) { 686 const GrPaint& paint, const GrStrokeInfo& str okeInfo) {
244 if (!can_fast_path_dash(pts, strokeInfo, *target, *pipelineBuilder, viewMatr ix)) { 687 if (!can_fast_path_dash(pts, strokeInfo, *target, *pipelineBuilder, viewMatr ix)) {
245 return false; 688 return false;
246 } 689 }
247 690
248 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo(); 691 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
249 692
250 SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap(); 693 SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap();
251 694
252 SkScalar srcStrokeWidth = strokeInfo.getStrokeRec().getWidth(); 695 SkScalar srcStrokeWidth = strokeInfo.getStrokeRec().getWidth();
253 696
254 // the phase should be normalized to be [0, sum of all intervals) 697 // the phase should be normalized to be [0, sum of all intervals)
255 SkASSERT(info.fPhase >= 0 && info.fPhase < info.fIntervals[0] + info.fInterv als[1]); 698 SkASSERT(info.fPhase >= 0 && info.fPhase < info.fIntervals[0] + info.fInterv als[1]);
256 699
257 SkScalar srcPhase = info.fPhase; 700 //SkScalar srcPhase = info.fPhase;
egdaniel 2015/02/27 15:13:18 remove line?
258 701
259 // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[ 1].fX 702 // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[ 1].fX
260 SkMatrix srcRotInv; 703 SkMatrix srcRotInv;
261 SkPoint ptsRot[2]; 704 SkPoint ptsRot[2];
262 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) { 705 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) {
263 SkMatrix rotMatrix; 706 SkMatrix rotMatrix;
264 align_to_x_axis(pts, &rotMatrix, ptsRot); 707 align_to_x_axis(pts, &rotMatrix, ptsRot);
265 if(!rotMatrix.invert(&srcRotInv)) { 708 if(!rotMatrix.invert(&srcRotInv)) {
266 SkDebugf("Failed to create invertible rotation matrix!\n"); 709 SkDebugf("Failed to create invertible rotation matrix!\n");
267 return false; 710 return false;
268 } 711 }
269 } else { 712 } else {
270 srcRotInv.reset(); 713 srcRotInv.reset();
271 memcpy(ptsRot, pts, 2 * sizeof(SkPoint)); 714 memcpy(ptsRot, pts, 2 * sizeof(SkPoint));
272 } 715 }
273 716
274 bool useAA = paint.isAntiAlias(); 717 // We have to do some throwaway work to determine if we need to fulldash
275
276 // Scale corrections of intervals and stroke from view matrix
277 SkScalar parallelScale; 718 SkScalar parallelScale;
278 SkScalar perpScale; 719 SkScalar perpScale;
279 calc_dash_scaling(&parallelScale, &perpScale, viewMatrix, ptsRot); 720 calc_dash_scaling(&parallelScale, &perpScale, viewMatrix, ptsRot);
280 721
281 bool hasCap = SkPaint::kButt_Cap != cap && 0 != srcStrokeWidth; 722 SkScalar endInterval = info.fIntervals[1] * parallelScale;
egdaniel 2015/02/27 15:13:18 can this be off interval? end interval doesn't rea
282
283 // We always want to at least stroke out half a pixel on each side in device space
284 // so 0.5f / perpScale gives us this min in src space
285 SkScalar halfSrcStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale );
286
287 SkScalar strokeAdj;
288 if (!hasCap) {
289 strokeAdj = 0.f;
290 } else {
291 strokeAdj = halfSrcStroke;
292 }
293
294 SkScalar startAdj = 0;
295
296 SkMatrix combinedMatrix = srcRotInv;
297 combinedMatrix.postConcat(viewMatrix);
298
299 bool lineDone = false;
300 SkRect startRect;
301 bool hasStartRect = false;
302 // If we are using AA, check to see if we are drawing a partial dash at the start. If so
303 // draw it separately here and adjust our start point accordingly
304 if (useAA) {
305 if (srcPhase > 0 && srcPhase < info.fIntervals[0]) {
306 SkPoint startPts[2];
307 startPts[0] = ptsRot[0];
308 startPts[1].fY = startPts[0].fY;
309 startPts[1].fX = SkMinScalar(startPts[0].fX + info.fIntervals[0] - s rcPhase,
310 ptsRot[1].fX);
311 startRect.set(startPts, 2);
312 startRect.outset(strokeAdj, halfSrcStroke);
313
314 hasStartRect = true;
315 startAdj = info.fIntervals[0] + info.fIntervals[1] - srcPhase;
316 }
317 }
318
319 // adjustments for start and end of bounding rect so we only draw dash inter vals
320 // contained in the original line segment.
321 startAdj += calc_start_adjustment(info);
322 if (startAdj != 0) {
323 ptsRot[0].fX += startAdj;
324 srcPhase = 0;
325 }
326 SkScalar endingInterval = 0;
327 SkScalar endAdj = calc_end_adjustment(info, ptsRot, srcPhase, &endingInterva l);
328 ptsRot[1].fX -= endAdj;
329 if (ptsRot[0].fX >= ptsRot[1].fX) {
330 lineDone = true;
331 }
332
333 SkRect endRect;
334 bool hasEndRect = false;
335 // If we are using AA, check to see if we are drawing a partial dash at then end. If so
336 // draw it separately here and adjust our end point accordingly
337 if (useAA && !lineDone) {
338 // If we adjusted the end then we will not be drawing a partial dash at the end.
339 // If we didn't adjust the end point then we just need to make sure the ending
340 // dash isn't a full dash
341 if (0 == endAdj && endingInterval != info.fIntervals[0]) {
342 SkPoint endPts[2];
343 endPts[1] = ptsRot[1];
344 endPts[0].fY = endPts[1].fY;
345 endPts[0].fX = endPts[1].fX - endingInterval;
346
347 endRect.set(endPts, 2);
348 endRect.outset(strokeAdj, halfSrcStroke);
349
350 hasEndRect = true;
351 endAdj = endingInterval + info.fIntervals[1];
352
353 ptsRot[1].fX -= endAdj;
354 if (ptsRot[0].fX >= ptsRot[1].fX) {
355 lineDone = true;
356 }
357 }
358 }
359
360 if (startAdj != 0) {
361 srcPhase = 0;
362 }
363
364 // Change the dashing info from src space into device space
365 SkScalar devIntervals[2];
366 devIntervals[0] = info.fIntervals[0] * parallelScale;
367 devIntervals[1] = info.fIntervals[1] * parallelScale;
368 SkScalar devPhase = srcPhase * parallelScale;
369 SkScalar strokeWidth = srcStrokeWidth * perpScale; 723 SkScalar strokeWidth = srcStrokeWidth * perpScale;
370 724
371 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) {
372 strokeWidth = 1.f;
373 }
374
375 SkScalar halfDevStroke = strokeWidth * 0.5f;
376
377 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) { 725 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) {
378 // add cap to on interveal and remove from off interval 726 // add cap to on interveal and remove from off interval
379 devIntervals[0] += strokeWidth; 727 endInterval -= strokeWidth;
380 devIntervals[1] -= strokeWidth; 728 }
381 } 729
382 SkScalar startOffset = devIntervals[1] * 0.5f + devPhase; 730 bool useAA = paint.isAntiAlias();
383 731 bool fullDash = endInterval > 0.f || useAA;
egdaniel 2015/02/27 15:13:18 Add todo to do a real rect call in case where full
384 SkScalar bloatX = useAA ? 0.5f / parallelScale : 0.f; 732
385 SkScalar bloatY = useAA ? 0.5f / perpScale : 0.f; 733 DashBatch::Geometry geometry;
386 734 geometry.fColor = color;
387 SkScalar devBloat = useAA ? 0.5f : 0.f; 735 geometry.fViewMatrix = viewMatrix;
388 736 geometry.fSrcRotInv = srcRotInv;
389 if (devIntervals[1] <= 0.f && useAA) { 737 geometry.fPtsRot[0] = ptsRot[0];
390 // Case when we end up drawing a solid AA rect 738 geometry.fPtsRot[1] = ptsRot[1];
391 // Reset the start rect to draw this single solid rect 739 geometry.fSrcStrokeWidth = srcStrokeWidth;
392 // but it requires to upload a new intervals uniform so we can mimic 740 geometry.fPhase = info.fPhase;
393 // one giant dash 741 geometry.fIntervals[0] = info.fIntervals[0];
394 ptsRot[0].fX -= hasStartRect ? startAdj : 0; 742 geometry.fIntervals[1] = info.fIntervals[1];
395 ptsRot[1].fX += hasEndRect ? endAdj : 0; 743 //SkDEBUGCODE(fDevBounds;)
egdaniel 2015/02/27 15:13:18 delete?
396 startRect.set(ptsRot, 2); 744
397 startRect.outset(strokeAdj, halfSrcStroke); 745 SkAutoTUnref<GrBatch> batch(DashBatch::Create(geometry, cap, useAA, fullDash ));
398 hasStartRect = true; 746 target->drawBatch(pipelineBuilder, batch);
399 hasEndRect = false; 747
400 lineDone = true;
401
402 SkPoint devicePts[2];
403 viewMatrix.mapPoints(devicePts, ptsRot, 2);
404 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
405 if (hasCap) {
406 lineLength += 2.f * halfDevStroke;
407 }
408 devIntervals[0] = lineLength;
409 }
410
411 // reset to device coordinates
412 SkMatrix invert;
413 if (!viewMatrix.invert(&invert)) {
414 SkDebugf("Failed to invert\n");
415 return false;
416 }
417
418 bool isRoundCap = SkPaint::kRound_Cap == cap;
419 DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap;
420
421 SkAutoTUnref<const GrGeometryProcessor> gp;
422 bool fullDash = devIntervals[1] > 0.f || useAA;
423 if (fullDash) {
424 SkPathEffect::DashInfo devInfo;
425 devInfo.fPhase = devPhase;
426 devInfo.fCount = 2;
427 devInfo.fIntervals = devIntervals;
428 GrPrimitiveEdgeType edgeType = useAA ? kFillAA_GrProcessorEdgeType :
429 kFillBW_GrProcessorEdgeType;
430 gp.reset(create_dash_gp(color, edgeType, capType, invert));
431 } else {
432 // Set up the vertex data for the line and start/end dashes
433 gp.reset(GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosit ion_GPType,
434 color,
435 SkMatrix::I(),
436 invert));
437 }
438
439 int totalRectCnt = 0;
440
441 totalRectCnt += !lineDone ? 1 : 0;
442 totalRectCnt += hasStartRect ? 1 : 0;
443 totalRectCnt += hasEndRect ? 1 : 0;
444
445 GrDrawTarget::AutoReleaseGeometry geo(target,
446 totalRectCnt * 4,
447 gp->getVertexStride(), 0);
448 if (!geo.succeeded()) {
449 SkDebugf("Failed to get space for vertices!\n");
450 return false;
451 }
452
453 int curVIdx = 0;
454
455 if (SkPaint::kRound_Cap == cap && 0 != srcStrokeWidth) {
456 // need to adjust this for round caps to correctly set the dashPos attri b on vertices
457 startOffset -= halfDevStroke;
458 }
459
460 // Draw interior part of dashed line
461 if (!lineDone) {
462 SkPoint devicePts[2];
463 viewMatrix.mapPoints(devicePts, ptsRot, 2);
464 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
465 if (hasCap) {
466 lineLength += 2.f * halfDevStroke;
467 }
468
469 SkRect bounds;
470 bounds.set(ptsRot[0].fX, ptsRot[0].fY, ptsRot[1].fX, ptsRot[1].fY);
471 bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
472 if (fullDash) {
473 setup_dashed_rect(bounds, geo.vertices(), curVIdx, combinedMatrix, s tartOffset,
474 devBloat, lineLength, halfDevStroke, devIntervals[ 0], devIntervals[1],
475 strokeWidth, capType, gp->getVertexStride());
476 } else {
477 SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
478 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
479 setup_dashed_rect_pos(bounds, curVIdx, combinedMatrix, verts);
480 }
481 curVIdx += 4;
482 }
483
484 if (hasStartRect) {
485 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
486 startRect.outset(bloatX, bloatY);
487 if (fullDash) {
488 setup_dashed_rect(startRect, geo.vertices(), curVIdx, combinedMatrix , startOffset,
489 devBloat, devIntervals[0], halfDevStroke, devInter vals[0],
490 devIntervals[1], strokeWidth, capType, gp->getVert exStride());
491 } else {
492 SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
493 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
494 setup_dashed_rect_pos(startRect, curVIdx, combinedMatrix, verts);
495 }
496
497 curVIdx += 4;
498 }
499
500 if (hasEndRect) {
501 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
502 endRect.outset(bloatX, bloatY);
503 if (fullDash) {
504 setup_dashed_rect(endRect, geo.vertices(), curVIdx, combinedMatrix, startOffset,
505 devBloat, devIntervals[0], halfDevStroke, devInter vals[0],
506 devIntervals[1], strokeWidth, capType, gp->getVert exStride());
507 } else {
508 SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
509 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
510 setup_dashed_rect_pos(endRect, curVIdx, combinedMatrix, verts);
511 }
512
513 }
514
515 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
516 target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType , totalRectCnt,
517 4, 6);
518 target->resetIndexSource();
519 return true; 748 return true;
520 } 749 }
521 750
522 ////////////////////////////////////////////////////////////////////////////// 751 //////////////////////////////////////////////////////////////////////////////
523 752
524 class GLDashingCircleEffect; 753 class GLDashingCircleEffect;
525 754
526 struct DashingCircleBatchTracker { 755 struct DashingCircleBatchTracker {
527 GrGPInput fInputColorType; 756 GrGPInput fInputColorType;
528 GrColor fColor; 757 GrColor fColor;
(...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after
1030 switch (cap) { 1259 switch (cap) {
1031 case kRound_DashCap: 1260 case kRound_DashCap:
1032 return DashingCircleEffect::Create(color, edgeType, localMatrix); 1261 return DashingCircleEffect::Create(color, edgeType, localMatrix);
1033 case kNonRound_DashCap: 1262 case kNonRound_DashCap:
1034 return DashingLineEffect::Create(color, edgeType, localMatrix); 1263 return DashingLineEffect::Create(color, edgeType, localMatrix);
1035 default: 1264 default:
1036 SkFAIL("Unexpected dashed cap."); 1265 SkFAIL("Unexpected dashed cap.");
1037 } 1266 }
1038 return NULL; 1267 return NULL;
1039 } 1268 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698