Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2012 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 #include "gm.h"
      9 #if SK_SUPPORT_GPU
     10 #include "GrContext.h"
     11 #include "GrDrawContext.h"
     12 #include "batches/GrDrawBatch.h"
     13 #include "batches/GrRectBatchFactory.h"
     14 #include "effects/GrRRectEffect.h"
     15 #endif
     16 #include "SkDevice.h"
     17 #include "SkRRect.h"
     18 
     19 namespace skiagm {
     20 
     21 ///////////////////////////////////////////////////////////////////////////////
     22 
     23 class RRectGM : public GM {
     24 public:
     25     enum Type {
     26         kBW_Draw_Type,
     27         kAA_Draw_Type,
     28         kBW_Clip_Type,
     29         kAA_Clip_Type,
     30         kEffect_Type,
     31     };
     32     RRectGM(Type type) : fType(type) { }
     33 
     34 protected:
     35 
     36     void onOnceBeforeDraw() override {
     37         this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
     38         this->setUpRRects();
     39     }
     40 
     41     SkString onShortName() override {
     42         SkString name("rrect");
     43         switch (fType) {
     44             case kBW_Draw_Type:
     45                 name.append("_draw_bw");
     46                 break;
     47             case kAA_Draw_Type:
     48                 name.append("_draw_aa");
     49                 break;
     50             case kBW_Clip_Type:
     51                 name.append("_clip_bw");
     52                 break;
     53             case kAA_Clip_Type:
     54                 name.append("_clip_aa");
     55                 break;
     56             case kEffect_Type:
     57                 name.append("_effect");
     58                 break;
     59         }
     60         return name;
     61     }
     62 
     63     SkISize onISize() override { return SkISize::Make(kImageWidth, kImageHeight); }
     64 
     65     void onDraw(SkCanvas* canvas) override {
     66         GrContext* context = nullptr;
     67 #if SK_SUPPORT_GPU
     68         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
     69         context = rt ? rt->getContext() : nullptr;
     70         SkAutoTUnref<GrDrawContext> drawContext;
     71         if (kEffect_Type == fType) {
     72             if (!context) {
     73                 skiagm::GM::DrawGpuOnlyMessage(canvas);
     74                 return;
     75             }
     76 
     77             drawContext.reset(context->drawContext(rt));
     78             if (!drawContext) {
     79                 return;
     80             }
     81         }
     82 #endif
     83         if (kEffect_Type == fType && nullptr == context) {
     84             skiagm::GM::DrawGpuOnlyMessage(canvas);
     85             return;
     86         }
     87 
     88         SkPaint paint;
     89         if (kAA_Draw_Type == fType) {
     90             paint.setAntiAlias(true);
     91         }
     92 
     93         static const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX),
     94                                                            SkIntToScalar(kTileY));
     95 #ifdef SK_DEBUG
     96         static const SkRect kMaxImageBound = SkRect::MakeWH(SkIntToScalar(kImageWidth),
     97                                                             SkIntToScalar(kImageHeight));
     98 #endif
     99 
    100 #if SK_SUPPORT_GPU
    101         int lastEdgeType = (kEffect_Type == fType) ? kLast_GrProcessorEdgeType: 0;
    102 #else
    103         int lastEdgeType = 0;
    104 #endif
    105 
    106         int y = 1;
    107         for (int et = 0; et <= lastEdgeType; ++et) {
    108             int x = 1;
    109             for (int curRRect = 0; curRRect < kNumRRects; ++curRRect) {
    110                 bool drew = true;
    111 #ifdef SK_DEBUG
    112                 SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds()));
    113                 SkRect imageSpaceBounds = fRRects[curRRect].getBounds();
    114                 imageSpaceBounds.offset(SkIntToScalar(x), SkIntToScalar(y));
    115                 SkASSERT(kMaxImageBound.contains(imageSpaceBounds));
    116 #endif
    117                 canvas->save();
    118                     canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    119                     if (kEffect_Type == fType) {
    120 #if SK_SUPPORT_GPU
    121                         GrPipelineBuilder pipelineBuilder;
    122                         pipelineBuilder.setXPFactory(
    123                             GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
    124 
    125                         SkRRect rrect = fRRects[curRRect];
    126                         rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
    127                         GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
    128                         SkAutoTUnref<GrFragmentProcessor> fp(GrRRectEffect::Create(edgeType,
    129                                                                                    rrect));
    130                         if (fp) {
    131                             pipelineBuilder.addCoverageFragmentProcessor(fp);
    132                             pipelineBuilder.setRenderTarget(rt);
    133 
    134                             SkRect bounds = rrect.getBounds();
    135                             bounds.outset(2.f, 2.f);
    136 
    137                             SkAutoTUnref<GrDrawBatch> batch(
    138                                     GrRectBatchFactory::CreateNonAAFill(0xff000000, SkMatrix::I(),
    139                                                                         bounds, nullptr, nullptr));
    140                             drawContext->internal_drawBatch(pipelineBuilder, batch);
    141                         } else {
    142                             drew = false;
    143                         }
    144 #endif
    145                     } else if (kBW_Clip_Type == fType || kAA_Clip_Type == fType) {
    146                         bool aaClip = (kAA_Clip_Type == fType);
    147                         canvas->clipRRect(fRRects[curRRect], SkRegion::kReplace_Op, aaClip);
    148                         canvas->drawRect(kMaxTileBound, paint);
    149                     } else {
    150                         canvas->drawRRect(fRRects[curRRect], paint);
    151                     }
    152                 canvas->restore();
    153                 if (drew) {
    154                     x = x + kTileX;
    155                     if (x > kImageWidth) {
    156                         x = 1;
    157                         y += kTileY;
    158                     }
    159                 }
    160             }
    161             if (x != 1) {
    162                 y += kTileY;
    163             }
    164         }
    165     }
    166 
    167     void setUpRRects() {
    168         // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
    169         // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.
    170 
    171         // simple cases
    172         fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
    173         fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
    174         fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);
    175         fRRects[3].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 5);
    176         // small circular corners are an interesting test case for gpu clipping
    177         fRRects[4].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 1, 1);
    178         fRRects[5].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.5f, 0.5f);
    179         fRRects[6].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.2f, 0.2f);
    180 
    181         // The first complex case needs special handling since it is a square
    182         fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
    183         for (size_t i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) {
    184             fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
    185         }
    186     }
    187 
    188 private:
    189     Type fType;
    190 
    191     static const int kImageWidth = 640;
    192     static const int kImageHeight = 480;
    193 
    194     static const int kTileX = 80;
    195     static const int kTileY = 40;
    196 
    197     static const int kNumSimpleCases = 7;
    198     static const int kNumComplexCases = 35;
    199     static const SkVector gRadii[kNumComplexCases][4];
    200 
    201     static const int kNumRRects = kNumSimpleCases + kNumComplexCases;
    202     SkRRect fRRects[kNumRRects];
    203 
    204     typedef GM INHERITED;
    205 };
    206 
    207 // Radii for the various test cases. Order is UL, UR, LR, LL
    208 const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
    209     // a circle
    210     { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },
    211 
    212     // odd ball cases
    213     { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
    214     { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
    215     { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },
    216 
    217     // UL
    218     { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    219     { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    220     { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    221 
    222     // UR
    223     { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
    224     { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
    225     { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },
    226 
    227     // LR
    228     { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
    229     { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
    230     { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },
    231 
    232     // LL
    233     { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
    234     { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
    235     { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },
    236 
    237     // over-sized radii
    238     { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
    239     { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
    240     { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
    241 
    242     // circular corner tabs
    243     { { 0, 0 }, { 20, 20 }, { 20, 20 }, { 0, 0 } },
    244     { { 20, 20 }, { 20, 20 }, { 0, 0 }, { 0, 0 } },
    245     { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 20, 20 } },
    246     { { 20, 20 }, { 0, 0 }, { 0, 0 }, { 20, 20 } },
    247 
    248     // small radius circular corner tabs
    249     { { 0, 0 }, { 0.2f, 0.2f }, { 0.2f, 0.2f }, { 0, 0 } },
    250     { { 0.3f, 0.3f }, { 0.3f, .3f }, { 0, 0 }, { 0, 0 } },
    251 
    252     // single circular corner cases
    253     { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 15 } },
    254     { { 0, 0 }, { 0, 0 }, { 15, 15 }, { 0, 0 } },
    255     { { 0, 0 }, { 15, 15 }, { 0, 0 }, { 0, 0 } },
    256     { { 15, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    257 
    258     // nine patch elliptical
    259     { { 5, 7 }, { 8, 7 }, { 8, 12 }, { 5, 12 } },
    260     { { 0, 7 }, { 8, 7 }, { 8, 12 }, { 0, 12 } },
    261 
    262     // nine patch elliptical, small radii
    263     { { 0.4f, 7 }, { 8, 7 }, { 8, 12 }, { 0.4f, 12 } },
    264     { { 0.4f, 0.4f }, { 8, 0.4f }, { 8, 12 }, { 0.4f, 12 } },
    265     { { 20, 0.4f }, { 18, 0.4f }, { 18, 0.4f }, { 20, 0.4f } },
    266     { { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f } },
    267 
    268 };
    269 
    270 ///////////////////////////////////////////////////////////////////////////////
    271 
    272 DEF_GM( return new RRectGM(RRectGM::kAA_Draw_Type); )
    273 DEF_GM( return new RRectGM(RRectGM::kBW_Draw_Type); )
    274 DEF_GM( return new RRectGM(RRectGM::kAA_Clip_Type); )
    275 DEF_GM( return new RRectGM(RRectGM::kBW_Clip_Type); )
    276 #if SK_SUPPORT_GPU
    277 DEF_GM( return new RRectGM(RRectGM::kEffect_Type); )
    278 #endif
    279 
    280 }
    281