blob: 41895ff42a0555a4d41e5ff051ab3c7651bd5433 [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"
26#include "include/gpu/GrContext.h"
27#include "include/gpu/GrTypes.h"
28#include "include/private/SkTArray.h"
Greg Daniel81b98972019-12-13 11:09:43 -050029#include "src/gpu/GrContextPriv.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040030#include "src/image/SkImage_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "src/image/SkImage_Gpu.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040032#include "tools/ToolUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050033#include "tools/gpu/ProxyUtils.h"
Robert Phillipsa0971732017-10-31 12:26:35 -040034
Ben Wagner7fde8e12019-05-01 17:28:53 -040035#include <string.h>
36#include <utility>
37
38class GrRenderTargetContext;
39
Robert Phillipsa0971732017-10-31 12:26:35 -040040static const int kNumMatrices = 6;
41static const int kImageSize = 128;
42static const int kLabelSize = 32;
43static const int kNumLabels = 4;
Robert Phillips206bda52017-11-01 09:26:06 -040044static const int kInset = 16;
Robert Phillipsa0971732017-10-31 12:26:35 -040045
46static const int kCellSize = kImageSize+2*kLabelSize;
47static const int kGMWidth = kNumMatrices*kCellSize;
Robert Phillips206bda52017-11-01 09:26:06 -040048static const int kGMHeight = 4*kCellSize;
Robert Phillipsa0971732017-10-31 12:26:35 -040049
50static const SkPoint kPoints[kNumLabels] = {
Robert Phillips206bda52017-11-01 09:26:06 -040051 { 0, kImageSize }, // LL
52 { kImageSize, kImageSize }, // LR
53 { 0, 0 }, // UL
54 { kImageSize, 0 }, // UR
Robert Phillipsa0971732017-10-31 12:26:35 -040055};
56
57static const SkMatrix kUVMatrices[kNumMatrices] = {
58 SkMatrix::MakeAll( 0, -1, 1,
59 -1, 0, 1,
60 0, 0, 1),
61 SkMatrix::MakeAll( 1, 0, 0,
62 0, -1, 1,
63 0, 0, 1),
64 // flip x
65 SkMatrix::MakeAll(-1, 0, 1,
66 0, 1, 0,
67 0, 0, 1),
68 SkMatrix::MakeAll( 0, 1, 0,
69 -1, 0, 1,
70 0, 0, 1),
71 // flip both x & y == rotate 180
72 SkMatrix::MakeAll(-1, 0, 1,
73 0, -1, 1,
74 0, 0, 1),
75 // identity
76 SkMatrix::MakeAll(1, 0, 0,
77 0, 1, 0,
78 0, 0, 1)
79};
80
Robert Phillips206bda52017-11-01 09:26:06 -040081
Robert Phillipsa0971732017-10-31 12:26:35 -040082// Create a fixed size text label like "LL" or "LR".
83static sk_sp<SkImage> make_text_image(GrContext* context, const char* text, SkColor color) {
84 SkPaint paint;
85 paint.setAntiAlias(true);
Robert Phillipsa0971732017-10-31 12:26:35 -040086 paint.setColor(color);
87
Mike Reed94cca602018-12-02 16:04:27 -050088 SkFont font;
89 font.setEdging(SkFont::Edging::kAntiAlias);
Mike Kleinea3f0142019-03-20 11:12:10 -050090 font.setTypeface(ToolUtils::create_portable_typeface());
Mike Reed94cca602018-12-02 16:04:27 -050091 font.setSize(32);
92
Robert Phillipsa0971732017-10-31 12:26:35 -040093 SkRect bounds;
Ben Wagner51e15a62019-05-07 15:38:46 -040094 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
Robert Phillipsa0971732017-10-31 12:26:35 -040095 const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
96 SkMatrix::kFill_ScaleToFit);
97
98 const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
99 sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
100
101 SkCanvas* canvas = surf->getCanvas();
102
103 canvas->clear(SK_ColorWHITE);
104 canvas->concat(mat);
Ben Wagner51e15a62019-05-07 15:38:46 -0400105 canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 0, 0, font, paint);
Robert Phillipsa0971732017-10-31 12:26:35 -0400106
107 sk_sp<SkImage> image = surf->makeImageSnapshot();
108
Brian Osmand566e2e2019-08-14 13:19:04 -0400109 return image->makeTextureImage(context);
Robert Phillipsa0971732017-10-31 12:26:35 -0400110}
111
Robert Phillipsa0971732017-10-31 12:26:35 -0400112// Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
113// or top-left.
Robert Phillips206bda52017-11-01 09:26:06 -0400114static sk_sp<SkImage> make_reference_image(GrContext* context,
115 const SkTArray<sk_sp<SkImage>>& labels,
116 bool bottomLeftOrigin) {
Robert Phillipsa0971732017-10-31 12:26:35 -0400117 SkASSERT(kNumLabels == labels.count());
118
Brian Salomon58389b92018-03-07 13:01:25 -0500119 SkImageInfo ii =
120 SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
Robert Phillipsa0971732017-10-31 12:26:35 -0400121 SkBitmap bm;
122 bm.allocPixels(ii);
123 SkCanvas canvas(bm);
124
125 canvas.clear(SK_ColorWHITE);
126 for (int i = 0; i < kNumLabels; ++i) {
127 canvas.drawImage(labels[i],
Robert Phillips206bda52017-11-01 09:26:06 -0400128 0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
129 0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
Robert Phillipsa0971732017-10-31 12:26:35 -0400130 }
131
Brian Salomon2a4f9832018-03-03 22:43:43 -0500132 auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
Robert Phillipsa0971732017-10-31 12:26:35 -0400133
Greg Daniel81b98972019-12-13 11:09:43 -0500134 // TODO: make MakeTextureProxyFromData return a GrSurfaceProxyView
Brian Salomon4eda7102019-10-21 15:04:52 -0400135 auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, GrRenderable::kNo, origin,
136 bm.info(), bm.getPixels(), bm.rowBytes());
Robert Phillipsa0971732017-10-31 12:26:35 -0400137 if (!proxy) {
138 return nullptr;
139 }
140
Greg Daniel14b57212019-12-17 16:18:06 -0500141 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(),
Mike Klein42032cb2020-01-14 22:57:02 +0000142 GrColorType::kRGBA_8888);
Greg Daniel81b98972019-12-13 11:09:43 -0500143 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
Mike Klein42032cb2020-01-14 22:57:02 +0000144 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
145 std::move(view), nullptr);
Robert Phillipsa0971732017-10-31 12:26:35 -0400146}
147
148// Here we're converting from a matrix that is intended for UVs to a matrix that is intended
149// for rect geometry used for a drawImage call. They are, in some sense, inverses of each
150// other but we also need a scale to map from the [0..1] uv range to the actual size of
151// image.
152static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
Robert Phillips206bda52017-11-01 09:26:06 -0400153
154 const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
155
Robert Phillipsa0971732017-10-31 12:26:35 -0400156 SkMatrix tmp = uvMat;
Robert Phillips206bda52017-11-01 09:26:06 -0400157 tmp.preConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400158 tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
Robert Phillips206bda52017-11-01 09:26:06 -0400159
160 tmp.postConcat(yFlip);
Robert Phillipsa0971732017-10-31 12:26:35 -0400161 tmp.postScale(kImageSize, kImageSize);
162
163 return tmp.invert(geomMat);
164}
165
166// This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
167// rotates.
Chris Dalton3a778372019-02-07 15:23:36 -0700168class FlippityGM : public skiagm::GpuGM {
Robert Phillipsa0971732017-10-31 12:26:35 -0400169public:
170 FlippityGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400171 this->setBGColor(0xFFCCCCCC);
Robert Phillipsa0971732017-10-31 12:26:35 -0400172 }
173
Ben Wagnerc061d312019-08-14 15:31:52 -0400174private:
Robert Phillipsa0971732017-10-31 12:26:35 -0400175 SkString onShortName() override {
176 return SkString("flippity");
177 }
178
179 SkISize onISize() override {
180 return SkISize::Make(kGMWidth, kGMHeight);
181 }
182
183 // Draw the reference image and the four corner labels in the matrix's coordinate space
Robert Phillips206bda52017-11-01 09:26:06 -0400184 void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
185 bool drawSubset, bool drawScaled) {
186 static const SkRect kSubsets[kNumMatrices] = {
187 SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
188 SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
189 SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
190 SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
191 SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
192 SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
193 };
194
Robert Phillipsa0971732017-10-31 12:26:35 -0400195 SkMatrix imageGeomMat;
196 SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
197
198 canvas->save();
Robert Phillipsa0971732017-10-31 12:26:35 -0400199
200 // draw the reference image
Robert Phillips206bda52017-11-01 09:26:06 -0400201 canvas->concat(imageGeomMat);
202 if (drawSubset) {
203 canvas->drawImageRect(image, kSubsets[matIndex],
204 drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
205 : kSubsets[matIndex],
206 nullptr, SkCanvas::kFast_SrcRectConstraint);
207 } else {
208 canvas->drawImage(image, 0, 0);
209 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400210
211 // draw the labels
212 for (int i = 0; i < kNumLabels; ++i) {
213 canvas->drawImage(fLabels[i],
214 0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
215 0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
216 }
217 canvas->restore();
218 }
219
Robert Phillips206bda52017-11-01 09:26:06 -0400220 void drawRow(GrContext* context, SkCanvas* canvas,
221 bool bottomLeftImage, bool drawSubset, bool drawScaled) {
222
223 sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
224
225 canvas->save();
226 canvas->translate(kLabelSize, kLabelSize);
227
228 for (int i = 0; i < kNumMatrices; ++i) {
229 this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
230 drawSubset, drawScaled);
231 canvas->translate(kCellSize, 0);
232 }
233 canvas->restore();
234 }
235
Robert Phillipsa0971732017-10-31 12:26:35 -0400236 void makeLabels(GrContext* context) {
Ben Wagnerc061d312019-08-14 15:31:52 -0400237 if (fLabels.count()) {
238 return;
239 }
240
Robert Phillipsa0971732017-10-31 12:26:35 -0400241 static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
242
243 static const SkColor kLabelColors[kNumLabels] = {
244 SK_ColorRED,
245 SK_ColorGREEN,
246 SK_ColorBLUE,
247 SK_ColorCYAN
248 };
249
Robert Phillipsa0971732017-10-31 12:26:35 -0400250 for (int i = 0; i < kNumLabels; ++i) {
251 fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
252 }
253 SkASSERT(kNumLabels == fLabels.count());
254 }
255
Chris Dalton3a778372019-02-07 15:23:36 -0700256 void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
Robert Phillipsa0971732017-10-31 12:26:35 -0400257 this->makeLabels(context);
258
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400259 canvas->save();
260
Robert Phillipsa0971732017-10-31 12:26:35 -0400261 // Top row gets TL image
Robert Phillips206bda52017-11-01 09:26:06 -0400262 this->drawRow(context, canvas, false, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400263
Robert Phillips206bda52017-11-01 09:26:06 -0400264 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400265
266 // Bottom row gets BL image
Robert Phillips206bda52017-11-01 09:26:06 -0400267 this->drawRow(context, canvas, true, false, false);
Robert Phillipsa0971732017-10-31 12:26:35 -0400268
Robert Phillips206bda52017-11-01 09:26:06 -0400269 canvas->translate(0, kCellSize);
Robert Phillipsa0971732017-10-31 12:26:35 -0400270
Robert Phillips206bda52017-11-01 09:26:06 -0400271 // Third row gets subsets of BL images
272 this->drawRow(context, canvas, true, true, false);
273
274 canvas->translate(0, kCellSize);
275
276 // Fourth row gets scaled subsets of BL images
277 this->drawRow(context, canvas, true, true, true);
Robert Phillipsa0971732017-10-31 12:26:35 -0400278
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400279 canvas->restore();
280
Robert Phillipsa0971732017-10-31 12:26:35 -0400281 // separator grid
Robert Phillipsf0a30d72017-11-01 14:05:12 -0400282 for (int i = 0; i < 4; ++i) {
283 canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
284 }
Robert Phillipsa0971732017-10-31 12:26:35 -0400285 for (int i = 0; i < kNumMatrices; ++i) {
286 canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
287 }
288 }
289
290private:
291 SkTArray<sk_sp<SkImage>> fLabels;
292
293 typedef GM INHERITED;
294};
295
296DEF_GM(return new FlippityGM;)