rrects.cpp 9.9 KB

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