xref: /aosp_15_r20/external/skia/gm/anisotropic.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker // This GM exercises anisotropic image scaling.
26*c8dee2aaSAndroid Build Coastguard Worker class AnisotropicGM : public GM {
27*c8dee2aaSAndroid Build Coastguard Worker public:
28*c8dee2aaSAndroid Build Coastguard Worker     enum class Mode { kLinear, kMip, kAniso };
29*c8dee2aaSAndroid Build Coastguard Worker 
AnisotropicGM(Mode mode)30*c8dee2aaSAndroid Build Coastguard Worker     AnisotropicGM(Mode mode) : fMode(mode) {
31*c8dee2aaSAndroid Build Coastguard Worker         switch (fMode) {
32*c8dee2aaSAndroid Build Coastguard Worker             case Mode::kLinear:
33*c8dee2aaSAndroid Build Coastguard Worker                 fSampling = SkSamplingOptions(SkFilterMode::kLinear);
34*c8dee2aaSAndroid Build Coastguard Worker                 break;
35*c8dee2aaSAndroid Build Coastguard Worker             case Mode::kMip:
36*c8dee2aaSAndroid Build Coastguard Worker                 fSampling = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
37*c8dee2aaSAndroid Build Coastguard Worker                 break;
38*c8dee2aaSAndroid Build Coastguard Worker             case Mode::kAniso:
39*c8dee2aaSAndroid Build Coastguard Worker                 fSampling = SkSamplingOptions::Aniso(16);
40*c8dee2aaSAndroid Build Coastguard Worker                 break;
41*c8dee2aaSAndroid Build Coastguard Worker         }
42*c8dee2aaSAndroid Build Coastguard Worker         this->setBGColor(0xFFCCCCCC);
43*c8dee2aaSAndroid Build Coastguard Worker     }
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const46*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override {
47*c8dee2aaSAndroid Build Coastguard Worker         SkString name("anisotropic_image_scale_");
48*c8dee2aaSAndroid Build Coastguard Worker         switch (fMode) {
49*c8dee2aaSAndroid Build Coastguard Worker             case Mode::kLinear:
50*c8dee2aaSAndroid Build Coastguard Worker                 name += "linear";
51*c8dee2aaSAndroid Build Coastguard Worker                 break;
52*c8dee2aaSAndroid Build Coastguard Worker             case Mode::kMip:
53*c8dee2aaSAndroid Build Coastguard Worker                 name += "mip";
54*c8dee2aaSAndroid Build Coastguard Worker                 break;
55*c8dee2aaSAndroid Build Coastguard Worker             case Mode::kAniso:
56*c8dee2aaSAndroid Build Coastguard Worker                 name += "aniso";
57*c8dee2aaSAndroid Build Coastguard Worker                 break;
58*c8dee2aaSAndroid Build Coastguard Worker         }
59*c8dee2aaSAndroid Build Coastguard Worker         return name;
60*c8dee2aaSAndroid Build Coastguard Worker     }
61*c8dee2aaSAndroid Build Coastguard Worker 
getISize()62*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override {
63*c8dee2aaSAndroid Build Coastguard Worker         return SkISize::Make(2*kImageSize + 3*kSpacer,
64*c8dee2aaSAndroid Build Coastguard Worker                              kNumVertImages*kImageSize + (kNumVertImages+1)*kSpacer);
65*c8dee2aaSAndroid Build Coastguard Worker     }
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     // Create an image consisting of lines radiating from its center
onOnceBeforeDraw()68*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
69*c8dee2aaSAndroid Build Coastguard Worker         constexpr int kNumLines = 100;
70*c8dee2aaSAndroid Build Coastguard Worker         constexpr SkScalar kAngleStep = 360.0f / kNumLines;
71*c8dee2aaSAndroid Build Coastguard Worker         constexpr int kInnerOffset = 10;
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker         auto info = SkImageInfo::MakeN32(kImageSize, kImageSize, kOpaque_SkAlphaType);
74*c8dee2aaSAndroid Build Coastguard Worker         auto surf = SkSurfaces::Raster(info);
75*c8dee2aaSAndroid Build Coastguard Worker         auto canvas = surf->getCanvas();
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker         canvas->clear(SK_ColorWHITE);
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker         SkPaint p;
80*c8dee2aaSAndroid Build Coastguard Worker         p.setAntiAlias(true);
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker         SkScalar angle = 0.0f, sin, cos;
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(kImageSize/2.0f, kImageSize/2.0f);
85*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < kNumLines; ++i, angle += kAngleStep) {
86*c8dee2aaSAndroid Build Coastguard Worker             sin = SkScalarSin(angle);
87*c8dee2aaSAndroid Build Coastguard Worker             cos = SkScalarCos(angle);
88*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawLine(cos * kInnerOffset, sin * kInnerOffset,
89*c8dee2aaSAndroid Build Coastguard Worker                              cos * kImageSize/2, sin * kImageSize/2, p);
90*c8dee2aaSAndroid Build Coastguard Worker         }
91*c8dee2aaSAndroid Build Coastguard Worker         fImage = surf->makeImageSnapshot();
92*c8dee2aaSAndroid Build Coastguard Worker     }
93*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas,int x,int y,int xSize,int ySize)94*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas, int x, int y, int xSize, int ySize) {
95*c8dee2aaSAndroid Build Coastguard Worker         SkRect r = SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
96*c8dee2aaSAndroid Build Coastguard Worker                                     SkIntToScalar(xSize), SkIntToScalar(ySize));
97*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawImageRect(fImage, r, fSampling);
98*c8dee2aaSAndroid Build Coastguard Worker     }
99*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)100*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
101*c8dee2aaSAndroid Build Coastguard Worker         SkScalar gScales[] = { 0.9f, 0.8f, 0.75f, 0.6f, 0.5f, 0.4f, 0.25f, 0.2f, 0.1f };
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(kNumVertImages-1 == (int)std::size(gScales)/2);
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker         // Minimize vertically
106*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < (int)std::size(gScales); ++i) {
107*c8dee2aaSAndroid Build Coastguard Worker             int height = SkScalarFloorToInt(fImage->height() * gScales[i]);
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker             int yOff;
110*c8dee2aaSAndroid Build Coastguard Worker             if (i <= (int)std::size(gScales)/2) {
111*c8dee2aaSAndroid Build Coastguard Worker                 yOff = kSpacer + i * (fImage->height() + kSpacer);
112*c8dee2aaSAndroid Build Coastguard Worker             } else {
113*c8dee2aaSAndroid Build Coastguard Worker                 // Position the more highly squashed images with their less squashed counterparts
114*c8dee2aaSAndroid Build Coastguard Worker                 yOff = (std::size(gScales) - i) * (fImage->height() + kSpacer) - height;
115*c8dee2aaSAndroid Build Coastguard Worker             }
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker             this->draw(canvas, kSpacer, yOff, fImage->width(), height);
118*c8dee2aaSAndroid Build Coastguard Worker         }
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker         // Minimize horizontally
121*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < (int)std::size(gScales); ++i) {
122*c8dee2aaSAndroid Build Coastguard Worker             int width = SkScalarFloorToInt(fImage->width() * gScales[i]);
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker             int xOff, yOff;
125*c8dee2aaSAndroid Build Coastguard Worker             if (i <= (int)std::size(gScales)/2) {
126*c8dee2aaSAndroid Build Coastguard Worker                 xOff = fImage->width() + 2*kSpacer;
127*c8dee2aaSAndroid Build Coastguard Worker                 yOff = kSpacer + i * (fImage->height() + kSpacer);
128*c8dee2aaSAndroid Build Coastguard Worker             } else {
129*c8dee2aaSAndroid Build Coastguard Worker                 // Position the more highly squashed images with their less squashed counterparts
130*c8dee2aaSAndroid Build Coastguard Worker                 xOff = fImage->width() + 2*kSpacer + fImage->width() - width;
131*c8dee2aaSAndroid Build Coastguard Worker                 yOff = kSpacer + (std::size(gScales) - i - 1) * (fImage->height() + kSpacer);
132*c8dee2aaSAndroid Build Coastguard Worker             }
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker             this->draw(canvas, xOff, yOff, width, fImage->height());
135*c8dee2aaSAndroid Build Coastguard Worker         }
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker private:
139*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kImageSize     = 256;
140*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kSpacer        = 10;
141*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kNumVertImages = 5;
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage>    fImage;
144*c8dee2aaSAndroid Build Coastguard Worker     SkSamplingOptions fSampling;
145*c8dee2aaSAndroid Build Coastguard Worker     Mode              fMode;
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GM;
148*c8dee2aaSAndroid Build Coastguard Worker };
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
151*c8dee2aaSAndroid Build Coastguard Worker 
152*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kLinear);)
153*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kMip);)
154*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kAniso);)
155*c8dee2aaSAndroid Build Coastguard Worker 
156*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker class AnisoMipsGM : public GM {
159*c8dee2aaSAndroid Build Coastguard Worker public:
160*c8dee2aaSAndroid Build Coastguard Worker     AnisoMipsGM() = default;
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const163*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("anisomips"); }
164*c8dee2aaSAndroid Build Coastguard Worker 
getISize()165*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(520, 260); }
166*c8dee2aaSAndroid Build Coastguard Worker 
updateImage(SkSurface * surf,SkColor color)167*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> updateImage(SkSurface* surf, SkColor color) {
168*c8dee2aaSAndroid Build Coastguard Worker         surf->getCanvas()->clear(color);
169*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
170*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(~color | 0xFF000000);
171*c8dee2aaSAndroid Build Coastguard Worker         surf->getCanvas()->drawRect(SkRect::MakeLTRB(surf->width() *2/5.f,
172*c8dee2aaSAndroid Build Coastguard Worker                                                      surf->height()*2/5.f,
173*c8dee2aaSAndroid Build Coastguard Worker                                                      surf->width() *3/5.f,
174*c8dee2aaSAndroid Build Coastguard Worker                                                      surf->height()*3/5.f),
175*c8dee2aaSAndroid Build Coastguard Worker                                     paint);
176*c8dee2aaSAndroid Build Coastguard Worker         return surf->makeImageSnapshot()->withDefaultMipmaps();
177*c8dee2aaSAndroid Build Coastguard Worker     }
178*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)179*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
180*c8dee2aaSAndroid Build Coastguard Worker         auto ct = canvas->imageInfo().colorType() == kUnknown_SkColorType
181*c8dee2aaSAndroid Build Coastguard Worker                           ? kRGBA_8888_SkColorType
182*c8dee2aaSAndroid Build Coastguard Worker                           : canvas->imageInfo().colorType();
183*c8dee2aaSAndroid Build Coastguard Worker         auto ii = SkImageInfo::Make(kImageSize,
184*c8dee2aaSAndroid Build Coastguard Worker                                     kImageSize,
185*c8dee2aaSAndroid Build Coastguard Worker                                     ct,
186*c8dee2aaSAndroid Build Coastguard Worker                                     kPremul_SkAlphaType,
187*c8dee2aaSAndroid Build Coastguard Worker                                     canvas->imageInfo().refColorSpace());
188*c8dee2aaSAndroid Build Coastguard Worker         // In GPU mode we want a surface that is created with mipmaps to ensure that we exercise the
189*c8dee2aaSAndroid Build Coastguard Worker         // case where the SkSurface and SkImage share a texture. If the surface texture isn't
190*c8dee2aaSAndroid Build Coastguard Worker         // created with MIPs then asking for a mipmapped image will cause a copy to a mipped
191*c8dee2aaSAndroid Build Coastguard Worker         // texture.
192*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkSurface> surface;
193*c8dee2aaSAndroid Build Coastguard Worker         if (auto rc = canvas->recordingContext()) {
194*c8dee2aaSAndroid Build Coastguard Worker             surface = SkSurfaces::RenderTarget(rc,
195*c8dee2aaSAndroid Build Coastguard Worker                                                skgpu::Budgeted::kYes,
196*c8dee2aaSAndroid Build Coastguard Worker                                                ii,
197*c8dee2aaSAndroid Build Coastguard Worker                                                /* sampleCount= */ 1,
198*c8dee2aaSAndroid Build Coastguard Worker                                                kTopLeft_GrSurfaceOrigin,
199*c8dee2aaSAndroid Build Coastguard Worker                                                /*surfaceProps=*/nullptr,
200*c8dee2aaSAndroid Build Coastguard Worker                                                /*shouldCreateWithMips=*/true);
201*c8dee2aaSAndroid Build Coastguard Worker             if (!surface) {
202*c8dee2aaSAndroid Build Coastguard Worker                 // We could be in an abandoned context situation.
203*c8dee2aaSAndroid Build Coastguard Worker                 return;
204*c8dee2aaSAndroid Build Coastguard Worker             }
205*c8dee2aaSAndroid Build Coastguard Worker         } else {
206*c8dee2aaSAndroid Build Coastguard Worker             surface = canvas->makeSurface(ii);
207*c8dee2aaSAndroid Build Coastguard Worker             if (!surface) {  // could be a recording canvas.
208*c8dee2aaSAndroid Build Coastguard Worker                 surface = SkSurfaces::Raster(ii);
209*c8dee2aaSAndroid Build Coastguard Worker             }
210*c8dee2aaSAndroid Build Coastguard Worker         }
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker         static constexpr float kScales[] = {1.f, 0.5f, 0.25f, 0.125f};
213*c8dee2aaSAndroid Build Coastguard Worker         SkColor kColors[] = {0xFFF0F0F0, SK_ColorBLUE, SK_ColorGREEN, SK_ColorRED};
214*c8dee2aaSAndroid Build Coastguard Worker         static const SkSamplingOptions kSampling = SkSamplingOptions::Aniso(16);
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker         for (bool shader : {false, true}) {
217*c8dee2aaSAndroid Build Coastguard Worker             int c = 0;
218*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
219*c8dee2aaSAndroid Build Coastguard Worker             for (float sy : kScales) {
220*c8dee2aaSAndroid Build Coastguard Worker                 canvas->save();
221*c8dee2aaSAndroid Build Coastguard Worker                 for (float sx : kScales) {
222*c8dee2aaSAndroid Build Coastguard Worker                     canvas->save();
223*c8dee2aaSAndroid Build Coastguard Worker                     canvas->scale(sx, sy);
224*c8dee2aaSAndroid Build Coastguard Worker                     auto image = this->updateImage(surface.get(), kColors[c]);
225*c8dee2aaSAndroid Build Coastguard Worker                     if (shader) {
226*c8dee2aaSAndroid Build Coastguard Worker                         SkPaint paint;
227*c8dee2aaSAndroid Build Coastguard Worker                         paint.setShader(image->makeShader(kSampling));
228*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawRect(SkRect::Make(image->dimensions()), paint);
229*c8dee2aaSAndroid Build Coastguard Worker                     } else {
230*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawImage(image, 0, 0, kSampling);
231*c8dee2aaSAndroid Build Coastguard Worker                     }
232*c8dee2aaSAndroid Build Coastguard Worker                     canvas->restore();
233*c8dee2aaSAndroid Build Coastguard Worker                     canvas->translate(ii.width() * sx + kPad, 0);
234*c8dee2aaSAndroid Build Coastguard Worker                     c = (c + 1) % std::size(kColors);
235*c8dee2aaSAndroid Build Coastguard Worker                 }
236*c8dee2aaSAndroid Build Coastguard Worker                 canvas->restore();
237*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(0, ii.width() * sy + kPad);
238*c8dee2aaSAndroid Build Coastguard Worker             }
239*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
240*c8dee2aaSAndroid Build Coastguard Worker             for (float sx : kScales) {
241*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(ii.width() * sx + kPad, 0);
242*c8dee2aaSAndroid Build Coastguard Worker             }
243*c8dee2aaSAndroid Build Coastguard Worker         }
244*c8dee2aaSAndroid Build Coastguard Worker     }
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker private:
247*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kImageSize = 128;
248*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kPad = 5;
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GM;
251*c8dee2aaSAndroid Build Coastguard Worker };
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnisoMipsGM();)
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
258