blob: 1cdc5007b520e462fe94e8dcf7e503c5eba8194e [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
Robert Phillips1afd4cd2018-01-08 13:40:32 -050013#include "GrContextPriv.h"
Brian Salomon58389b92018-03-07 13:01:25 -050014#include "ProxyUtils.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040015#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
Robert Phillipsa0971732017-10-31 12:26:35 -040086// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
87// or top-left.
Robert Phillips206bda52017-11-01 09:26:06 -040088static sk_sp<SkImage> make_reference_image(GrContext* context,
89 const SkTArray<sk_sp<SkImage>>& labels,
90 bool bottomLeftOrigin) {
Robert Phillipsa0971732017-10-31 12:26:35 -040091 SkASSERT(kNumLabels == labels.count());
92
Brian Salomon58389b92018-03-07 13:01:25 -050093 SkImageInfo ii =
94 SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
Robert Phillipsa0971732017-10-31 12:26:35 -040095 SkBitmap bm;
96 bm.allocPixels(ii);
97 SkCanvas canvas(bm);
98
99 canvas.clear(SK_ColorWHITE);
100 for (int i = 0; i < kNumLabels; ++i) {
101 canvas.drawImage(labels[i],
Robert Phillips206bda52017-11-01 09:26:06 -0400102 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
103 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
Robert Phillipsa0971732017-10-31 12:26:35 -0400104 }
105
Brian Salomon2a4f9832018-03-03 22:43:43 -0500106 auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
Robert Phillipsa0971732017-10-31 12:26:35 -0400107
Brian Salomon58389b92018-03-07 13:01:25 -0500108 auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, false, kImageSize, kImageSize,
109 bm.colorType(), origin, bm.getPixels(),
110 bm.rowBytes());
Robert Phillipsa0971732017-10-31 12:26:35 -0400111 if (!proxy) {
112 return nullptr;
113 }
114
Brian Salomon8a8dd332018-05-24 14:08:31 -0400115 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
Robert Phillipsa0971732017-10-31 12:26:35 -0400116 std::move(proxy), nullptr, SkBudgeted::kYes);
117}
118
119// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
120// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
121// other but we also need a scale to map from the [0..1] uv range to the actual size of
122// image.
123static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400124
125 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
126
Robert Phillipsa0971732017-10-31 12:26:35 -0400127 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400128 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400129 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400130
131 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400132 tmp.postScale(kImageSize, kImageSize);
133
134 return tmp.invert(geomMat);
135}
136
137// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
138// rotates.
139class FlippityGM : public skiagm::GM {
140public:
141 FlippityGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400142 this->setBGColor(0xFFCCCCCC);
Robert Phillipsa0971732017-10-31 12:26:35 -0400143 }
144
145protected:
146
147 SkString onShortName() override {
148 return SkString("flippity");
149 }
150
151 SkISize onISize() override {
152 return SkISize::Make(kGMWidth, kGMHeight);
153 }
154
155 // Draw the reference image and the four corner labels in the matrix's coordinate space
Robert Phillips206bda52017-11-01 09:26:06 -0400156 void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
157 bool drawSubset, bool drawScaled) {
158 static const SkRect kSubsets[kNumMatrices] = {
159 SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
160 SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
161 SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
162 SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
163 SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
164 SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
165 };
166
Robert Phillipsa0971732017-10-31 12:26:35 -0400167 SkMatrix imageGeomMat;
168 SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
169
170 canvas->save();
Robert Phillipsa0971732017-10-31 12:26:35 -0400171
172 // draw the reference image
Robert Phillips206bda52017-11-01 09:26:06 -0400173 canvas->concat(imageGeomMat);
174 if (drawSubset) {
175 canvas->drawImageRect(image, kSubsets[matIndex],
176 drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
177 : kSubsets[matIndex],
178 nullptr, SkCanvas::kFast_SrcRectConstraint);
179 } else {
180 canvas->drawImage(image, 0, 0);
181 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400182
183 // draw the labels
184 for (int i = 0; i < kNumLabels; ++i) {
185 canvas->drawImage(fLabels[i],
186 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
187 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
188 }
189 canvas->restore();
190 }
191
Robert Phillips206bda52017-11-01 09:26:06 -0400192 void drawRow(GrContext* context, SkCanvas* canvas,
193 bool bottomLeftImage, bool drawSubset, bool drawScaled) {
194
195 sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
196
197 canvas->save();
198 canvas->translate(kLabelSize, kLabelSize);
199
200 for (int i = 0; i < kNumMatrices; ++i) {
201 this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
202 drawSubset, drawScaled);
203 canvas->translate(kCellSize, 0);
204 }
205 canvas->restore();
206 }
207
Robert Phillipsa0971732017-10-31 12:26:35 -0400208 void makeLabels(GrContext* context) {
209 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
210
211 static const SkColor kLabelColors[kNumLabels] = {
212 SK_ColorRED,
213 SK_ColorGREEN,
214 SK_ColorBLUE,
215 SK_ColorCYAN
216 };
217
218 SkASSERT(!fLabels.count());
219 for (int i = 0; i < kNumLabels; ++i) {
220 fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
221 }
222 SkASSERT(kNumLabels == fLabels.count());
223 }
224
225 void onDraw(SkCanvas* canvas) override {
226 GrContext* context = canvas->getGrContext();
227 if (!context) {
228 skiagm::GM::DrawGpuOnlyMessage(canvas);
229 return;
230 }
231
232 this->makeLabels(context);
233
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400234 canvas->save();
235
Robert Phillipsa0971732017-10-31 12:26:35 -0400236 // Top row gets TL image
Robert Phillips206bda52017-11-01 09:26:06 -0400237 this->drawRow(context, canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400238
Robert Phillips206bda52017-11-01 09:26:06 -0400239 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400240
241 // Bottom row gets BL image
Robert Phillips206bda52017-11-01 09:26:06 -0400242 this->drawRow(context, canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400243
Robert Phillips206bda52017-11-01 09:26:06 -0400244 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400245
Robert Phillips206bda52017-11-01 09:26:06 -0400246 // Third row gets subsets of BL images
247 this->drawRow(context, canvas, true, true, false);
248
249 canvas->translate(0, kCellSize);
250
251 // Fourth row gets scaled subsets of BL images
252 this->drawRow(context, canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400253
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400254 canvas->restore();
255
Robert Phillipsa0971732017-10-31 12:26:35 -0400256 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400257 for (int i = 0; i < 4; ++i) {
258 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
259 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400260 for (int i = 0; i < kNumMatrices; ++i) {
261 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
262 }
263 }
264
265private:
266 SkTArray<sk_sp<SkImage>> fLabels;
267
268 typedef GM INHERITED;
269};
270
271DEF_GM(return new FlippityGM;)