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 }; RRectGM(Type type)32 RRectGM(Type type) : fType(type) { } 33 34 protected: 35 onOnceBeforeDraw()36 void onOnceBeforeDraw() override { 37 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD)); 38 this->setUpRRects(); 39 } 40 onShortName()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 onISize()63 SkISize onISize() override { return SkISize::Make(kImageWidth, kImageHeight); } 64 onDraw(SkCanvas * canvas)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 setUpRRects()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