blob: f4358382c34506c6c4ef623b97594701b0b3bff7 [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
8#include "gm.h"
9#include "sk_tool_utils.h"
10
11#include "SkSurface.h"
12
13#if SK_SUPPORT_GPU
14
15#include "SkImage_Gpu.h"
16
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;
Robert Phillipsf0a30d72017-11-01 14:05:12 -040062 sk_tool_utils::set_portable_typeface(&paint);
Robert Phillipsa0971732017-10-31 12:26:35 -040063 paint.setAntiAlias(true);
64 paint.setTextSize(32);
65 paint.setColor(color);
66
67 SkRect bounds;
68 paint.measureText(text, strlen(text), &bounds);
69 const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
70 SkMatrix::kFill_ScaleToFit);
71
72 const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
73 sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
74
75 SkCanvas* canvas = surf->getCanvas();
76
77 canvas->clear(SK_ColorWHITE);
78 canvas->concat(mat);
79 canvas->drawText(text, strlen(text), 0, 0, paint);
80
81 sk_sp<SkImage> image = surf->makeImageSnapshot();
82
83 return image->makeTextureImage(context, nullptr);
84}
85
86static SkColor swap_red_and_blue(SkColor c) {
87 return SkColorSetRGB(SkColorGetB(c), SkColorGetG(c), SkColorGetR(c));
88}
89
90// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
91// or top-left.
Robert Phillips206bda52017-11-01 09:26:06 -040092static sk_sp<SkImage> make_reference_image(GrContext* context,
93 const SkTArray<sk_sp<SkImage>>& labels,
94 bool bottomLeftOrigin) {
Robert Phillipsa0971732017-10-31 12:26:35 -040095 SkASSERT(kNumLabels == labels.count());
96
97 SkImageInfo ii = SkImageInfo::Make(kImageSize, kImageSize,
98 kN32_SkColorType, kOpaque_SkAlphaType);
99 SkBitmap bm;
100 bm.allocPixels(ii);
101 SkCanvas canvas(bm);
102
103 canvas.clear(SK_ColorWHITE);
104 for (int i = 0; i < kNumLabels; ++i) {
105 canvas.drawImage(labels[i],
Robert Phillips206bda52017-11-01 09:26:06 -0400106 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
107 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
Robert Phillipsa0971732017-10-31 12:26:35 -0400108 }
109
110 GrSurfaceDesc desc;
111 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
112 desc.fWidth = kImageSize;
113 desc.fHeight = kImageSize;
114 desc.fConfig = kRGBA_8888_GrPixelConfig;
115
116 if (bottomLeftOrigin) {
117 // Note that Ganesh will flip the data when it is uploaded
118 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
119 }
120
121 if (kN32_SkColorType == kBGRA_8888_SkColorType) {
122 // We're playing a game here and uploading N32 data into an RGB dest. We might have
123 // to swap red & blue to compensate.
124 for (int y = 0; y < bm.height(); ++y) {
125 uint32_t *sl = bm.getAddr32(0, y);
126 for (int x = 0; x < bm.width(); ++x) {
127 sl[x] = swap_red_and_blue(sl[x]);
128 }
129 }
130 }
131
132 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
133 desc, SkBudgeted::kYes,
134 bm.getPixels(), bm.rowBytes());
135 if (!proxy) {
136 return nullptr;
137 }
138
139 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, kOpaque_SkAlphaType,
140 std::move(proxy), nullptr, SkBudgeted::kYes);
141}
142
143// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
144// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
145// other but we also need a scale to map from the [0..1] uv range to the actual size of
146// image.
147static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400148
149 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
150
Robert Phillipsa0971732017-10-31 12:26:35 -0400151 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400152 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400153 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400154
155 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400156 tmp.postScale(kImageSize, kImageSize);
157
158 return tmp.invert(geomMat);
159}
160
161// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
162// rotates.
163class FlippityGM : public skiagm::GM {
164public:
165 FlippityGM() {
166 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
167 }
168
169protected:
170
171 SkString onShortName() override {
172 return SkString("flippity");
173 }
174
175 SkISize onISize() override {
176 return SkISize::Make(kGMWidth, kGMHeight);
177 }
178
179 // Draw the reference image and the four corner labels in the matrix's coordinate space
Robert Phillips206bda52017-11-01 09:26:06 -0400180 void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
181 bool drawSubset, bool drawScaled) {
182 static const SkRect kSubsets[kNumMatrices] = {
183 SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
184 SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
185 SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
186 SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
187 SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
188 SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
189 };
190
Robert Phillipsa0971732017-10-31 12:26:35 -0400191 SkMatrix imageGeomMat;
192 SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
193
194 canvas->save();
Robert Phillipsa0971732017-10-31 12:26:35 -0400195
196 // draw the reference image
Robert Phillips206bda52017-11-01 09:26:06 -0400197 canvas->concat(imageGeomMat);
198 if (drawSubset) {
199 canvas->drawImageRect(image, kSubsets[matIndex],
200 drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
201 : kSubsets[matIndex],
202 nullptr, SkCanvas::kFast_SrcRectConstraint);
203 } else {
204 canvas->drawImage(image, 0, 0);
205 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400206
207 // draw the labels
208 for (int i = 0; i < kNumLabels; ++i) {
209 canvas->drawImage(fLabels[i],
210 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
211 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
212 }
213 canvas->restore();
214 }
215
Robert Phillips206bda52017-11-01 09:26:06 -0400216 void drawRow(GrContext* context, SkCanvas* canvas,
217 bool bottomLeftImage, bool drawSubset, bool drawScaled) {
218
219 sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
220
221 canvas->save();
222 canvas->translate(kLabelSize, kLabelSize);
223
224 for (int i = 0; i < kNumMatrices; ++i) {
225 this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
226 drawSubset, drawScaled);
227 canvas->translate(kCellSize, 0);
228 }
229 canvas->restore();
230 }
231
Robert Phillipsa0971732017-10-31 12:26:35 -0400232 void makeLabels(GrContext* context) {
233 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
234
235 static const SkColor kLabelColors[kNumLabels] = {
236 SK_ColorRED,
237 SK_ColorGREEN,
238 SK_ColorBLUE,
239 SK_ColorCYAN
240 };
241
242 SkASSERT(!fLabels.count());
243 for (int i = 0; i < kNumLabels; ++i) {
244 fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
245 }
246 SkASSERT(kNumLabels == fLabels.count());
247 }
248
249 void onDraw(SkCanvas* canvas) override {
250 GrContext* context = canvas->getGrContext();
251 if (!context) {
252 skiagm::GM::DrawGpuOnlyMessage(canvas);
253 return;
254 }
255
256 this->makeLabels(context);
257
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400258 canvas->save();
259
Robert Phillipsa0971732017-10-31 12:26:35 -0400260 // Top row gets TL image
Robert Phillips206bda52017-11-01 09:26:06 -0400261 this->drawRow(context, canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400262
Robert Phillips206bda52017-11-01 09:26:06 -0400263 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400264
265 // Bottom row gets BL image
Robert Phillips206bda52017-11-01 09:26:06 -0400266 this->drawRow(context, canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400267
Robert Phillips206bda52017-11-01 09:26:06 -0400268 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400269
Robert Phillips206bda52017-11-01 09:26:06 -0400270 // Third row gets subsets of BL images
271 this->drawRow(context, canvas, true, true, false);
272
273 canvas->translate(0, kCellSize);
274
275 // Fourth row gets scaled subsets of BL images
276 this->drawRow(context, canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400277
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400278 canvas->restore();
279
Robert Phillipsa0971732017-10-31 12:26:35 -0400280 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400281 for (int i = 0; i < 4; ++i) {
282 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
283 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400284 for (int i = 0; i < kNumMatrices; ++i) {
285 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
286 }
287 }
288
289private:
290 SkTArray<sk_sp<SkImage>> fLabels;
291
292 typedef GM INHERITED;
293};
294
295DEF_GM(return new FlippityGM;)
296
297#endif