1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 // This test only works with the GPU backend. 9 10 #include "gm.h" 11 12 #if SK_SUPPORT_GPU 13 14 #include "GrContext.h" 15 #include "GrOpFlushState.h" 16 #include "GrPathUtils.h" 17 #include "GrRenderTargetContextPriv.h" 18 #include "GrTest.h" 19 #include "SkColorPriv.h" 20 #include "SkGeometry.h" 21 #include "effects/GrBezierEffect.h" 22 #include "ops/GrMeshDrawOp.h" 23 24 namespace skiagm { 25 26 class BezierTestOp : public GrMeshDrawOp { 27 public: fixedFunctionFlags() const28 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 29 finalize(const GrCaps & caps,const GrAppliedClip * clip)30 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override { 31 auto analysis = fProcessorSet.finalize(fColor, GrProcessorAnalysisCoverage::kSingleChannel, 32 clip, false, caps, &fColor); 33 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo; 34 } 35 36 protected: BezierTestOp(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color,int32_t classID)37 BezierTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, int32_t classID) 38 : INHERITED(classID) 39 , fRect(rect) 40 , fColor(color) 41 , fGeometryProcessor(std::move(gp)) 42 , fProcessorSet(SkBlendMode::kSrc) { 43 this->setBounds(rect, HasAABloat::kYes, IsZeroArea::kNo); 44 } 45 makePipeline(Target * target) const46 const GrPipeline* makePipeline(Target* target) const { 47 return target->makePipeline(0, &fProcessorSet); 48 } 49 gp() const50 const GrGeometryProcessor* gp() const { return fGeometryProcessor.get(); } 51 rect() const52 const SkRect& rect() const { return fRect; } color() const53 GrColor color() const { return fColor; } 54 55 private: onCombineIfPossible(GrOp * op,const GrCaps & caps)56 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; } 57 58 SkRect fRect; 59 GrColor fColor; 60 sk_sp<GrGeometryProcessor> fGeometryProcessor; 61 GrProcessorSet fProcessorSet; 62 63 typedef GrMeshDrawOp INHERITED; 64 }; 65 66 class BezierCubicTestOp : public BezierTestOp { 67 public: 68 DEFINE_OP_CLASS_ID 69 name() const70 const char* name() const override { return "BezierCubicTestOp"; } 71 Make(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color)72 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, 73 GrColor color) { 74 return std::unique_ptr<GrDrawOp>(new BezierCubicTestOp(std::move(gp), rect, color)); 75 } 76 77 private: BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color)78 BezierCubicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color) 79 : INHERITED(std::move(gp), rect, color, ClassID()) {} 80 onPrepareDraws(Target * target) const81 void onPrepareDraws(Target* target) const override { 82 QuadHelper helper; 83 size_t vertexStride = this->gp()->getVertexStride(); 84 SkASSERT(vertexStride == sizeof(SkPoint)); 85 SkPoint* pts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1)); 86 if (!pts) { 87 return; 88 } 89 SkRect rect = this->rect(); 90 pts[0].setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); 91 helper.recordDraw(target, this->gp(), this->makePipeline(target)); 92 } 93 94 static constexpr int kVertsPerCubic = 4; 95 static constexpr int kIndicesPerCubic = 6; 96 97 typedef BezierTestOp INHERITED; 98 }; 99 100 /** 101 * This GM directly exercises effects that draw Bezier curves in the GPU backend. 102 */ 103 class BezierCubicEffects : public GM { 104 public: BezierCubicEffects()105 BezierCubicEffects() { 106 this->setBGColor(0xFFFFFFFF); 107 } 108 109 protected: onShortName()110 SkString onShortName() override { 111 return SkString("bezier_cubic_effects"); 112 } 113 onISize()114 SkISize onISize() override { 115 return SkISize::Make(800, 800); 116 } 117 onDraw(SkCanvas * canvas)118 void onDraw(SkCanvas* canvas) override { 119 GrRenderTargetContext* renderTargetContext = 120 canvas->internal_private_accessTopLayerRenderTargetContext(); 121 if (!renderTargetContext) { 122 skiagm::GM::DrawGpuOnlyMessage(canvas); 123 return; 124 } 125 126 GrContext* context = canvas->getGrContext(); 127 if (!context) { 128 return; 129 } 130 131 struct Vertex { 132 SkPoint fPosition; 133 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 134 }; 135 136 constexpr int kNumCubics = 15; 137 SkRandom rand; 138 139 // Mult by 3 for each edge effect type 140 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3))); 141 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols); 142 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols; 143 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows; 144 int row = 0; 145 int col = 0; 146 constexpr GrColor color = 0xff000000; 147 148 for (int i = 0; i < kNumCubics; ++i) { 149 SkPoint baseControlPts[] = { 150 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 151 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 152 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 153 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)} 154 }; 155 for(GrPrimitiveEdgeType edgeType : {kFillBW_GrProcessorEdgeType, 156 kFillAA_GrProcessorEdgeType, 157 kHairlineAA_GrProcessorEdgeType}) { 158 SkScalar x = col * w; 159 SkScalar y = row * h; 160 SkPoint controlPts[] = { 161 {x + baseControlPts[0].fX, y + baseControlPts[0].fY}, 162 {x + baseControlPts[1].fX, y + baseControlPts[1].fY}, 163 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}, 164 {x + baseControlPts[3].fX, y + baseControlPts[3].fY} 165 }; 166 SkPoint chopped[10]; 167 SkMatrix klm; 168 int loopIndex; 169 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts, 170 chopped, 171 &klm, 172 &loopIndex); 173 174 SkPaint ctrlPtPaint; 175 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000); 176 canvas->drawCircle(controlPts[0], 8.f, ctrlPtPaint); 177 for (int i = 1; i < 4; ++i) { 178 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint); 179 } 180 181 SkPaint polyPaint; 182 polyPaint.setColor(0xffA0A0A0); 183 polyPaint.setStrokeWidth(0); 184 polyPaint.setStyle(SkPaint::kStroke_Style); 185 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint); 186 187 SkPaint choppedPtPaint; 188 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000); 189 190 for (int c = 0; c < cnt; ++c) { 191 SkPoint* pts = chopped + 3 * c; 192 193 for (int i = 0; i < 4; ++i) { 194 canvas->drawCircle(pts[i], 3.f, choppedPtPaint); 195 } 196 197 SkRect bounds; 198 bounds.set(pts, 4); 199 200 SkPaint boundsPaint; 201 boundsPaint.setColor(0xff808080); 202 boundsPaint.setStrokeWidth(0); 203 boundsPaint.setStyle(SkPaint::kStroke_Style); 204 canvas->drawRect(bounds, boundsPaint); 205 206 207 bool flipKL = (c == loopIndex && cnt != 3); 208 sk_sp<GrGeometryProcessor> gp = GrCubicEffect::Make(color, SkMatrix::I(), klm, 209 flipKL, edgeType, 210 *context->caps()); 211 if (!gp) { 212 break; 213 } 214 215 std::unique_ptr<GrDrawOp> op = 216 BezierCubicTestOp::Make(std::move(gp), bounds, color); 217 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 218 } 219 ++col; 220 if (numCols == col) { 221 col = 0; 222 ++row; 223 } 224 } 225 } 226 } 227 228 private: 229 typedef GM INHERITED; 230 }; 231 232 ////////////////////////////////////////////////////////////////////////////// 233 234 class BezierConicTestOp : public BezierTestOp { 235 public: 236 DEFINE_OP_CLASS_ID 237 name() const238 const char* name() const override { return "BezierConicTestOp"; } 239 Make(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color,const SkMatrix & klm)240 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, 241 GrColor color, const SkMatrix& klm) { 242 return std::unique_ptr<GrMeshDrawOp>( 243 new BezierConicTestOp(std::move(gp), rect, color, klm)); 244 } 245 246 private: BezierConicTestOp(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color,const SkMatrix & klm)247 BezierConicTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, 248 const SkMatrix& klm) 249 : INHERITED(std::move(gp), rect, color, ClassID()), fKLM(klm) {} 250 251 struct Vertex { 252 SkPoint fPosition; 253 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 254 }; 255 onPrepareDraws(Target * target) const256 void onPrepareDraws(Target* target) const override { 257 QuadHelper helper; 258 size_t vertexStride = this->gp()->getVertexStride(); 259 SkASSERT(vertexStride == sizeof(Vertex)); 260 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1)); 261 if (!verts) { 262 return; 263 } 264 SkRect rect = this->rect(); 265 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, 266 sizeof(Vertex)); 267 for (int v = 0; v < 4; ++v) { 268 SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f}; 269 fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1); 270 } 271 helper.recordDraw(target, this->gp(), this->makePipeline(target)); 272 } 273 274 SkMatrix fKLM; 275 276 static constexpr int kVertsPerCubic = 4; 277 static constexpr int kIndicesPerCubic = 6; 278 279 typedef BezierTestOp INHERITED; 280 }; 281 282 283 /** 284 * This GM directly exercises effects that draw Bezier curves in the GPU backend. 285 */ 286 class BezierConicEffects : public GM { 287 public: BezierConicEffects()288 BezierConicEffects() { 289 this->setBGColor(0xFFFFFFFF); 290 } 291 292 protected: onShortName()293 SkString onShortName() override { 294 return SkString("bezier_conic_effects"); 295 } 296 onISize()297 SkISize onISize() override { 298 return SkISize::Make(800, 800); 299 } 300 301 onDraw(SkCanvas * canvas)302 void onDraw(SkCanvas* canvas) override { 303 GrRenderTargetContext* renderTargetContext = 304 canvas->internal_private_accessTopLayerRenderTargetContext(); 305 if (!renderTargetContext) { 306 skiagm::GM::DrawGpuOnlyMessage(canvas); 307 return; 308 } 309 310 GrContext* context = canvas->getGrContext(); 311 if (!context) { 312 return; 313 } 314 315 struct Vertex { 316 SkPoint fPosition; 317 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 318 }; 319 320 constexpr int kNumConics = 10; 321 SkRandom rand; 322 323 // Mult by 3 for each edge effect type 324 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3))); 325 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols); 326 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols; 327 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows; 328 int row = 0; 329 int col = 0; 330 constexpr GrColor color = 0xff000000; 331 332 for (int i = 0; i < kNumConics; ++i) { 333 SkPoint baseControlPts[] = { 334 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 335 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 336 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)} 337 }; 338 SkScalar weight = rand.nextRangeF(0.f, 2.f); 339 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) { 340 sk_sp<GrGeometryProcessor> gp; 341 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType; 342 gp = GrConicEffect::Make(color, SkMatrix::I(), et, 343 *context->caps(), SkMatrix::I(), false); 344 if (!gp) { 345 continue; 346 } 347 348 SkScalar x = col * w; 349 SkScalar y = row * h; 350 SkPoint controlPts[] = { 351 {x + baseControlPts[0].fX, y + baseControlPts[0].fY}, 352 {x + baseControlPts[1].fX, y + baseControlPts[1].fY}, 353 {x + baseControlPts[2].fX, y + baseControlPts[2].fY} 354 }; 355 SkConic dst[4]; 356 SkMatrix klm; 357 int cnt = chop_conic(controlPts, dst, weight); 358 GrPathUtils::getConicKLM(controlPts, weight, &klm); 359 360 SkPaint ctrlPtPaint; 361 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000); 362 for (int i = 0; i < 3; ++i) { 363 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint); 364 } 365 366 SkPaint polyPaint; 367 polyPaint.setColor(0xffA0A0A0); 368 polyPaint.setStrokeWidth(0); 369 polyPaint.setStyle(SkPaint::kStroke_Style); 370 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint); 371 372 SkPaint choppedPtPaint; 373 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000); 374 375 for (int c = 0; c < cnt; ++c) { 376 SkPoint* pts = dst[c].fPts; 377 for (int i = 0; i < 3; ++i) { 378 canvas->drawCircle(pts[i], 3.f, choppedPtPaint); 379 } 380 381 SkRect bounds; 382 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}}; 383 //bounds.set(bPts, 2); 384 bounds.set(pts, 3); 385 386 SkPaint boundsPaint; 387 boundsPaint.setColor(0xff808080); 388 boundsPaint.setStrokeWidth(0); 389 boundsPaint.setStyle(SkPaint::kStroke_Style); 390 canvas->drawRect(bounds, boundsPaint); 391 392 std::unique_ptr<GrDrawOp> op = BezierConicTestOp::Make(gp, bounds, color, klm); 393 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 394 } 395 ++col; 396 if (numCols == col) { 397 col = 0; 398 ++row; 399 } 400 } 401 } 402 } 403 404 private: 405 // Uses the max curvature function for quads to estimate 406 // where to chop the conic. If the max curvature is not 407 // found along the curve segment it will return 1 and 408 // dst[0] is the original conic. If it returns 2 the dst[0] 409 // and dst[1] are the two new conics. split_conic(const SkPoint src[3],SkConic dst[2],const SkScalar weight)410 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { 411 SkScalar t = SkFindQuadMaxCurvature(src); 412 if (t == 0) { 413 if (dst) { 414 dst[0].set(src, weight); 415 } 416 return 1; 417 } else { 418 if (dst) { 419 SkConic conic; 420 conic.set(src, weight); 421 if (!conic.chopAt(t, dst)) { 422 dst[0].set(src, weight); 423 return 1; 424 } 425 } 426 return 2; 427 } 428 } 429 430 // Calls split_conic on the entire conic and then once more on each subsection. 431 // Most cases will result in either 1 conic (chop point is not within t range) 432 // or 3 points (split once and then one subsection is split again). chop_conic(const SkPoint src[3],SkConic dst[4],const SkScalar weight)433 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { 434 SkConic dstTemp[2]; 435 int conicCnt = split_conic(src, dstTemp, weight); 436 if (2 == conicCnt) { 437 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); 438 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW); 439 } else { 440 dst[0] = dstTemp[0]; 441 } 442 return conicCnt; 443 } 444 445 typedef GM INHERITED; 446 }; 447 448 ////////////////////////////////////////////////////////////////////////////// 449 450 class BezierQuadTestOp : public BezierTestOp { 451 public: 452 DEFINE_OP_CLASS_ID name() const453 const char* name() const override { return "BezierQuadTestOp"; } 454 Make(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color,const GrPathUtils::QuadUVMatrix & devToUV)455 static std::unique_ptr<GrDrawOp> Make(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, 456 GrColor color, const GrPathUtils::QuadUVMatrix& devToUV) { 457 return std::unique_ptr<GrDrawOp>(new BezierQuadTestOp(std::move(gp), rect, color, devToUV)); 458 } 459 460 private: BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp,const SkRect & rect,GrColor color,const GrPathUtils::QuadUVMatrix & devToUV)461 BezierQuadTestOp(sk_sp<GrGeometryProcessor> gp, const SkRect& rect, GrColor color, 462 const GrPathUtils::QuadUVMatrix& devToUV) 463 : INHERITED(std::move(gp), rect, color, ClassID()), fDevToUV(devToUV) {} 464 465 struct Vertex { 466 SkPoint fPosition; 467 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 468 }; 469 onPrepareDraws(Target * target) const470 void onPrepareDraws(Target* target) const override { 471 QuadHelper helper; 472 size_t vertexStride = this->gp()->getVertexStride(); 473 SkASSERT(vertexStride == sizeof(Vertex)); 474 Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1)); 475 if (!verts) { 476 return; 477 } 478 SkRect rect = this->rect(); 479 verts[0].fPosition.setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, 480 sizeof(Vertex)); 481 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts); 482 helper.recordDraw(target, this->gp(), this->makePipeline(target)); 483 } 484 485 GrPathUtils::QuadUVMatrix fDevToUV; 486 487 static constexpr int kVertsPerCubic = 4; 488 static constexpr int kIndicesPerCubic = 6; 489 490 typedef BezierTestOp INHERITED; 491 }; 492 493 /** 494 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend. 495 */ 496 class BezierQuadEffects : public GM { 497 public: BezierQuadEffects()498 BezierQuadEffects() { 499 this->setBGColor(0xFFFFFFFF); 500 } 501 502 protected: onShortName()503 SkString onShortName() override { 504 return SkString("bezier_quad_effects"); 505 } 506 onISize()507 SkISize onISize() override { 508 return SkISize::Make(800, 800); 509 } 510 511 onDraw(SkCanvas * canvas)512 void onDraw(SkCanvas* canvas) override { 513 GrRenderTargetContext* renderTargetContext = 514 canvas->internal_private_accessTopLayerRenderTargetContext(); 515 if (!renderTargetContext) { 516 skiagm::GM::DrawGpuOnlyMessage(canvas); 517 return; 518 } 519 520 GrContext* context = canvas->getGrContext(); 521 if (!context) { 522 return; 523 } 524 525 struct Vertex { 526 SkPoint fPosition; 527 float fUV[4]; // The last two values are ignored. The effect expects a vec4f. 528 }; 529 530 constexpr int kNumQuads = 5; 531 SkRandom rand; 532 533 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3))); 534 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols); 535 SkScalar w = SkIntToScalar(renderTargetContext->width()) / numCols; 536 SkScalar h = SkIntToScalar(renderTargetContext->height()) / numRows; 537 int row = 0; 538 int col = 0; 539 constexpr GrColor color = 0xff000000; 540 541 for (int i = 0; i < kNumQuads; ++i) { 542 SkPoint baseControlPts[] = { 543 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 544 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 545 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)} 546 }; 547 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) { 548 sk_sp<GrGeometryProcessor> gp; 549 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType; 550 gp = GrQuadEffect::Make(color, SkMatrix::I(), et, 551 *context->caps(), SkMatrix::I(), false); 552 if (!gp) { 553 continue; 554 } 555 556 SkScalar x = col * w; 557 SkScalar y = row * h; 558 SkPoint controlPts[] = { 559 {x + baseControlPts[0].fX, y + baseControlPts[0].fY}, 560 {x + baseControlPts[1].fX, y + baseControlPts[1].fY}, 561 {x + baseControlPts[2].fX, y + baseControlPts[2].fY} 562 }; 563 SkPoint chopped[5]; 564 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped); 565 566 SkPaint ctrlPtPaint; 567 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000); 568 for (int i = 0; i < 3; ++i) { 569 canvas->drawCircle(controlPts[i], 6.f, ctrlPtPaint); 570 } 571 572 SkPaint polyPaint; 573 polyPaint.setColor(0xffA0A0A0); 574 polyPaint.setStrokeWidth(0); 575 polyPaint.setStyle(SkPaint::kStroke_Style); 576 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint); 577 578 SkPaint choppedPtPaint; 579 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000); 580 581 for (int c = 0; c < cnt; ++c) { 582 SkPoint* pts = chopped + 2 * c; 583 584 for (int i = 0; i < 3; ++i) { 585 canvas->drawCircle(pts[i], 3.f, choppedPtPaint); 586 } 587 588 SkRect bounds; 589 bounds.set(pts, 3); 590 591 SkPaint boundsPaint; 592 boundsPaint.setColor(0xff808080); 593 boundsPaint.setStrokeWidth(0); 594 boundsPaint.setStyle(SkPaint::kStroke_Style); 595 canvas->drawRect(bounds, boundsPaint); 596 597 GrPaint grPaint; 598 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 599 600 GrPathUtils::QuadUVMatrix DevToUV(pts); 601 602 std::unique_ptr<GrDrawOp> op = 603 BezierQuadTestOp::Make(gp, bounds, color, DevToUV); 604 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 605 } 606 ++col; 607 if (numCols == col) { 608 col = 0; 609 ++row; 610 } 611 } 612 } 613 } 614 615 private: 616 typedef GM INHERITED; 617 }; 618 619 DEF_GM(return new BezierCubicEffects;) 620 DEF_GM(return new BezierConicEffects;) 621 DEF_GM(return new BezierQuadEffects;) 622 } 623 624 #endif 625