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