xref: /aosp_15_r20/external/skia/gm/flippity.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
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/gm.h"
9 #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"
23 #include "include/core/SkSurface.h"
24 #include "include/core/SkTypeface.h"
25 #include "include/core/SkTypes.h"
26 #include "include/gpu/ganesh/GrDirectContext.h"
27 #include "include/gpu/ganesh/GrRecordingContext.h"
28 #include "include/gpu/ganesh/GrTypes.h"
29 #include "include/private/base/SkTArray.h"
30 #include "src/gpu/ganesh/GrDirectContextPriv.h"
31 #include "src/gpu/ganesh/GrPixmap.h"
32 #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
33 #include "src/image/SkImage_Base.h"
34 #include "tools/ToolUtils.h"
35 #include "tools/fonts/FontToolUtils.h"
36 #include "tools/gpu/ProxyUtils.h"
37 
38 #include <string.h>
39 #include <utility>
40 
41 using namespace skia_private;
42 
43 static const int kNumMatrices = 6;
44 static const int kImageSize = 128;
45 static const int kLabelSize = 32;
46 static const int kNumLabels = 4;
47 static const int kInset = 16;
48 
49 static const int kCellSize = kImageSize+2*kLabelSize;
50 static const int kGMWidth  = kNumMatrices*kCellSize;
51 static const int kGMHeight = 4*kCellSize;
52 
53 static const SkPoint kPoints[kNumLabels] = {
54     {          0, kImageSize },     // LL
55     { kImageSize, kImageSize },     // LR
56     {          0,          0 },     // UL
57     { kImageSize,          0 },     // UR
58 };
59 
60 static 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 
84 
85 // Create a fixed size text label like "LL" or "LR".
make_text_image(const char * text,SkColor color)86 static sk_sp<SkImage> make_text_image(const char* text, SkColor color) {
87     SkPaint paint;
88     paint.setAntiAlias(true);
89     paint.setColor(color);
90 
91     SkFont font = ToolUtils::DefaultPortableFont();
92     font.setEdging(SkFont::Edging::kAntiAlias);
93     font.setSize(32);
94 
95     SkRect bounds;
96     font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
97     const SkMatrix mat = SkMatrix::RectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize));
98 
99     const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
100     sk_sp<SkSurface> surf = SkSurfaces::Raster(ii);
101 
102     SkCanvas* canvas = surf->getCanvas();
103 
104     canvas->clear(SK_ColorWHITE);
105     canvas->concat(mat);
106     canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 0, 0, font, paint);
107 
108     return surf->makeImageSnapshot();
109 }
110 
111 // Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
112 // or top-left.
make_reference_image(SkCanvas * mainCanvas,const TArray<sk_sp<SkImage>> & labels,bool bottomLeftOrigin)113 static sk_sp<SkImage> make_reference_image(SkCanvas* mainCanvas,
114                                            const TArray<sk_sp<SkImage>>& labels,
115                                            bool bottomLeftOrigin) {
116     SkASSERT(kNumLabels == labels.size());
117 
118     SkImageInfo ii = SkImageInfo::Make(kImageSize, kImageSize,
119                                        kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
120     SkBitmap bm;
121     bm.allocPixels(ii);
122 
123     {
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();
134     }
135 
136     auto dContext = GrAsDirectContext(mainCanvas->recordingContext());
137     if (dContext && !dContext->abandoned()) {
138         auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
139 
140         auto view = sk_gpu_test::MakeTextureProxyViewFromData(dContext, GrRenderable::kNo, origin,
141                                                               bm.pixmap());
142         if (!view) {
143             return nullptr;
144         }
145 
146         return sk_make_sp<SkImage_Ganesh>(
147                 sk_ref_sp(dContext), kNeedNewImageUniqueID, std::move(view), ii.colorInfo());
148     }
149 
150     return SkImages::RasterFromBitmap(bm);
151 }
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.
UVMatToGeomMatForImage(SkMatrix * geomMat,const SkMatrix & uvMat)157 static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
158 
159     const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
160 
161     SkMatrix tmp = uvMat;
162     tmp.preConcat(yFlip);
163     tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
164 
165     tmp.postConcat(yFlip);
166     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.
173 class FlippityGM : public skiagm::GM {
174 public:
FlippityGM()175     FlippityGM() {
176         this->setBGColor(0xFFCCCCCC);
177     }
178 
179 private:
getName() const180     SkString getName() const override { return SkString("flippity"); }
181 
getISize()182     SkISize getISize() override { return SkISize::Make(kGMWidth, kGMHeight); }
183 
184     // Draw the reference image and the four corner labels in the matrix's coordinate space
drawImageWithMatrixAndLabels(SkCanvas * canvas,SkImage * image,int matIndex,bool drawSubset,bool drawScaled)185     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 
196         SkMatrix imageGeomMat;
197         SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
198 
199         canvas->save();
200 
201             // draw the reference image
202             canvas->concat(imageGeomMat);
203             if (drawSubset) {
204                 canvas->drawImageRect(image, kSubsets[matIndex],
205                                       drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
206                                                  : kSubsets[matIndex],
207                                       SkSamplingOptions(), nullptr,
208                                       SkCanvas::kFast_SrcRectConstraint);
209             } else {
210                 canvas->drawImage(image, 0, 0);
211             }
212 
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 
drawRow(SkCanvas * canvas,bool bottomLeftImage,bool drawSubset,bool drawScaled)222     void drawRow(SkCanvas* canvas, bool bottomLeftImage, bool drawSubset, bool drawScaled) {
223 
224         canvas->save();
225             canvas->translate(kLabelSize, kLabelSize);
226 
227             for (int i = 0; i < kNumMatrices; ++i) {
228                 this->drawImageWithMatrixAndLabels(canvas, fReferenceImages[bottomLeftImage].get(),
229                                                    i, drawSubset, drawScaled);
230                 canvas->translate(kCellSize, 0);
231             }
232         canvas->restore();
233     }
234 
makeLabels()235     void makeLabels() {
236         if (fLabels.size()) {
237             return;
238         }
239 
240         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 
249         for (int i = 0; i < kNumLabels; ++i) {
250             fLabels.push_back(make_text_image(kLabelText[i], kLabelColors[i]));
251         }
252         SkASSERT(kNumLabels == fLabels.size());
253     }
254 
onGpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext *)255     DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override {
256         this->makeLabels();
257         fReferenceImages[0] = make_reference_image(canvas, fLabels, false);
258         fReferenceImages[1] = make_reference_image(canvas, fLabels, true);
259         if (!fReferenceImages[0] || !fReferenceImages[1]) {
260             *errorMsg = "Failed to create reference images.";
261             return DrawResult::kFail;
262         }
263 
264         return DrawResult::kOk;
265     }
266 
onGpuTeardown()267     void onGpuTeardown() override {
268         fLabels.clear();
269         fReferenceImages[0] = fReferenceImages[1] = nullptr;
270     }
271 
onDraw(SkCanvas * canvas)272     void onDraw(SkCanvas* canvas) override {
273         SkASSERT(fReferenceImages[0] && fReferenceImages[1]);
274 
275         canvas->save();
276 
277         // Top row gets TL image
278         this->drawRow(canvas, false, false, false);
279 
280         canvas->translate(0, kCellSize);
281 
282         // Bottom row gets BL image
283         this->drawRow(canvas, true, false, false);
284 
285         canvas->translate(0, kCellSize);
286 
287         // Third row gets subsets of BL images
288         this->drawRow(canvas, true, true, false);
289 
290         canvas->translate(0, kCellSize);
291 
292         // Fourth row gets scaled subsets of BL images
293         this->drawRow(canvas, true, true, true);
294 
295         canvas->restore();
296 
297         // separator grid
298         for (int i = 0; i < 4; ++i) {
299             canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
300         }
301         for (int i = 0; i < kNumMatrices; ++i) {
302             canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
303         }
304     }
305 
306 private:
307     TArray<sk_sp<SkImage>> fLabels;
308     sk_sp<SkImage> fReferenceImages[2];
309 
310     using INHERITED = GM;
311 };
312 
313 DEF_GM(return new FlippityGM;)
314