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