Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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(¶llelScale, &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(¶llelScale, &perpScale, viewMatrix, ptsRot); | 720 calc_dash_scaling(¶llelScale, &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 Loading... | |
| 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 } |
| OLD | NEW |