blob: aa5798c962af90842f8f52756b1ecbee88e3f5ca [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"
29#include "include/private/SkTArray.h"
Greg Daniel81b98972019-12-13 11:09:43 -050030#include "src/gpu/GrContextPriv.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040031#include "src/image/SkImage_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050032#include "src/image/SkImage_Gpu.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040033#include "tools/ToolUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050034#include "tools/gpu/ProxyUtils.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040035
Ben Wagner7fde8e12019-05-01 17:28:53 -040036#include <string.h>
37#include <utility>
38
39class GrRenderTargetContext;
40
Robert Phillipsa0971732017-10-31 12:26:35 -040041static const int kNumMatrices = 6;
42static const int kImageSize = 128;
43static const int kLabelSize = 32;
44static const int kNumLabels = 4;
Robert Phillips206bda52017-11-01 09:26:06 -040045static const int kInset = 16;
Robert Phillipsa0971732017-10-31 12:26:35 -040046
47static const int kCellSize = kImageSize+2*kLabelSize;
48static const int kGMWidth = kNumMatrices*kCellSize;
Robert Phillips206bda52017-11-01 09:26:06 -040049static const int kGMHeight = 4*kCellSize;
Robert Phillipsa0971732017-10-31 12:26:35 -040050
51static const SkPoint kPoints[kNumLabels] = {
Robert Phillips206bda52017-11-01 09:26:06 -040052 { 0, kImageSize }, // LL
53 { kImageSize, kImageSize }, // LR
54 { 0, 0 }, // UL
55 { kImageSize, 0 }, // UR
Robert Phillipsa0971732017-10-31 12:26:35 -040056};
57
58static const SkMatrix kUVMatrices[kNumMatrices] = {
59 SkMatrix::MakeAll( 0, -1, 1,
60 -1, 0, 1,
61 0, 0, 1),
62 SkMatrix::MakeAll( 1, 0, 0,
63 0, -1, 1,
64 0, 0, 1),
65 // flip x
66 SkMatrix::MakeAll(-1, 0, 1,
67 0, 1, 0,
68 0, 0, 1),
69 SkMatrix::MakeAll( 0, 1, 0,
70 -1, 0, 1,
71 0, 0, 1),
72 // flip both x & y == rotate 180
73 SkMatrix::MakeAll(-1, 0, 1,
74 0, -1, 1,
75 0, 0, 1),
76 // identity
77 SkMatrix::MakeAll(1, 0, 0,
78 0, 1, 0,
79 0, 0, 1)
80};
81
Robert Phillips206bda52017-11-01 09:26:06 -040082
Robert Phillipsa0971732017-10-31 12:26:35 -040083// Create a fixed size text label like "LL" or "LR".
84static sk_sp<SkImage> make_text_image(GrContext* context, const char* text, SkColor color) {
85 SkPaint paint;
86 paint.setAntiAlias(true);
Robert Phillipsa0971732017-10-31 12:26:35 -040087 paint.setColor(color);
88
Mike Reed94cca602018-12-02 16:04:27 -050089 SkFont font;
90 font.setEdging(SkFont::Edging::kAntiAlias);
Mike Kleinea3f0142019-03-20 11:12:10 -050091 font.setTypeface(ToolUtils::create_portable_typeface());
Mike Reed94cca602018-12-02 16:04:27 -050092 font.setSize(32);
93
Robert Phillipsa0971732017-10-31 12:26:35 -040094 SkRect bounds;
Ben Wagner51e15a62019-05-07 15:38:46 -040095 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
Robert Phillipsa0971732017-10-31 12:26:35 -040096 const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
97 SkMatrix::kFill_ScaleToFit);
98
99 const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
100 sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
101
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
108 sk_sp<SkImage> image = surf->makeImageSnapshot();
109
Brian Osmand566e2e2019-08-14 13:19:04 -0400110 return image->makeTextureImage(context);
Robert Phillipsa0971732017-10-31 12:26:35 -0400111}
112
Robert Phillipsa0971732017-10-31 12:26:35 -0400113// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
114// or top-left.
Robert Phillipsb87b39b2020-07-01 14:45:24 -0400115static sk_sp<SkImage> make_reference_image(GrDirectContext* context,
Robert Phillips206bda52017-11-01 09:26:06 -0400116 const SkTArray<sk_sp<SkImage>>& labels,
117 bool bottomLeftOrigin) {
Robert Phillipsa0971732017-10-31 12:26:35 -0400118 SkASSERT(kNumLabels == labels.count());
119
Brian Salomon58389b92018-03-07 13:01:25 -0500120 SkImageInfo ii =
121 SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
Robert Phillipsa0971732017-10-31 12:26:35 -0400122 SkBitmap bm;
123 bm.allocPixels(ii);
124 SkCanvas canvas(bm);
125
126 canvas.clear(SK_ColorWHITE);
127 for (int i = 0; i < kNumLabels; ++i) {
128 canvas.drawImage(labels[i],
Robert Phillips206bda52017-11-01 09:26:06 -0400129 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
130 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
Robert Phillipsa0971732017-10-31 12:26:35 -0400131 }
132
Brian Salomon2a4f9832018-03-03 22:43:43 -0500133 auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
Robert Phillipsa0971732017-10-31 12:26:35 -0400134
Greg Daniel81b98972019-12-13 11:09:43 -0500135 // TODO: make MakeTextureProxyFromData return a GrSurfaceProxyView
Brian Salomon4eda7102019-10-21 15:04:52 -0400136 auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, GrRenderable::kNo, origin,
137 bm.info(), bm.getPixels(), bm.rowBytes());
Robert Phillipsa0971732017-10-31 12:26:35 -0400138 if (!proxy) {
139 return nullptr;
140 }
141
Greg Daniel14b57212019-12-17 16:18:06 -0500142 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(),
Greg Daniel7c165a42020-01-22 12:22:36 -0500143 GrColorType::kRGBA_8888);
Greg Daniel81b98972019-12-13 11:09:43 -0500144 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
Greg Daniel7c165a42020-01-22 12:22:36 -0500145 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, std::move(view),
146 ii.colorType(), kOpaque_SkAlphaType, nullptr);
Robert Phillipsa0971732017-10-31 12:26:35 -0400147}
148
149// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
150// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
151// other but we also need a scale to map from the [0..1] uv range to the actual size of
152// image.
153static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400154
155 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
156
Robert Phillipsa0971732017-10-31 12:26:35 -0400157 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400158 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400159 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400160
161 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400162 tmp.postScale(kImageSize, kImageSize);
163
164 return tmp.invert(geomMat);
165}
166
167// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
168// rotates.
Chris Dalton3a778372019-02-07 15:23:36 -0700169class FlippityGM : public skiagm::GpuGM {
Robert Phillipsa0971732017-10-31 12:26:35 -0400170public:
171 FlippityGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400172 this->setBGColor(0xFFCCCCCC);
Robert Phillipsa0971732017-10-31 12:26:35 -0400173 }
174
Ben Wagnerc061d312019-08-14 15:31:52 -0400175private:
Robert Phillipsa0971732017-10-31 12:26:35 -0400176 SkString onShortName() override {
177 return SkString("flippity");
178 }
179
180 SkISize onISize() override {
181 return SkISize::Make(kGMWidth, kGMHeight);
182 }
183
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],
207 nullptr, SkCanvas::kFast_SrcRectConstraint);
208 } else {
209 canvas->drawImage(image, 0, 0);
210 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400211
212 // draw the labels
213 for (int i = 0; i < kNumLabels; ++i) {
214 canvas->drawImage(fLabels[i],
215 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
216 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
217 }
218 canvas->restore();
219 }
220
Robert Phillipsc869ff72020-06-19 09:50:33 -0400221 void drawRow(SkCanvas* canvas, bool bottomLeftImage, bool drawSubset, bool drawScaled) {
Robert Phillips206bda52017-11-01 09:26:06 -0400222
223 canvas->save();
224 canvas->translate(kLabelSize, kLabelSize);
225
226 for (int i = 0; i < kNumMatrices; ++i) {
Robert Phillipsc869ff72020-06-19 09:50:33 -0400227 this->drawImageWithMatrixAndLabels(canvas, fReferenceImages[bottomLeftImage].get(),
228 i, drawSubset, drawScaled);
Robert Phillips206bda52017-11-01 09:26:06 -0400229 canvas->translate(kCellSize, 0);
230 }
231 canvas->restore();
232 }
233
Robert Phillipsb87b39b2020-07-01 14:45:24 -0400234 void makeLabels(GrDirectContext* context) {
Ben Wagnerc061d312019-08-14 15:31:52 -0400235 if (fLabels.count()) {
236 return;
237 }
238
Robert Phillipsa0971732017-10-31 12:26:35 -0400239 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
240
241 static const SkColor kLabelColors[kNumLabels] = {
242 SK_ColorRED,
243 SK_ColorGREEN,
244 SK_ColorBLUE,
245 SK_ColorCYAN
246 };
247
Robert Phillipsa0971732017-10-31 12:26:35 -0400248 for (int i = 0; i < kNumLabels; ++i) {
249 fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
250 }
251 SkASSERT(kNumLabels == fLabels.count());
252 }
253
Robert Phillipsb87b39b2020-07-01 14:45:24 -0400254 DrawResult onGpuSetup(GrDirectContext* context, SkString* errorMsg) override {
Robert Phillipsc869ff72020-06-19 09:50:33 -0400255 if (!context || context->abandoned()) {
256 return DrawResult::kSkip;
257 }
258
Robert Phillipsa0971732017-10-31 12:26:35 -0400259 this->makeLabels(context);
Robert Phillipsc869ff72020-06-19 09:50:33 -0400260 fReferenceImages[0] = make_reference_image(context, fLabels, false);
261 fReferenceImages[1] = make_reference_image(context, fLabels, true);
262 if (!fReferenceImages[0] || !fReferenceImages[1]) {
263 *errorMsg = "Failed to create reference images.";
264 return DrawResult::kFail;
265 }
266
267 return DrawResult::kOk;
268 }
269
Robert Phillipsb795bea2020-06-25 12:38:53 -0400270 void onGpuTeardown() override {
271 fLabels.reset();
272 fReferenceImages[0] = fReferenceImages[1] = nullptr;
273 }
274
Robert Phillips95c250c2020-06-29 15:36:12 -0400275 void onDraw(GrRecordingContext*, GrRenderTargetContext*, SkCanvas* canvas) override {
Robert Phillipsc869ff72020-06-19 09:50:33 -0400276 SkASSERT(fReferenceImages[0] && fReferenceImages[1]);
Robert Phillipsa0971732017-10-31 12:26:35 -0400277
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400278 canvas->save();
279
Robert Phillipsa0971732017-10-31 12:26:35 -0400280 // Top row gets TL image
Robert Phillipsc869ff72020-06-19 09:50:33 -0400281 this->drawRow(canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400282
Robert Phillips206bda52017-11-01 09:26:06 -0400283 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400284
285 // Bottom row gets BL image
Robert Phillipsc869ff72020-06-19 09:50:33 -0400286 this->drawRow(canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400287
Robert Phillips206bda52017-11-01 09:26:06 -0400288 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400289
Robert Phillips206bda52017-11-01 09:26:06 -0400290 // Third row gets subsets of BL images
Robert Phillipsc869ff72020-06-19 09:50:33 -0400291 this->drawRow(canvas, true, true, false);
Robert Phillips206bda52017-11-01 09:26:06 -0400292
293 canvas->translate(0, kCellSize);
294
295 // Fourth row gets scaled subsets of BL images
Robert Phillipsc869ff72020-06-19 09:50:33 -0400296 this->drawRow(canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400297
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400298 canvas->restore();
299
Robert Phillipsa0971732017-10-31 12:26:35 -0400300 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400301 for (int i = 0; i < 4; ++i) {
302 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
303 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400304 for (int i = 0; i < kNumMatrices; ++i) {
305 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
306 }
307 }
308
309private:
310 SkTArray<sk_sp<SkImage>> fLabels;
Robert Phillipsc869ff72020-06-19 09:50:33 -0400311 sk_sp<SkImage> fReferenceImages[2];
Robert Phillipsa0971732017-10-31 12:26:35 -0400312
313 typedef GM INHERITED;
314};
315
316DEF_GM(return new FlippityGM;)