blob: 7c595d6ffb63f0fbf4db3ef6f97a334147fa79ef [file] [log] [blame]
Robert Phillipsa0971732017-10-31 12:26:35 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "tools/ToolUtils.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040010
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkSurface.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040012
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrContextPriv.h"
14#include "src/image/SkImage_Gpu.h"
15#include "tools/gpu/ProxyUtils.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040016
17static const int kNumMatrices = 6;
18static const int kImageSize = 128;
19static const int kLabelSize = 32;
20static const int kNumLabels = 4;
Robert Phillips206bda52017-11-01 09:26:06 -040021static const int kInset = 16;
Robert Phillipsa0971732017-10-31 12:26:35 -040022
23static const int kCellSize = kImageSize+2*kLabelSize;
24static const int kGMWidth = kNumMatrices*kCellSize;
Robert Phillips206bda52017-11-01 09:26:06 -040025static const int kGMHeight = 4*kCellSize;
Robert Phillipsa0971732017-10-31 12:26:35 -040026
27static const SkPoint kPoints[kNumLabels] = {
Robert Phillips206bda52017-11-01 09:26:06 -040028 { 0, kImageSize }, // LL
29 { kImageSize, kImageSize }, // LR
30 { 0, 0 }, // UL
31 { kImageSize, 0 }, // UR
Robert Phillipsa0971732017-10-31 12:26:35 -040032};
33
34static const SkMatrix kUVMatrices[kNumMatrices] = {
35 SkMatrix::MakeAll( 0, -1, 1,
36 -1, 0, 1,
37 0, 0, 1),
38 SkMatrix::MakeAll( 1, 0, 0,
39 0, -1, 1,
40 0, 0, 1),
41 // flip x
42 SkMatrix::MakeAll(-1, 0, 1,
43 0, 1, 0,
44 0, 0, 1),
45 SkMatrix::MakeAll( 0, 1, 0,
46 -1, 0, 1,
47 0, 0, 1),
48 // flip both x & y == rotate 180
49 SkMatrix::MakeAll(-1, 0, 1,
50 0, -1, 1,
51 0, 0, 1),
52 // identity
53 SkMatrix::MakeAll(1, 0, 0,
54 0, 1, 0,
55 0, 0, 1)
56};
57
Robert Phillips206bda52017-11-01 09:26:06 -040058
Robert Phillipsa0971732017-10-31 12:26:35 -040059// Create a fixed size text label like "LL" or "LR".
60static sk_sp<SkImage> make_text_image(GrContext* context, const char* text, SkColor color) {
61 SkPaint paint;
62 paint.setAntiAlias(true);
Robert Phillipsa0971732017-10-31 12:26:35 -040063 paint.setColor(color);
64
Mike Reed94cca602018-12-02 16:04:27 -050065 SkFont font;
66 font.setEdging(SkFont::Edging::kAntiAlias);
Mike Kleinea3f0142019-03-20 11:12:10 -050067 font.setTypeface(ToolUtils::create_portable_typeface());
Mike Reed94cca602018-12-02 16:04:27 -050068 font.setSize(32);
69
Robert Phillipsa0971732017-10-31 12:26:35 -040070 SkRect bounds;
Mike Reed94cca602018-12-02 16:04:27 -050071 font.measureText(text, strlen(text), kUTF8_SkTextEncoding, &bounds);
Robert Phillipsa0971732017-10-31 12:26:35 -040072 const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
73 SkMatrix::kFill_ScaleToFit);
74
75 const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
76 sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
77
78 SkCanvas* canvas = surf->getCanvas();
79
80 canvas->clear(SK_ColorWHITE);
81 canvas->concat(mat);
Mike Reed94cca602018-12-02 16:04:27 -050082 canvas->drawSimpleText(text, strlen(text), kUTF8_SkTextEncoding, 0, 0, font, paint);
Robert Phillipsa0971732017-10-31 12:26:35 -040083
84 sk_sp<SkImage> image = surf->makeImageSnapshot();
85
86 return image->makeTextureImage(context, nullptr);
87}
88
Robert Phillipsa0971732017-10-31 12:26:35 -040089// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
90// or top-left.
Robert Phillips206bda52017-11-01 09:26:06 -040091static sk_sp<SkImage> make_reference_image(GrContext* context,
92 const SkTArray<sk_sp<SkImage>>& labels,
93 bool bottomLeftOrigin) {
Robert Phillipsa0971732017-10-31 12:26:35 -040094 SkASSERT(kNumLabels == labels.count());
95
Brian Salomon58389b92018-03-07 13:01:25 -050096 SkImageInfo ii =
97 SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
Robert Phillipsa0971732017-10-31 12:26:35 -040098 SkBitmap bm;
99 bm.allocPixels(ii);
100 SkCanvas canvas(bm);
101
102 canvas.clear(SK_ColorWHITE);
103 for (int i = 0; i < kNumLabels; ++i) {
104 canvas.drawImage(labels[i],
Robert Phillips206bda52017-11-01 09:26:06 -0400105 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
106 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
Robert Phillipsa0971732017-10-31 12:26:35 -0400107 }
108
Brian Salomon2a4f9832018-03-03 22:43:43 -0500109 auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
Robert Phillipsa0971732017-10-31 12:26:35 -0400110
Brian Salomon58389b92018-03-07 13:01:25 -0500111 auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, false, kImageSize, kImageSize,
112 bm.colorType(), origin, bm.getPixels(),
113 bm.rowBytes());
Robert Phillipsa0971732017-10-31 12:26:35 -0400114 if (!proxy) {
115 return nullptr;
116 }
117
Brian Salomon8a8dd332018-05-24 14:08:31 -0400118 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
Brian Salomonf05e6d32018-12-20 08:41:41 -0500119 std::move(proxy), nullptr);
Robert Phillipsa0971732017-10-31 12:26:35 -0400120}
121
122// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
123// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
124// other but we also need a scale to map from the [0..1] uv range to the actual size of
125// image.
126static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400127
128 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
129
Robert Phillipsa0971732017-10-31 12:26:35 -0400130 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400131 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400132 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400133
134 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400135 tmp.postScale(kImageSize, kImageSize);
136
137 return tmp.invert(geomMat);
138}
139
140// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
141// rotates.
Chris Dalton3a778372019-02-07 15:23:36 -0700142class FlippityGM : public skiagm::GpuGM {
Robert Phillipsa0971732017-10-31 12:26:35 -0400143public:
144 FlippityGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400145 this->setBGColor(0xFFCCCCCC);
Robert Phillipsa0971732017-10-31 12:26:35 -0400146 }
147
148protected:
149
150 SkString onShortName() override {
151 return SkString("flippity");
152 }
153
154 SkISize onISize() override {
155 return SkISize::Make(kGMWidth, kGMHeight);
156 }
157
158 // Draw the reference image and the four corner labels in the matrix's coordinate space
Robert Phillips206bda52017-11-01 09:26:06 -0400159 void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
160 bool drawSubset, bool drawScaled) {
161 static const SkRect kSubsets[kNumMatrices] = {
162 SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
163 SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
164 SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
165 SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
166 SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
167 SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
168 };
169
Robert Phillipsa0971732017-10-31 12:26:35 -0400170 SkMatrix imageGeomMat;
171 SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
172
173 canvas->save();
Robert Phillipsa0971732017-10-31 12:26:35 -0400174
175 // draw the reference image
Robert Phillips206bda52017-11-01 09:26:06 -0400176 canvas->concat(imageGeomMat);
177 if (drawSubset) {
178 canvas->drawImageRect(image, kSubsets[matIndex],
179 drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
180 : kSubsets[matIndex],
181 nullptr, SkCanvas::kFast_SrcRectConstraint);
182 } else {
183 canvas->drawImage(image, 0, 0);
184 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400185
186 // draw the labels
187 for (int i = 0; i < kNumLabels; ++i) {
188 canvas->drawImage(fLabels[i],
189 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
190 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
191 }
192 canvas->restore();
193 }
194
Robert Phillips206bda52017-11-01 09:26:06 -0400195 void drawRow(GrContext* context, SkCanvas* canvas,
196 bool bottomLeftImage, bool drawSubset, bool drawScaled) {
197
198 sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
199
200 canvas->save();
201 canvas->translate(kLabelSize, kLabelSize);
202
203 for (int i = 0; i < kNumMatrices; ++i) {
204 this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
205 drawSubset, drawScaled);
206 canvas->translate(kCellSize, 0);
207 }
208 canvas->restore();
209 }
210
Robert Phillipsa0971732017-10-31 12:26:35 -0400211 void makeLabels(GrContext* context) {
212 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
213
214 static const SkColor kLabelColors[kNumLabels] = {
215 SK_ColorRED,
216 SK_ColorGREEN,
217 SK_ColorBLUE,
218 SK_ColorCYAN
219 };
220
221 SkASSERT(!fLabels.count());
222 for (int i = 0; i < kNumLabels; ++i) {
223 fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
224 }
225 SkASSERT(kNumLabels == fLabels.count());
226 }
227
Chris Dalton3a778372019-02-07 15:23:36 -0700228 void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
Robert Phillipsa0971732017-10-31 12:26:35 -0400229 this->makeLabels(context);
230
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400231 canvas->save();
232
Robert Phillipsa0971732017-10-31 12:26:35 -0400233 // Top row gets TL image
Robert Phillips206bda52017-11-01 09:26:06 -0400234 this->drawRow(context, canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400235
Robert Phillips206bda52017-11-01 09:26:06 -0400236 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400237
238 // Bottom row gets BL image
Robert Phillips206bda52017-11-01 09:26:06 -0400239 this->drawRow(context, canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400240
Robert Phillips206bda52017-11-01 09:26:06 -0400241 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400242
Robert Phillips206bda52017-11-01 09:26:06 -0400243 // Third row gets subsets of BL images
244 this->drawRow(context, canvas, true, true, false);
245
246 canvas->translate(0, kCellSize);
247
248 // Fourth row gets scaled subsets of BL images
249 this->drawRow(context, canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400250
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400251 canvas->restore();
252
Robert Phillipsa0971732017-10-31 12:26:35 -0400253 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400254 for (int i = 0; i < 4; ++i) {
255 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
256 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400257 for (int i = 0; i < kNumMatrices; ++i) {
258 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
259 }
260 }
261
262private:
263 SkTArray<sk_sp<SkImage>> fLabels;
264
265 typedef GM INHERITED;
266};
267
268DEF_GM(return new FlippityGM;)