blob: 93813b943f056ac1deef86334ad88425fe7f3209 [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
Robert Phillips1afd4cd2018-01-08 13:40:32 -050015#include "GrContextPriv.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040016#include "SkImage_Gpu.h"
17
18static const int kNumMatrices = 6;
19static const int kImageSize = 128;
20static const int kLabelSize = 32;
21static const int kNumLabels = 4;
Robert Phillips206bda52017-11-01 09:26:06 -040022static const int kInset = 16;
Robert Phillipsa0971732017-10-31 12:26:35 -040023
24static const int kCellSize = kImageSize+2*kLabelSize;
25static const int kGMWidth = kNumMatrices*kCellSize;
Robert Phillips206bda52017-11-01 09:26:06 -040026static const int kGMHeight = 4*kCellSize;
Robert Phillipsa0971732017-10-31 12:26:35 -040027
28static const SkPoint kPoints[kNumLabels] = {
Robert Phillips206bda52017-11-01 09:26:06 -040029 { 0, kImageSize }, // LL
30 { kImageSize, kImageSize }, // LR
31 { 0, 0 }, // UL
32 { kImageSize, 0 }, // UR
Robert Phillipsa0971732017-10-31 12:26:35 -040033};
34
35static const SkMatrix kUVMatrices[kNumMatrices] = {
36 SkMatrix::MakeAll( 0, -1, 1,
37 -1, 0, 1,
38 0, 0, 1),
39 SkMatrix::MakeAll( 1, 0, 0,
40 0, -1, 1,
41 0, 0, 1),
42 // flip x
43 SkMatrix::MakeAll(-1, 0, 1,
44 0, 1, 0,
45 0, 0, 1),
46 SkMatrix::MakeAll( 0, 1, 0,
47 -1, 0, 1,
48 0, 0, 1),
49 // flip both x & y == rotate 180
50 SkMatrix::MakeAll(-1, 0, 1,
51 0, -1, 1,
52 0, 0, 1),
53 // identity
54 SkMatrix::MakeAll(1, 0, 0,
55 0, 1, 0,
56 0, 0, 1)
57};
58
Robert Phillips206bda52017-11-01 09:26:06 -040059
Robert Phillipsa0971732017-10-31 12:26:35 -040060// Create a fixed size text label like "LL" or "LR".
61static sk_sp<SkImage> make_text_image(GrContext* context, const char* text, SkColor color) {
62 SkPaint paint;
Robert Phillipsf0a30d72017-11-01 14:05:12 -040063 sk_tool_utils::set_portable_typeface(&paint);
Robert Phillipsa0971732017-10-31 12:26:35 -040064 paint.setAntiAlias(true);
65 paint.setTextSize(32);
66 paint.setColor(color);
67
68 SkRect bounds;
69 paint.measureText(text, strlen(text), &bounds);
70 const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
71 SkMatrix::kFill_ScaleToFit);
72
73 const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
74 sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
75
76 SkCanvas* canvas = surf->getCanvas();
77
78 canvas->clear(SK_ColorWHITE);
79 canvas->concat(mat);
80 canvas->drawText(text, strlen(text), 0, 0, paint);
81
82 sk_sp<SkImage> image = surf->makeImageSnapshot();
83
84 return image->makeTextureImage(context, nullptr);
85}
86
87static SkColor swap_red_and_blue(SkColor c) {
88 return SkColorSetRGB(SkColorGetB(c), SkColorGetG(c), SkColorGetR(c));
89}
90
91// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
92// or top-left.
Robert Phillips206bda52017-11-01 09:26:06 -040093static sk_sp<SkImage> make_reference_image(GrContext* context,
94 const SkTArray<sk_sp<SkImage>>& labels,
95 bool bottomLeftOrigin) {
Robert Phillipsa0971732017-10-31 12:26:35 -040096 SkASSERT(kNumLabels == labels.count());
97
98 SkImageInfo ii = SkImageInfo::Make(kImageSize, kImageSize,
99 kN32_SkColorType, kOpaque_SkAlphaType);
100 SkBitmap bm;
101 bm.allocPixels(ii);
102 SkCanvas canvas(bm);
103
104 canvas.clear(SK_ColorWHITE);
105 for (int i = 0; i < kNumLabels; ++i) {
106 canvas.drawImage(labels[i],
Robert Phillips206bda52017-11-01 09:26:06 -0400107 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
108 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
Robert Phillipsa0971732017-10-31 12:26:35 -0400109 }
110
111 GrSurfaceDesc desc;
112 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
113 desc.fWidth = kImageSize;
114 desc.fHeight = kImageSize;
115 desc.fConfig = kRGBA_8888_GrPixelConfig;
116
117 if (bottomLeftOrigin) {
118 // Note that Ganesh will flip the data when it is uploaded
119 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
120 }
121
122 if (kN32_SkColorType == kBGRA_8888_SkColorType) {
123 // We're playing a game here and uploading N32 data into an RGB dest. We might have
124 // to swap red & blue to compensate.
125 for (int y = 0; y < bm.height(); ++y) {
126 uint32_t *sl = bm.getAddr32(0, y);
127 for (int x = 0; x < bm.width(); ++x) {
128 sl[x] = swap_red_and_blue(sl[x]);
129 }
130 }
131 }
132
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500133 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(
134 context->contextPriv().proxyProvider(),
135 desc, SkBudgeted::kYes,
136 bm.getPixels(), bm.rowBytes());
Robert Phillipsa0971732017-10-31 12:26:35 -0400137 if (!proxy) {
138 return nullptr;
139 }
140
141 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, kOpaque_SkAlphaType,
142 std::move(proxy), nullptr, SkBudgeted::kYes);
143}
144
145// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
146// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
147// other but we also need a scale to map from the [0..1] uv range to the actual size of
148// image.
149static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400150
151 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
152
Robert Phillipsa0971732017-10-31 12:26:35 -0400153 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400154 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400155 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400156
157 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400158 tmp.postScale(kImageSize, kImageSize);
159
160 return tmp.invert(geomMat);
161}
162
163// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
164// rotates.
165class FlippityGM : public skiagm::GM {
166public:
167 FlippityGM() {
168 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
169 }
170
171protected:
172
173 SkString onShortName() override {
174 return SkString("flippity");
175 }
176
177 SkISize onISize() override {
178 return SkISize::Make(kGMWidth, kGMHeight);
179 }
180
181 // Draw the reference image and the four corner labels in the matrix's coordinate space
Robert Phillips206bda52017-11-01 09:26:06 -0400182 void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
183 bool drawSubset, bool drawScaled) {
184 static const SkRect kSubsets[kNumMatrices] = {
185 SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
186 SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
187 SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
188 SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
189 SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
190 SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
191 };
192
Robert Phillipsa0971732017-10-31 12:26:35 -0400193 SkMatrix imageGeomMat;
194 SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
195
196 canvas->save();
Robert Phillipsa0971732017-10-31 12:26:35 -0400197
198 // draw the reference image
Robert Phillips206bda52017-11-01 09:26:06 -0400199 canvas->concat(imageGeomMat);
200 if (drawSubset) {
201 canvas->drawImageRect(image, kSubsets[matIndex],
202 drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
203 : kSubsets[matIndex],
204 nullptr, SkCanvas::kFast_SrcRectConstraint);
205 } else {
206 canvas->drawImage(image, 0, 0);
207 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400208
209 // draw the labels
210 for (int i = 0; i < kNumLabels; ++i) {
211 canvas->drawImage(fLabels[i],
212 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
213 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
214 }
215 canvas->restore();
216 }
217
Robert Phillips206bda52017-11-01 09:26:06 -0400218 void drawRow(GrContext* context, SkCanvas* canvas,
219 bool bottomLeftImage, bool drawSubset, bool drawScaled) {
220
221 sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
222
223 canvas->save();
224 canvas->translate(kLabelSize, kLabelSize);
225
226 for (int i = 0; i < kNumMatrices; ++i) {
227 this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
228 drawSubset, drawScaled);
229 canvas->translate(kCellSize, 0);
230 }
231 canvas->restore();
232 }
233
Robert Phillipsa0971732017-10-31 12:26:35 -0400234 void makeLabels(GrContext* context) {
235 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
236
237 static const SkColor kLabelColors[kNumLabels] = {
238 SK_ColorRED,
239 SK_ColorGREEN,
240 SK_ColorBLUE,
241 SK_ColorCYAN
242 };
243
244 SkASSERT(!fLabels.count());
245 for (int i = 0; i < kNumLabels; ++i) {
246 fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
247 }
248 SkASSERT(kNumLabels == fLabels.count());
249 }
250
251 void onDraw(SkCanvas* canvas) override {
252 GrContext* context = canvas->getGrContext();
253 if (!context) {
254 skiagm::GM::DrawGpuOnlyMessage(canvas);
255 return;
256 }
257
258 this->makeLabels(context);
259
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400260 canvas->save();
261
Robert Phillipsa0971732017-10-31 12:26:35 -0400262 // Top row gets TL image
Robert Phillips206bda52017-11-01 09:26:06 -0400263 this->drawRow(context, canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400264
Robert Phillips206bda52017-11-01 09:26:06 -0400265 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400266
267 // Bottom row gets BL image
Robert Phillips206bda52017-11-01 09:26:06 -0400268 this->drawRow(context, canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400269
Robert Phillips206bda52017-11-01 09:26:06 -0400270 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400271
Robert Phillips206bda52017-11-01 09:26:06 -0400272 // Third row gets subsets of BL images
273 this->drawRow(context, canvas, true, true, false);
274
275 canvas->translate(0, kCellSize);
276
277 // Fourth row gets scaled subsets of BL images
278 this->drawRow(context, canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400279
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400280 canvas->restore();
281
Robert Phillipsa0971732017-10-31 12:26:35 -0400282 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400283 for (int i = 0; i < 4; ++i) {
284 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
285 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400286 for (int i = 0; i < kNumMatrices; ++i) {
287 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
288 }
289 }
290
291private:
292 SkTArray<sk_sp<SkImage>> fLabels;
293
294 typedef GM INHERITED;
295};
296
297DEF_GM(return new FlippityGM;)
298
299#endif