blob: d038c266f2e4498fb49483e49fe305bc653e2855 [file] [log] [blame]
robertphillipsf5ac9722015-04-14 08:19:01 -07001/*
2 * Copyright 2015 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 Wagnerd1701ba2019-04-30 13:44:26 -04009#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
Brian Salomonc8ee7b12022-04-29 13:10:33 -040011#include "include/core/SkColorSpace.h"
Mike Reed6dbeac52021-01-13 13:14:23 -050012#include "include/core/SkImage.h"
Ben Wagnerd1701ba2019-04-30 13:44:26 -040013#include "include/core/SkPaint.h"
14#include "include/core/SkRect.h"
15#include "include/core/SkScalar.h"
Kevin Lubick08fc9882023-01-30 16:05:54 -050016#include "include/core/SkShader.h"
Ben Wagnerd1701ba2019-04-30 13:44:26 -040017#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
Mike Reed18aeb572021-01-19 17:58:25 -050019#include "include/core/SkSurface.h"
Kevin Lubick77472bf2023-03-24 07:11:17 -040020#include "include/gpu/GpuTypes.h"
Kevin Lubick5c93acf2023-05-09 12:11:43 -040021#include "include/gpu/ganesh/SkSurfaceGanesh.h"
robertphillipsf5ac9722015-04-14 08:19:01 -070022
23namespace skiagm {
24
Brian Salomon6538e892022-03-21 12:13:55 -040025// This GM exercises anisotropic image scaling.
robertphillipsf5ac9722015-04-14 08:19:01 -070026class AnisotropicGM : public GM {
27public:
Brian Salomonc8ee7b12022-04-29 13:10:33 -040028 enum class Mode { kLinear, kMip, kAniso };
29
30 AnisotropicGM(Mode mode) : fMode(mode) {
31 switch (fMode) {
32 case Mode::kLinear:
33 fSampling = SkSamplingOptions(SkFilterMode::kLinear);
34 break;
35 case Mode::kMip:
36 fSampling = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
37 break;
38 case Mode::kAniso:
39 fSampling = SkSamplingOptions::Aniso(16);
40 break;
41 }
Mike Kleind46dce32018-08-16 10:17:03 -040042 this->setBGColor(0xFFCCCCCC);
robertphillipsf5ac9722015-04-14 08:19:01 -070043 }
44
45protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +000046 SkString getName() const override {
Brian Salomonc8ee7b12022-04-29 13:10:33 -040047 SkString name("anisotropic_image_scale_");
48 switch (fMode) {
49 case Mode::kLinear:
50 name += "linear";
51 break;
52 case Mode::kMip:
53 name += "mip";
54 break;
55 case Mode::kAniso:
56 name += "aniso";
57 break;
58 }
59 return name;
60 }
robertphillipsf5ac9722015-04-14 08:19:01 -070061
Leandro Lovisolo8f023882023-08-15 21:13:52 +000062 SkISize getISize() override {
robertphillipsf5ac9722015-04-14 08:19:01 -070063 return SkISize::Make(2*kImageSize + 3*kSpacer,
64 kNumVertImages*kImageSize + (kNumVertImages+1)*kSpacer);
65 }
66
67 // Create an image consisting of lines radiating from its center
68 void onOnceBeforeDraw() override {
mtkleindbfd7ab2016-09-01 11:24:54 -070069 constexpr int kNumLines = 100;
70 constexpr SkScalar kAngleStep = 360.0f / kNumLines;
71 constexpr int kInnerOffset = 10;
robertphillipsf5ac9722015-04-14 08:19:01 -070072
Mike Reed18aeb572021-01-19 17:58:25 -050073 auto info = SkImageInfo::MakeN32(kImageSize, kImageSize, kOpaque_SkAlphaType);
Kevin Lubick5c93acf2023-05-09 12:11:43 -040074 auto surf = SkSurfaces::Raster(info);
Mike Reed18aeb572021-01-19 17:58:25 -050075 auto canvas = surf->getCanvas();
robertphillipsf5ac9722015-04-14 08:19:01 -070076
Mike Reed18aeb572021-01-19 17:58:25 -050077 canvas->clear(SK_ColorWHITE);
robertphillipsf5ac9722015-04-14 08:19:01 -070078
79 SkPaint p;
80 p.setAntiAlias(true);
81
82 SkScalar angle = 0.0f, sin, cos;
83
Mike Reed18aeb572021-01-19 17:58:25 -050084 canvas->translate(kImageSize/2.0f, kImageSize/2.0f);
robertphillipsf5ac9722015-04-14 08:19:01 -070085 for (int i = 0; i < kNumLines; ++i, angle += kAngleStep) {
Brian Osman4428f2c2019-04-02 10:59:28 -040086 sin = SkScalarSin(angle);
87 cos = SkScalarCos(angle);
Mike Reed18aeb572021-01-19 17:58:25 -050088 canvas->drawLine(cos * kInnerOffset, sin * kInnerOffset,
89 cos * kImageSize/2, sin * kImageSize/2, p);
robertphillipsf5ac9722015-04-14 08:19:01 -070090 }
Mike Reed18aeb572021-01-19 17:58:25 -050091 fImage = surf->makeImageSnapshot();
robertphillipsf5ac9722015-04-14 08:19:01 -070092 }
93
94 void draw(SkCanvas* canvas, int x, int y, int xSize, int ySize) {
95 SkRect r = SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
96 SkIntToScalar(xSize), SkIntToScalar(ySize));
Mike Reed34c56a52021-01-22 15:26:41 -050097 canvas->drawImageRect(fImage, r, fSampling);
robertphillipsf5ac9722015-04-14 08:19:01 -070098 }
99
100 void onDraw(SkCanvas* canvas) override {
101 SkScalar gScales[] = { 0.9f, 0.8f, 0.75f, 0.6f, 0.5f, 0.4f, 0.25f, 0.2f, 0.1f };
halcanary9d524f22016-03-29 09:03:52 -0700102
Herb Derbyc37b3862022-06-21 09:49:17 -0400103 SkASSERT(kNumVertImages-1 == (int)std::size(gScales)/2);
robertphillipsf5ac9722015-04-14 08:19:01 -0700104
105 // Minimize vertically
Herb Derbyc37b3862022-06-21 09:49:17 -0400106 for (int i = 0; i < (int)std::size(gScales); ++i) {
Mike Reed18aeb572021-01-19 17:58:25 -0500107 int height = SkScalarFloorToInt(fImage->height() * gScales[i]);
robertphillipsf5ac9722015-04-14 08:19:01 -0700108
109 int yOff;
Herb Derbyc37b3862022-06-21 09:49:17 -0400110 if (i <= (int)std::size(gScales)/2) {
Mike Reed18aeb572021-01-19 17:58:25 -0500111 yOff = kSpacer + i * (fImage->height() + kSpacer);
robertphillipsf5ac9722015-04-14 08:19:01 -0700112 } else {
113 // Position the more highly squashed images with their less squashed counterparts
Herb Derbyc37b3862022-06-21 09:49:17 -0400114 yOff = (std::size(gScales) - i) * (fImage->height() + kSpacer) - height;
robertphillipsf5ac9722015-04-14 08:19:01 -0700115 }
116
Mike Reed18aeb572021-01-19 17:58:25 -0500117 this->draw(canvas, kSpacer, yOff, fImage->width(), height);
robertphillipsf5ac9722015-04-14 08:19:01 -0700118 }
119
120 // Minimize horizontally
Herb Derbyc37b3862022-06-21 09:49:17 -0400121 for (int i = 0; i < (int)std::size(gScales); ++i) {
Mike Reed18aeb572021-01-19 17:58:25 -0500122 int width = SkScalarFloorToInt(fImage->width() * gScales[i]);
robertphillipsf5ac9722015-04-14 08:19:01 -0700123
124 int xOff, yOff;
Herb Derbyc37b3862022-06-21 09:49:17 -0400125 if (i <= (int)std::size(gScales)/2) {
Mike Reed18aeb572021-01-19 17:58:25 -0500126 xOff = fImage->width() + 2*kSpacer;
127 yOff = kSpacer + i * (fImage->height() + kSpacer);
robertphillipsf5ac9722015-04-14 08:19:01 -0700128 } else {
129 // Position the more highly squashed images with their less squashed counterparts
Mike Reed18aeb572021-01-19 17:58:25 -0500130 xOff = fImage->width() + 2*kSpacer + fImage->width() - width;
Herb Derbyc37b3862022-06-21 09:49:17 -0400131 yOff = kSpacer + (std::size(gScales) - i - 1) * (fImage->height() + kSpacer);
robertphillipsf5ac9722015-04-14 08:19:01 -0700132 }
133
Mike Reed18aeb572021-01-19 17:58:25 -0500134 this->draw(canvas, xOff, yOff, width, fImage->height());
robertphillipsf5ac9722015-04-14 08:19:01 -0700135 }
136 }
137
138private:
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400139 inline static constexpr int kImageSize = 256;
140 inline static constexpr int kSpacer = 10;
141 inline static constexpr int kNumVertImages = 5;
robertphillipsf5ac9722015-04-14 08:19:01 -0700142
Mike Reed18aeb572021-01-19 17:58:25 -0500143 sk_sp<SkImage> fImage;
144 SkSamplingOptions fSampling;
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400145 Mode fMode;
robertphillipsf5ac9722015-04-14 08:19:01 -0700146
John Stiles7571f9e2020-09-02 22:42:33 -0400147 using INHERITED = GM;
robertphillipsf5ac9722015-04-14 08:19:01 -0700148};
149
150//////////////////////////////////////////////////////////////////////////////
151
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400152DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kLinear);)
153DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kMip);)
154DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kAniso);)
155
156//////////////////////////////////////////////////////////////////////////////
157
158class AnisoMipsGM : public GM {
159public:
160 AnisoMipsGM() = default;
161
162protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000163 SkString getName() const override { return SkString("anisomips"); }
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400164
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000165 SkISize getISize() override { return SkISize::Make(520, 260); }
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400166
167 sk_sp<SkImage> updateImage(SkSurface* surf, SkColor color) {
168 surf->getCanvas()->clear(color);
169 SkPaint paint;
170 paint.setColor(~color | 0xFF000000);
171 surf->getCanvas()->drawRect(SkRect::MakeLTRB(surf->width() *2/5.f,
172 surf->height()*2/5.f,
173 surf->width() *3/5.f,
174 surf->height()*3/5.f),
175 paint);
176 return surf->makeImageSnapshot()->withDefaultMipmaps();
177 }
178
179 void onDraw(SkCanvas* canvas) override {
180 auto ct = canvas->imageInfo().colorType() == kUnknown_SkColorType
Brian Osman3f4ceac2022-10-28 15:09:34 +0000181 ? kRGBA_8888_SkColorType
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400182 : canvas->imageInfo().colorType();
183 auto ii = SkImageInfo::Make(kImageSize,
184 kImageSize,
185 ct,
186 kPremul_SkAlphaType,
187 canvas->imageInfo().refColorSpace());
188 // In GPU mode we want a surface that is created with mipmaps to ensure that we exercise the
189 // case where the SkSurface and SkImage share a texture. If the surface texture isn't
190 // created with MIPs then asking for a mipmapped image will cause a copy to a mipped
191 // texture.
192 sk_sp<SkSurface> surface;
193 if (auto rc = canvas->recordingContext()) {
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400194 surface = SkSurfaces::RenderTarget(rc,
195 skgpu::Budgeted::kYes,
196 ii,
Robert Phillipsaddbff52023-08-03 15:48:53 -0400197 /* sampleCount= */ 1,
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400198 kTopLeft_GrSurfaceOrigin,
199 /*surfaceProps=*/nullptr,
200 /*shouldCreateWithMips=*/true);
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400201 if (!surface) {
202 // We could be in an abandoned context situation.
203 return;
204 }
205 } else {
206 surface = canvas->makeSurface(ii);
207 if (!surface) { // could be a recording canvas.
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400208 surface = SkSurfaces::Raster(ii);
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400209 }
210 }
211
212 static constexpr float kScales[] = {1.f, 0.5f, 0.25f, 0.125f};
213 SkColor kColors[] = {0xFFF0F0F0, SK_ColorBLUE, SK_ColorGREEN, SK_ColorRED};
214 static const SkSamplingOptions kSampling = SkSamplingOptions::Aniso(16);
215
216 for (bool shader : {false, true}) {
217 int c = 0;
218 canvas->save();
219 for (float sy : kScales) {
220 canvas->save();
221 for (float sx : kScales) {
222 canvas->save();
223 canvas->scale(sx, sy);
224 auto image = this->updateImage(surface.get(), kColors[c]);
225 if (shader) {
226 SkPaint paint;
227 paint.setShader(image->makeShader(kSampling));
228 canvas->drawRect(SkRect::Make(image->dimensions()), paint);
229 } else {
230 canvas->drawImage(image, 0, 0, kSampling);
231 }
232 canvas->restore();
233 canvas->translate(ii.width() * sx + kPad, 0);
Herb Derbyc37b3862022-06-21 09:49:17 -0400234 c = (c + 1) % std::size(kColors);
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400235 }
236 canvas->restore();
237 canvas->translate(0, ii.width() * sy + kPad);
238 }
239 canvas->restore();
240 for (float sx : kScales) {
241 canvas->translate(ii.width() * sx + kPad, 0);
242 }
243 }
244 }
245
246private:
247 inline static constexpr int kImageSize = 128;
248 inline static constexpr int kPad = 5;
249
250 using INHERITED = GM;
251};
252
253//////////////////////////////////////////////////////////////////////////////
254
255DEF_GM(return new AnisoMipsGM();)
256
John Stilesa6841be2020-08-06 14:11:56 -0400257} // namespace skiagm