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