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