flippity.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright 2017 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/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColor.h"
  11. #include "include/core/SkFont.h"
  12. #include "include/core/SkFontTypes.h"
  13. #include "include/core/SkImage.h"
  14. #include "include/core/SkImageInfo.h"
  15. #include "include/core/SkMatrix.h"
  16. #include "include/core/SkPaint.h"
  17. #include "include/core/SkPoint.h"
  18. #include "include/core/SkRect.h"
  19. #include "include/core/SkRefCnt.h"
  20. #include "include/core/SkSize.h"
  21. #include "include/core/SkString.h"
  22. #include "include/core/SkSurface.h"
  23. #include "include/core/SkTypeface.h"
  24. #include "include/core/SkTypes.h"
  25. #include "include/gpu/GrContext.h"
  26. #include "include/gpu/GrTypes.h"
  27. #include "include/private/SkTArray.h"
  28. #include "src/image/SkImage_Base.h"
  29. #include "src/image/SkImage_Gpu.h"
  30. #include "tools/ToolUtils.h"
  31. #include "tools/gpu/ProxyUtils.h"
  32. #include <string.h>
  33. #include <utility>
  34. class GrRenderTargetContext;
  35. static const int kNumMatrices = 6;
  36. static const int kImageSize = 128;
  37. static const int kLabelSize = 32;
  38. static const int kNumLabels = 4;
  39. static const int kInset = 16;
  40. static const int kCellSize = kImageSize+2*kLabelSize;
  41. static const int kGMWidth = kNumMatrices*kCellSize;
  42. static const int kGMHeight = 4*kCellSize;
  43. static const SkPoint kPoints[kNumLabels] = {
  44. { 0, kImageSize }, // LL
  45. { kImageSize, kImageSize }, // LR
  46. { 0, 0 }, // UL
  47. { kImageSize, 0 }, // UR
  48. };
  49. static const SkMatrix kUVMatrices[kNumMatrices] = {
  50. SkMatrix::MakeAll( 0, -1, 1,
  51. -1, 0, 1,
  52. 0, 0, 1),
  53. SkMatrix::MakeAll( 1, 0, 0,
  54. 0, -1, 1,
  55. 0, 0, 1),
  56. // flip x
  57. SkMatrix::MakeAll(-1, 0, 1,
  58. 0, 1, 0,
  59. 0, 0, 1),
  60. SkMatrix::MakeAll( 0, 1, 0,
  61. -1, 0, 1,
  62. 0, 0, 1),
  63. // flip both x & y == rotate 180
  64. SkMatrix::MakeAll(-1, 0, 1,
  65. 0, -1, 1,
  66. 0, 0, 1),
  67. // identity
  68. SkMatrix::MakeAll(1, 0, 0,
  69. 0, 1, 0,
  70. 0, 0, 1)
  71. };
  72. // Create a fixed size text label like "LL" or "LR".
  73. static sk_sp<SkImage> make_text_image(GrContext* context, const char* text, SkColor color) {
  74. SkPaint paint;
  75. paint.setAntiAlias(true);
  76. paint.setColor(color);
  77. SkFont font;
  78. font.setEdging(SkFont::Edging::kAntiAlias);
  79. font.setTypeface(ToolUtils::create_portable_typeface());
  80. font.setSize(32);
  81. SkRect bounds;
  82. font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
  83. const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
  84. SkMatrix::kFill_ScaleToFit);
  85. const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
  86. sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
  87. SkCanvas* canvas = surf->getCanvas();
  88. canvas->clear(SK_ColorWHITE);
  89. canvas->concat(mat);
  90. canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 0, 0, font, paint);
  91. sk_sp<SkImage> image = surf->makeImageSnapshot();
  92. return image->makeTextureImage(context, nullptr);
  93. }
  94. // Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
  95. // or top-left.
  96. static sk_sp<SkImage> make_reference_image(GrContext* context,
  97. const SkTArray<sk_sp<SkImage>>& labels,
  98. bool bottomLeftOrigin) {
  99. SkASSERT(kNumLabels == labels.count());
  100. SkImageInfo ii =
  101. SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
  102. SkBitmap bm;
  103. bm.allocPixels(ii);
  104. SkCanvas canvas(bm);
  105. canvas.clear(SK_ColorWHITE);
  106. for (int i = 0; i < kNumLabels; ++i) {
  107. canvas.drawImage(labels[i],
  108. 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
  109. 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
  110. }
  111. auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
  112. auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, GrRenderable::kNo, kImageSize,
  113. kImageSize, bm.colorType(), bm.alphaType(),
  114. origin, bm.getPixels(), bm.rowBytes());
  115. if (!proxy) {
  116. return nullptr;
  117. }
  118. return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
  119. std::move(proxy), nullptr);
  120. }
  121. // Here we're converting from a matrix that is intended for UVs to a matrix that is intended
  122. // for rect geometry used for a drawImage call. They are, in some sense, inverses of each
  123. // other but we also need a scale to map from the [0..1] uv range to the actual size of
  124. // image.
  125. static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
  126. const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
  127. SkMatrix tmp = uvMat;
  128. tmp.preConcat(yFlip);
  129. tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
  130. tmp.postConcat(yFlip);
  131. tmp.postScale(kImageSize, kImageSize);
  132. return tmp.invert(geomMat);
  133. }
  134. // This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
  135. // rotates.
  136. class FlippityGM : public skiagm::GpuGM {
  137. public:
  138. FlippityGM() {
  139. this->setBGColor(0xFFCCCCCC);
  140. }
  141. protected:
  142. SkString onShortName() override {
  143. return SkString("flippity");
  144. }
  145. SkISize onISize() override {
  146. return SkISize::Make(kGMWidth, kGMHeight);
  147. }
  148. // Draw the reference image and the four corner labels in the matrix's coordinate space
  149. void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
  150. bool drawSubset, bool drawScaled) {
  151. static const SkRect kSubsets[kNumMatrices] = {
  152. SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
  153. SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
  154. SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
  155. SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
  156. SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
  157. SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
  158. };
  159. SkMatrix imageGeomMat;
  160. SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
  161. canvas->save();
  162. // draw the reference image
  163. canvas->concat(imageGeomMat);
  164. if (drawSubset) {
  165. canvas->drawImageRect(image, kSubsets[matIndex],
  166. drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
  167. : kSubsets[matIndex],
  168. nullptr, SkCanvas::kFast_SrcRectConstraint);
  169. } else {
  170. canvas->drawImage(image, 0, 0);
  171. }
  172. // draw the labels
  173. for (int i = 0; i < kNumLabels; ++i) {
  174. canvas->drawImage(fLabels[i],
  175. 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
  176. 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
  177. }
  178. canvas->restore();
  179. }
  180. void drawRow(GrContext* context, SkCanvas* canvas,
  181. bool bottomLeftImage, bool drawSubset, bool drawScaled) {
  182. sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
  183. canvas->save();
  184. canvas->translate(kLabelSize, kLabelSize);
  185. for (int i = 0; i < kNumMatrices; ++i) {
  186. this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
  187. drawSubset, drawScaled);
  188. canvas->translate(kCellSize, 0);
  189. }
  190. canvas->restore();
  191. }
  192. void makeLabels(GrContext* context) {
  193. static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
  194. static const SkColor kLabelColors[kNumLabels] = {
  195. SK_ColorRED,
  196. SK_ColorGREEN,
  197. SK_ColorBLUE,
  198. SK_ColorCYAN
  199. };
  200. SkASSERT(!fLabels.count());
  201. for (int i = 0; i < kNumLabels; ++i) {
  202. fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
  203. }
  204. SkASSERT(kNumLabels == fLabels.count());
  205. }
  206. void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
  207. this->makeLabels(context);
  208. canvas->save();
  209. // Top row gets TL image
  210. this->drawRow(context, canvas, false, false, false);
  211. canvas->translate(0, kCellSize);
  212. // Bottom row gets BL image
  213. this->drawRow(context, canvas, true, false, false);
  214. canvas->translate(0, kCellSize);
  215. // Third row gets subsets of BL images
  216. this->drawRow(context, canvas, true, true, false);
  217. canvas->translate(0, kCellSize);
  218. // Fourth row gets scaled subsets of BL images
  219. this->drawRow(context, canvas, true, true, true);
  220. canvas->restore();
  221. // separator grid
  222. for (int i = 0; i < 4; ++i) {
  223. canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
  224. }
  225. for (int i = 0; i < kNumMatrices; ++i) {
  226. canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
  227. }
  228. }
  229. private:
  230. SkTArray<sk_sp<SkImage>> fLabels;
  231. typedef GM INHERITED;
  232. };
  233. DEF_GM(return new FlippityGM;)