blob: ec9ade46579342e872b6bd805d3fbcd9528d0008 [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"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkFont.h"
13#include "include/core/SkFontTypes.h"
14#include "include/core/SkImage.h"
15#include "include/core/SkImageInfo.h"
16#include "include/core/SkMatrix.h"
17#include "include/core/SkPaint.h"
18#include "include/core/SkPoint.h"
19#include "include/core/SkRect.h"
20#include "include/core/SkRefCnt.h"
21#include "include/core/SkSize.h"
22#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/core/SkSurface.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040024#include "include/core/SkTypeface.h"
25#include "include/core/SkTypes.h"
Robert Phillipsb87b39b2020-07-01 14:45:24 -040026#include "include/gpu/GrDirectContext.h"
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040027#include "include/gpu/GrRecordingContext.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040028#include "include/gpu/GrTypes.h"
Kevin Lubickdc6cc022023-01-13 11:24:27 -050029#include "include/private/base/SkTArray.h"
Greg Daniel719239c2022-04-07 11:20:24 -040030#include "src/gpu/ganesh/GrDirectContextPriv.h"
31#include "src/gpu/ganesh/GrPixmap.h"
Kevin Lubickbf174bc2023-03-27 11:24:20 -040032#include "src/gpu/ganesh/image/SkImage_Ganesh.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040033#include "src/image/SkImage_Base.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040034#include "tools/ToolUtils.h"
Kevin Lubicke836c3a2023-10-20 06:55:35 -040035#include "tools/fonts/FontToolUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "tools/gpu/ProxyUtils.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040037
Ben Wagner7fde8e12019-05-01 17:28:53 -040038#include <string.h>
39#include <utility>
40
Herb Derbyec96c212023-03-06 10:31:22 -050041using namespace skia_private;
42
Robert Phillipsa0971732017-10-31 12:26:35 -040043static const int kNumMatrices = 6;
44static const int kImageSize = 128;
45static const int kLabelSize = 32;
46static const int kNumLabels = 4;
Robert Phillips206bda52017-11-01 09:26:06 -040047static const int kInset = 16;
Robert Phillipsa0971732017-10-31 12:26:35 -040048
49static const int kCellSize = kImageSize+2*kLabelSize;
50static const int kGMWidth = kNumMatrices*kCellSize;
Robert Phillips206bda52017-11-01 09:26:06 -040051static const int kGMHeight = 4*kCellSize;
Robert Phillipsa0971732017-10-31 12:26:35 -040052
53static const SkPoint kPoints[kNumLabels] = {
Robert Phillips206bda52017-11-01 09:26:06 -040054 { 0, kImageSize }, // LL
55 { kImageSize, kImageSize }, // LR
56 { 0, 0 }, // UL
57 { kImageSize, 0 }, // UR
Robert Phillipsa0971732017-10-31 12:26:35 -040058};
59
60static const SkMatrix kUVMatrices[kNumMatrices] = {
61 SkMatrix::MakeAll( 0, -1, 1,
62 -1, 0, 1,
63 0, 0, 1),
64 SkMatrix::MakeAll( 1, 0, 0,
65 0, -1, 1,
66 0, 0, 1),
67 // flip x
68 SkMatrix::MakeAll(-1, 0, 1,
69 0, 1, 0,
70 0, 0, 1),
71 SkMatrix::MakeAll( 0, 1, 0,
72 -1, 0, 1,
73 0, 0, 1),
74 // flip both x & y == rotate 180
75 SkMatrix::MakeAll(-1, 0, 1,
76 0, -1, 1,
77 0, 0, 1),
78 // identity
79 SkMatrix::MakeAll(1, 0, 0,
80 0, 1, 0,
81 0, 0, 1)
82};
83
Robert Phillips206bda52017-11-01 09:26:06 -040084
Robert Phillipsa0971732017-10-31 12:26:35 -040085// Create a fixed size text label like "LL" or "LR".
Robert Phillips88d8aba2023-02-22 11:04:06 -050086static sk_sp<SkImage> make_text_image(const char* text, SkColor color) {
Robert Phillipsa0971732017-10-31 12:26:35 -040087 SkPaint paint;
88 paint.setAntiAlias(true);
Robert Phillipsa0971732017-10-31 12:26:35 -040089 paint.setColor(color);
90
Kevin Lubickbca43ec2023-10-30 10:11:22 -040091 SkFont font = ToolUtils::DefaultPortableFont();
Mike Reed94cca602018-12-02 16:04:27 -050092 font.setEdging(SkFont::Edging::kAntiAlias);
Mike Reed94cca602018-12-02 16:04:27 -050093 font.setSize(32);
94
Robert Phillipsa0971732017-10-31 12:26:35 -040095 SkRect bounds;
Ben Wagner51e15a62019-05-07 15:38:46 -040096 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
Mike Reed2ac6ce82021-01-15 12:26:22 -050097 const SkMatrix mat = SkMatrix::RectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize));
Robert Phillipsa0971732017-10-31 12:26:35 -040098
99 const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400100 sk_sp<SkSurface> surf = SkSurfaces::Raster(ii);
Robert Phillipsa0971732017-10-31 12:26:35 -0400101
102 SkCanvas* canvas = surf->getCanvas();
103
104 canvas->clear(SK_ColorWHITE);
105 canvas->concat(mat);
Ben Wagner51e15a62019-05-07 15:38:46 -0400106 canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 0, 0, font, paint);
Robert Phillipsa0971732017-10-31 12:26:35 -0400107
Robert Phillips88d8aba2023-02-22 11:04:06 -0500108 return surf->makeImageSnapshot();
Robert Phillipsa0971732017-10-31 12:26:35 -0400109}
110
Robert Phillipsa0971732017-10-31 12:26:35 -0400111// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
112// or top-left.
Robert Phillips88d8aba2023-02-22 11:04:06 -0500113static sk_sp<SkImage> make_reference_image(SkCanvas* mainCanvas,
Herb Derbyec96c212023-03-06 10:31:22 -0500114 const TArray<sk_sp<SkImage>>& labels,
Robert Phillips206bda52017-11-01 09:26:06 -0400115 bool bottomLeftOrigin) {
Herb Derbyffacce52022-11-09 10:51:34 -0500116 SkASSERT(kNumLabels == labels.size());
Robert Phillipsa0971732017-10-31 12:26:35 -0400117
Robert Phillips88d8aba2023-02-22 11:04:06 -0500118 SkImageInfo ii = SkImageInfo::Make(kImageSize, kImageSize,
119 kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
Robert Phillipsa0971732017-10-31 12:26:35 -0400120 SkBitmap bm;
121 bm.allocPixels(ii);
Robert Phillipsa0971732017-10-31 12:26:35 -0400122
Robert Phillips88d8aba2023-02-22 11:04:06 -0500123 {
124 SkCanvas canvas(bm);
125
126 canvas.clear(SK_ColorWHITE);
127 for (int i = 0; i < kNumLabels; ++i) {
128 canvas.drawImage(labels[i],
129 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
130 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
131 }
132
133 bm.setImmutable();
Robert Phillipsa0971732017-10-31 12:26:35 -0400134 }
135
Robert Phillips88d8aba2023-02-22 11:04:06 -0500136 auto dContext = GrAsDirectContext(mainCanvas->recordingContext());
137 if (dContext && !dContext->abandoned()) {
138 auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
Robert Phillipsa0971732017-10-31 12:26:35 -0400139
Robert Phillips88d8aba2023-02-22 11:04:06 -0500140 auto view = sk_gpu_test::MakeTextureProxyViewFromData(dContext, GrRenderable::kNo, origin,
141 bm.pixmap());
142 if (!view) {
143 return nullptr;
144 }
145
Kevin Lubickbf174bc2023-03-27 11:24:20 -0400146 return sk_make_sp<SkImage_Ganesh>(
147 sk_ref_sp(dContext), kNeedNewImageUniqueID, std::move(view), ii.colorInfo());
Robert Phillipsa0971732017-10-31 12:26:35 -0400148 }
149
Kevin Lubick77472bf2023-03-24 07:11:17 -0400150 return SkImages::RasterFromBitmap(bm);
Robert Phillipsa0971732017-10-31 12:26:35 -0400151}
152
153// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
154// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
155// other but we also need a scale to map from the [0..1] uv range to the actual size of
156// image.
157static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400158
159 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
160
Robert Phillipsa0971732017-10-31 12:26:35 -0400161 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400162 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400163 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400164
165 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400166 tmp.postScale(kImageSize, kImageSize);
167
168 return tmp.invert(geomMat);
169}
170
171// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
172// rotates.
Robert Phillipsedcd4312021-06-03 10:14:16 -0400173class FlippityGM : public skiagm::GM {
Robert Phillipsa0971732017-10-31 12:26:35 -0400174public:
175 FlippityGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400176 this->setBGColor(0xFFCCCCCC);
Robert Phillipsa0971732017-10-31 12:26:35 -0400177 }
178
Ben Wagnerc061d312019-08-14 15:31:52 -0400179private:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000180 SkString getName() const override { return SkString("flippity"); }
Robert Phillipsa0971732017-10-31 12:26:35 -0400181
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000182 SkISize getISize() override { return SkISize::Make(kGMWidth, kGMHeight); }
Robert Phillipsa0971732017-10-31 12:26:35 -0400183
184 // Draw the reference image and the four corner labels in the matrix's coordinate space
Robert Phillips206bda52017-11-01 09:26:06 -0400185 void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
186 bool drawSubset, bool drawScaled) {
187 static const SkRect kSubsets[kNumMatrices] = {
188 SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
189 SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
190 SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
191 SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
192 SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
193 SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
194 };
195
Robert Phillipsa0971732017-10-31 12:26:35 -0400196 SkMatrix imageGeomMat;
197 SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
198
199 canvas->save();
Robert Phillipsa0971732017-10-31 12:26:35 -0400200
201 // draw the reference image
Robert Phillips206bda52017-11-01 09:26:06 -0400202 canvas->concat(imageGeomMat);
203 if (drawSubset) {
204 canvas->drawImageRect(image, kSubsets[matIndex],
205 drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
206 : kSubsets[matIndex],
Mike Reedd396cd52021-01-23 21:14:47 -0500207 SkSamplingOptions(), nullptr,
208 SkCanvas::kFast_SrcRectConstraint);
Robert Phillips206bda52017-11-01 09:26:06 -0400209 } else {
210 canvas->drawImage(image, 0, 0);
211 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400212
213 // draw the labels
214 for (int i = 0; i < kNumLabels; ++i) {
215 canvas->drawImage(fLabels[i],
216 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
217 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
218 }
219 canvas->restore();
220 }
221
Robert Phillipsc869ff72020-06-19 09:50:33 -0400222 void drawRow(SkCanvas* canvas, bool bottomLeftImage, bool drawSubset, bool drawScaled) {
Robert Phillips206bda52017-11-01 09:26:06 -0400223
224 canvas->save();
225 canvas->translate(kLabelSize, kLabelSize);
226
227 for (int i = 0; i < kNumMatrices; ++i) {
Robert Phillipsc869ff72020-06-19 09:50:33 -0400228 this->drawImageWithMatrixAndLabels(canvas, fReferenceImages[bottomLeftImage].get(),
229 i, drawSubset, drawScaled);
Robert Phillips206bda52017-11-01 09:26:06 -0400230 canvas->translate(kCellSize, 0);
231 }
232 canvas->restore();
233 }
234
Robert Phillips88d8aba2023-02-22 11:04:06 -0500235 void makeLabels() {
Herb Derbyffacce52022-11-09 10:51:34 -0500236 if (fLabels.size()) {
Ben Wagnerc061d312019-08-14 15:31:52 -0400237 return;
238 }
239
Robert Phillipsa0971732017-10-31 12:26:35 -0400240 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
241
242 static const SkColor kLabelColors[kNumLabels] = {
243 SK_ColorRED,
244 SK_ColorGREEN,
245 SK_ColorBLUE,
246 SK_ColorCYAN
247 };
248
Robert Phillipsa0971732017-10-31 12:26:35 -0400249 for (int i = 0; i < kNumLabels; ++i) {
Robert Phillips88d8aba2023-02-22 11:04:06 -0500250 fLabels.push_back(make_text_image(kLabelText[i], kLabelColors[i]));
Robert Phillipsa0971732017-10-31 12:26:35 -0400251 }
Herb Derbyffacce52022-11-09 10:51:34 -0500252 SkASSERT(kNumLabels == fLabels.size());
Robert Phillipsa0971732017-10-31 12:26:35 -0400253 }
254
Brian Salomonc759bbf2023-12-05 11:11:27 -0500255 DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override {
Robert Phillips88d8aba2023-02-22 11:04:06 -0500256 this->makeLabels();
257 fReferenceImages[0] = make_reference_image(canvas, fLabels, false);
258 fReferenceImages[1] = make_reference_image(canvas, fLabels, true);
Robert Phillipsc869ff72020-06-19 09:50:33 -0400259 if (!fReferenceImages[0] || !fReferenceImages[1]) {
260 *errorMsg = "Failed to create reference images.";
261 return DrawResult::kFail;
262 }
263
264 return DrawResult::kOk;
265 }
266
Robert Phillipsb795bea2020-06-25 12:38:53 -0400267 void onGpuTeardown() override {
Herb Derbye308b1c2022-12-13 09:27:24 -0500268 fLabels.clear();
Robert Phillipsb795bea2020-06-25 12:38:53 -0400269 fReferenceImages[0] = fReferenceImages[1] = nullptr;
270 }
271
Robert Phillipsedcd4312021-06-03 10:14:16 -0400272 void onDraw(SkCanvas* canvas) override {
Robert Phillipsc869ff72020-06-19 09:50:33 -0400273 SkASSERT(fReferenceImages[0] && fReferenceImages[1]);
Robert Phillipsa0971732017-10-31 12:26:35 -0400274
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400275 canvas->save();
276
Robert Phillipsa0971732017-10-31 12:26:35 -0400277 // Top row gets TL image
Robert Phillipsc869ff72020-06-19 09:50:33 -0400278 this->drawRow(canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400279
Robert Phillips206bda52017-11-01 09:26:06 -0400280 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400281
282 // Bottom row gets BL image
Robert Phillipsc869ff72020-06-19 09:50:33 -0400283 this->drawRow(canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400284
Robert Phillips206bda52017-11-01 09:26:06 -0400285 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400286
Robert Phillips206bda52017-11-01 09:26:06 -0400287 // Third row gets subsets of BL images
Robert Phillipsc869ff72020-06-19 09:50:33 -0400288 this->drawRow(canvas, true, true, false);
Robert Phillips206bda52017-11-01 09:26:06 -0400289
290 canvas->translate(0, kCellSize);
291
292 // Fourth row gets scaled subsets of BL images
Robert Phillipsc869ff72020-06-19 09:50:33 -0400293 this->drawRow(canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400294
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400295 canvas->restore();
296
Robert Phillipsa0971732017-10-31 12:26:35 -0400297 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400298 for (int i = 0; i < 4; ++i) {
299 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
300 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400301 for (int i = 0; i < kNumMatrices; ++i) {
302 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
303 }
304 }
305
306private:
Herb Derbyec96c212023-03-06 10:31:22 -0500307 TArray<sk_sp<SkImage>> fLabels;
Robert Phillipsc869ff72020-06-19 09:50:33 -0400308 sk_sp<SkImage> fReferenceImages[2];
Robert Phillipsa0971732017-10-31 12:26:35 -0400309
John Stiles7571f9e2020-09-02 22:42:33 -0400310 using INHERITED = GM;
Robert Phillipsa0971732017-10-31 12:26:35 -0400311};
312
313DEF_GM(return new FlippityGM;)