beziereffects.cpp revision ab622c7b8cc8c39f0a594e4392b9e31b7e1ddb26
1 2/* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9// This test only works with the GPU backend. 10 11#include "gm.h" 12 13#if SK_SUPPORT_GPU 14 15#include "GrBatchTarget.h" 16#include "GrBufferAllocPool.h" 17#include "GrContext.h" 18#include "GrPathUtils.h" 19#include "GrResourceProvider.h" 20#include "GrTest.h" 21#include "GrTestBatch.h" 22#include "SkColorPriv.h" 23#include "SkDevice.h" 24#include "SkGeometry.h" 25 26#include "effects/GrBezierEffect.h" 27 28static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) { 29 return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]); 30} 31 32namespace skiagm { 33 34class BezierCubicOrConicTestBatch : public GrTestBatch { 35public: 36 struct Geometry : public GrTestBatch::Geometry { 37 SkRect fBounds; 38 }; 39 40 const char* name() const override { return "BezierCubicOrConicTestBatch"; } 41 42 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo, 43 const SkScalar klmEqs[9], SkScalar sign) { 44 return SkNEW_ARGS(BezierCubicOrConicTestBatch, (gp, geo, klmEqs, sign)); 45 } 46 47private: 48 BezierCubicOrConicTestBatch(const GrGeometryProcessor* gp, const Geometry& geo, 49 const SkScalar klmEqs[9], SkScalar sign) 50 : INHERITED(gp, geo.fBounds) { 51 for (int i = 0; i < 9; i++) { 52 fKlmEqs[i] = klmEqs[i]; 53 } 54 55 fGeometry = geo; 56 fSign = sign; 57 } 58 59 struct Vertex { 60 SkPoint fPosition; 61 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 62 }; 63 64 Geometry* geoData(int index) override { 65 SkASSERT(0 == index); 66 return &fGeometry; 67 } 68 69 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { 70 SkAutoTUnref<const GrIndexBuffer> indexBuffer( 71 batchTarget->resourceProvider()->refQuadIndexBuffer()); 72 73 size_t vertexStride = this->geometryProcessor()->getVertexStride(); 74 const GrVertexBuffer* vertexBuffer; 75 int firstVertex; 76 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, 77 kVertsPerCubic, 78 &vertexBuffer, 79 &firstVertex); 80 81 if (!vertices || !indexBuffer) { 82 SkDebugf("Could not allocate buffers\n"); 83 return; 84 } 85 86 SkASSERT(vertexStride == sizeof(Vertex)); 87 Vertex* verts = reinterpret_cast<Vertex*>(vertices); 88 89 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop, 90 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom, 91 sizeof(Vertex)); 92 for (int v = 0; v < 4; ++v) { 93 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign); 94 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign); 95 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f); 96 } 97 98 GrDrawTarget::DrawInfo drawInfo; 99 drawInfo.setPrimitiveType(kTriangleFan_GrPrimitiveType); 100 drawInfo.setVertexBuffer(vertexBuffer); 101 drawInfo.setStartVertex(firstVertex); 102 drawInfo.setVertexCount(kVertsPerCubic); 103 drawInfo.setStartIndex(0); 104 drawInfo.setIndexCount(kIndicesPerCubic); 105 drawInfo.setIndexBuffer(indexBuffer); 106 batchTarget->draw(drawInfo); 107 } 108 109 Geometry fGeometry; 110 SkScalar fKlmEqs[9]; 111 SkScalar fSign; 112 113 static const int kVertsPerCubic = 4; 114 static const int kIndicesPerCubic = 6; 115 116 typedef GrTestBatch INHERITED; 117}; 118 119/** 120 * This GM directly exercises effects that draw Bezier curves in the GPU backend. 121 */ 122class BezierCubicEffects : public GM { 123public: 124 BezierCubicEffects() { 125 this->setBGColor(0xFFFFFFFF); 126 } 127 128protected: 129 SkString onShortName() override { 130 return SkString("bezier_cubic_effects"); 131 } 132 133 SkISize onISize() override { 134 return SkISize::Make(800, 800); 135 } 136 137 void onDraw(SkCanvas* canvas) override { 138 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); 139 if (NULL == rt) { 140 this->drawGpuOnlyMessage(canvas); 141 return; 142 } 143 GrContext* context = rt->getContext(); 144 if (NULL == context) { 145 return; 146 } 147 148 struct Vertex { 149 SkPoint fPosition; 150 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 151 }; 152 153 static const int kNumCubics = 15; 154 SkRandom rand; 155 156 // Mult by 3 for each edge effect type 157 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3))); 158 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols); 159 SkScalar w = SkIntToScalar(rt->width()) / numCols; 160 SkScalar h = SkIntToScalar(rt->height()) / numRows; 161 int row = 0; 162 int col = 0; 163 164 for (int i = 0; i < kNumCubics; ++i) { 165 SkPoint baseControlPts[] = { 166 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 167 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 168 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 169 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)} 170 }; 171 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) { 172 SkAutoTUnref<GrGeometryProcessor> gp; 173 { // scope to contain GrTestTarget 174 GrTestTarget tt; 175 context->getTestTarget(&tt); 176 if (NULL == tt.target()) { 177 continue; 178 } 179 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType; 180 gp.reset(GrCubicEffect::Create(0xff000000, SkMatrix::I(), et, 181 *tt.target()->caps())); 182 if (!gp) { 183 continue; 184 } 185 } 186 187 SkScalar x = SkScalarMul(col, w); 188 SkScalar y = SkScalarMul(row, h); 189 SkPoint controlPts[] = { 190 {x + baseControlPts[0].fX, y + baseControlPts[0].fY}, 191 {x + baseControlPts[1].fX, y + baseControlPts[1].fY}, 192 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}, 193 {x + baseControlPts[3].fX, y + baseControlPts[3].fY} 194 }; 195 SkPoint chopped[10]; 196 SkScalar klmEqs[9]; 197 SkScalar klmSigns[3]; 198 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts, 199 chopped, 200 klmEqs, 201 klmSigns); 202 203 SkPaint ctrlPtPaint; 204 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000); 205 for (int i = 0; i < 4; ++i) { 206 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint); 207 } 208 209 SkPaint polyPaint; 210 polyPaint.setColor(0xffA0A0A0); 211 polyPaint.setStrokeWidth(0); 212 polyPaint.setStyle(SkPaint::kStroke_Style); 213 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint); 214 215 SkPaint choppedPtPaint; 216 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000); 217 218 for (int c = 0; c < cnt; ++c) { 219 SkPoint* pts = chopped + 3 * c; 220 221 for (int i = 0; i < 4; ++i) { 222 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint); 223 } 224 225 SkRect bounds; 226 bounds.set(pts, 4); 227 228 SkPaint boundsPaint; 229 boundsPaint.setColor(0xff808080); 230 boundsPaint.setStrokeWidth(0); 231 boundsPaint.setStyle(SkPaint::kStroke_Style); 232 canvas->drawRect(bounds, boundsPaint); 233 234 GrTestTarget tt; 235 context->getTestTarget(&tt); 236 SkASSERT(tt.target()); 237 238 GrPipelineBuilder pipelineBuilder; 239 pipelineBuilder.setRenderTarget(rt); 240 241 BezierCubicOrConicTestBatch::Geometry geometry; 242 geometry.fColor = gp->color(); 243 geometry.fBounds = bounds; 244 245 SkAutoTUnref<GrBatch> batch( 246 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c])); 247 248 tt.target()->drawBatch(&pipelineBuilder, batch); 249 } 250 ++col; 251 if (numCols == col) { 252 col = 0; 253 ++row; 254 } 255 } 256 } 257 } 258 259private: 260 typedef GM INHERITED; 261}; 262 263////////////////////////////////////////////////////////////////////////////// 264 265/** 266 * This GM directly exercises effects that draw Bezier curves in the GPU backend. 267 */ 268class BezierConicEffects : public GM { 269public: 270 BezierConicEffects() { 271 this->setBGColor(0xFFFFFFFF); 272 } 273 274protected: 275 SkString onShortName() override { 276 return SkString("bezier_conic_effects"); 277 } 278 279 SkISize onISize() override { 280 return SkISize::Make(800, 800); 281 } 282 283 284 void onDraw(SkCanvas* canvas) override { 285 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); 286 if (NULL == rt) { 287 this->drawGpuOnlyMessage(canvas); 288 return; 289 } 290 GrContext* context = rt->getContext(); 291 if (NULL == context) { 292 return; 293 } 294 295 struct Vertex { 296 SkPoint fPosition; 297 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 298 }; 299 300 static const int kNumConics = 10; 301 SkRandom rand; 302 303 // Mult by 3 for each edge effect type 304 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3))); 305 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols); 306 SkScalar w = SkIntToScalar(rt->width()) / numCols; 307 SkScalar h = SkIntToScalar(rt->height()) / numRows; 308 int row = 0; 309 int col = 0; 310 311 for (int i = 0; i < kNumConics; ++i) { 312 SkPoint baseControlPts[] = { 313 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 314 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 315 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)} 316 }; 317 SkScalar weight = rand.nextRangeF(0.f, 2.f); 318 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) { 319 SkAutoTUnref<GrGeometryProcessor> gp; 320 { // scope to contain GrTestTarget 321 GrTestTarget tt; 322 context->getTestTarget(&tt); 323 if (NULL == tt.target()) { 324 continue; 325 } 326 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType; 327 gp.reset(GrConicEffect::Create(0xff000000, SkMatrix::I(), et, 328 *tt.target()->caps(), SkMatrix::I())); 329 if (!gp) { 330 continue; 331 } 332 } 333 334 SkScalar x = SkScalarMul(col, w); 335 SkScalar y = SkScalarMul(row, h); 336 SkPoint controlPts[] = { 337 {x + baseControlPts[0].fX, y + baseControlPts[0].fY}, 338 {x + baseControlPts[1].fX, y + baseControlPts[1].fY}, 339 {x + baseControlPts[2].fX, y + baseControlPts[2].fY} 340 }; 341 SkConic dst[4]; 342 SkScalar klmEqs[9]; 343 int cnt = chop_conic(controlPts, dst, weight); 344 GrPathUtils::getConicKLM(controlPts, weight, klmEqs); 345 346 SkPaint ctrlPtPaint; 347 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000); 348 for (int i = 0; i < 3; ++i) { 349 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint); 350 } 351 352 SkPaint polyPaint; 353 polyPaint.setColor(0xffA0A0A0); 354 polyPaint.setStrokeWidth(0); 355 polyPaint.setStyle(SkPaint::kStroke_Style); 356 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint); 357 358 SkPaint choppedPtPaint; 359 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000); 360 361 for (int c = 0; c < cnt; ++c) { 362 SkPoint* pts = dst[c].fPts; 363 for (int i = 0; i < 3; ++i) { 364 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint); 365 } 366 367 SkRect bounds; 368 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}}; 369 //bounds.set(bPts, 2); 370 bounds.set(pts, 3); 371 372 SkPaint boundsPaint; 373 boundsPaint.setColor(0xff808080); 374 boundsPaint.setStrokeWidth(0); 375 boundsPaint.setStyle(SkPaint::kStroke_Style); 376 canvas->drawRect(bounds, boundsPaint); 377 378 GrTestTarget tt; 379 context->getTestTarget(&tt); 380 SkASSERT(tt.target()); 381 382 GrPipelineBuilder pipelineBuilder; 383 pipelineBuilder.setRenderTarget(rt); 384 385 BezierCubicOrConicTestBatch::Geometry geometry; 386 geometry.fColor = gp->color(); 387 geometry.fBounds = bounds; 388 389 SkAutoTUnref<GrBatch> batch( 390 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f)); 391 392 tt.target()->drawBatch(&pipelineBuilder, batch); 393 } 394 ++col; 395 if (numCols == col) { 396 col = 0; 397 ++row; 398 } 399 } 400 } 401 } 402 403private: 404 // Uses the max curvature function for quads to estimate 405 // where to chop the conic. If the max curvature is not 406 // found along the curve segment it will return 1 and 407 // dst[0] is the original conic. If it returns 2 the dst[0] 408 // and dst[1] are the two new conics. 409 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { 410 SkScalar t = SkFindQuadMaxCurvature(src); 411 if (t == 0) { 412 if (dst) { 413 dst[0].set(src, weight); 414 } 415 return 1; 416 } else { 417 if (dst) { 418 SkConic conic; 419 conic.set(src, weight); 420 conic.chopAt(t, dst); 421 } 422 return 2; 423 } 424 } 425 426 // Calls split_conic on the entire conic and then once more on each subsection. 427 // Most cases will result in either 1 conic (chop point is not within t range) 428 // or 3 points (split once and then one subsection is split again). 429 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { 430 SkConic dstTemp[2]; 431 int conicCnt = split_conic(src, dstTemp, weight); 432 if (2 == conicCnt) { 433 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); 434 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW); 435 } else { 436 dst[0] = dstTemp[0]; 437 } 438 return conicCnt; 439 } 440 441 typedef GM INHERITED; 442}; 443 444////////////////////////////////////////////////////////////////////////////// 445 446class BezierQuadTestBatch : public GrTestBatch { 447public: 448 struct Geometry : public GrTestBatch::Geometry { 449 SkRect fBounds; 450 }; 451 452 const char* name() const override { return "BezierQuadTestBatch"; } 453 454 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo, 455 const GrPathUtils::QuadUVMatrix& devToUV) { 456 return SkNEW_ARGS(BezierQuadTestBatch, (gp, geo, devToUV)); 457 } 458 459private: 460 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo, 461 const GrPathUtils::QuadUVMatrix& devToUV) 462 : INHERITED(gp, geo.fBounds) 463 , fGeometry(geo) 464 , fDevToUV(devToUV) { 465 } 466 467 struct Vertex { 468 SkPoint fPosition; 469 float fKLM[4]; // The last value is ignored. The effect expects a vec4f. 470 }; 471 472 Geometry* geoData(int index) override { 473 SkASSERT(0 == index); 474 return &fGeometry; 475 } 476 477 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { 478 SkAutoTUnref<const GrIndexBuffer> indexBuffer( 479 batchTarget->resourceProvider()->refQuadIndexBuffer()); 480 481 size_t vertexStride = this->geometryProcessor()->getVertexStride(); 482 const GrVertexBuffer* vertexBuffer; 483 int firstVertex; 484 485 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, 486 kVertsPerCubic, 487 &vertexBuffer, 488 &firstVertex); 489 490 if (!vertices || !indexBuffer) { 491 SkDebugf("Could not allocate buffers\n"); 492 return; 493 } 494 495 SkASSERT(vertexStride == sizeof(Vertex)); 496 Vertex* verts = reinterpret_cast<Vertex*>(vertices); 497 498 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop, 499 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom, 500 sizeof(Vertex)); 501 502 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts); 503 504 505 GrDrawTarget::DrawInfo drawInfo; 506 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); 507 drawInfo.setVertexBuffer(vertexBuffer); 508 drawInfo.setStartVertex(firstVertex); 509 drawInfo.setVertexCount(kVertsPerCubic); 510 drawInfo.setStartIndex(0); 511 drawInfo.setIndexCount(kIndicesPerCubic); 512 drawInfo.setIndexBuffer(indexBuffer); 513 batchTarget->draw(drawInfo); 514 } 515 516 Geometry fGeometry; 517 GrPathUtils::QuadUVMatrix fDevToUV; 518 519 static const int kVertsPerCubic = 4; 520 static const int kIndicesPerCubic = 6; 521 522 typedef GrTestBatch INHERITED; 523}; 524 525/** 526 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend. 527 */ 528class BezierQuadEffects : public GM { 529public: 530 BezierQuadEffects() { 531 this->setBGColor(0xFFFFFFFF); 532 } 533 534protected: 535 SkString onShortName() override { 536 return SkString("bezier_quad_effects"); 537 } 538 539 SkISize onISize() override { 540 return SkISize::Make(800, 800); 541 } 542 543 544 void onDraw(SkCanvas* canvas) override { 545 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); 546 if (NULL == rt) { 547 this->drawGpuOnlyMessage(canvas); 548 return; 549 } 550 GrContext* context = rt->getContext(); 551 if (NULL == context) { 552 return; 553 } 554 555 struct Vertex { 556 SkPoint fPosition; 557 float fUV[4]; // The last two values are ignored. The effect expects a vec4f. 558 }; 559 560 static const int kNumQuads = 5; 561 SkRandom rand; 562 563 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3))); 564 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols); 565 SkScalar w = SkIntToScalar(rt->width()) / numCols; 566 SkScalar h = SkIntToScalar(rt->height()) / numRows; 567 int row = 0; 568 int col = 0; 569 570 for (int i = 0; i < kNumQuads; ++i) { 571 SkPoint baseControlPts[] = { 572 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 573 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}, 574 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)} 575 }; 576 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) { 577 SkAutoTUnref<GrGeometryProcessor> gp; 578 { // scope to contain GrTestTarget 579 GrTestTarget tt; 580 context->getTestTarget(&tt); 581 if (NULL == tt.target()) { 582 continue; 583 } 584 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType; 585 gp.reset(GrQuadEffect::Create(0xff000000, SkMatrix::I(), et, 586 *tt.target()->caps(), SkMatrix::I())); 587 if (!gp) { 588 continue; 589 } 590 } 591 592 SkScalar x = SkScalarMul(col, w); 593 SkScalar y = SkScalarMul(row, h); 594 SkPoint controlPts[] = { 595 {x + baseControlPts[0].fX, y + baseControlPts[0].fY}, 596 {x + baseControlPts[1].fX, y + baseControlPts[1].fY}, 597 {x + baseControlPts[2].fX, y + baseControlPts[2].fY} 598 }; 599 SkPoint chopped[5]; 600 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped); 601 602 SkPaint ctrlPtPaint; 603 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000); 604 for (int i = 0; i < 3; ++i) { 605 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint); 606 } 607 608 SkPaint polyPaint; 609 polyPaint.setColor(0xffA0A0A0); 610 polyPaint.setStrokeWidth(0); 611 polyPaint.setStyle(SkPaint::kStroke_Style); 612 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint); 613 614 SkPaint choppedPtPaint; 615 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000); 616 617 for (int c = 0; c < cnt; ++c) { 618 SkPoint* pts = chopped + 2 * c; 619 620 for (int i = 0; i < 3; ++i) { 621 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint); 622 } 623 624 SkRect bounds; 625 bounds.set(pts, 3); 626 627 SkPaint boundsPaint; 628 boundsPaint.setColor(0xff808080); 629 boundsPaint.setStrokeWidth(0); 630 boundsPaint.setStyle(SkPaint::kStroke_Style); 631 canvas->drawRect(bounds, boundsPaint); 632 633 GrTestTarget tt; 634 context->getTestTarget(&tt); 635 SkASSERT(tt.target()); 636 637 GrPipelineBuilder pipelineBuilder; 638 pipelineBuilder.setRenderTarget(rt); 639 640 GrPathUtils::QuadUVMatrix DevToUV(pts); 641 642 BezierQuadTestBatch::Geometry geometry; 643 geometry.fColor = gp->color(); 644 geometry.fBounds = bounds; 645 646 SkAutoTUnref<GrBatch> batch(BezierQuadTestBatch::Create(gp, geometry, DevToUV)); 647 648 tt.target()->drawBatch(&pipelineBuilder, batch); 649 } 650 ++col; 651 if (numCols == col) { 652 col = 0; 653 ++row; 654 } 655 } 656 } 657 } 658 659private: 660 typedef GM INHERITED; 661}; 662 663DEF_GM( return SkNEW(BezierCubicEffects); ) 664DEF_GM( return SkNEW(BezierConicEffects); ) 665DEF_GM( return SkNEW(BezierQuadEffects); ) 666 667} 668 669#endif 670