1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2012 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/SkBitmap.h" 10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageFilter.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h" 22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h" 23*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h" 24*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkImageFilters.h" 25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BlurUtils.h" 26*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h" 27*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h" 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Worker #include <vector> 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm { 32*c8dee2aaSAndroid Build Coastguard Worker 33*c8dee2aaSAndroid Build Coastguard Worker enum KernelFixture { 34*c8dee2aaSAndroid Build Coastguard Worker kBasic_KernelFixture, 35*c8dee2aaSAndroid Build Coastguard Worker kLarge_KernelFixture, 36*c8dee2aaSAndroid Build Coastguard Worker kLarger_KernelFixture, 37*c8dee2aaSAndroid Build Coastguard Worker kLargest_KernelFixture, 38*c8dee2aaSAndroid Build Coastguard Worker }; 39*c8dee2aaSAndroid Build Coastguard Worker 40*c8dee2aaSAndroid Build Coastguard Worker class MatrixConvolutionGM : public GM { 41*c8dee2aaSAndroid Build Coastguard Worker public: MatrixConvolutionGM(SkColor colorOne,SkColor colorTwo,KernelFixture kernelFixture,const char * nameSuffix)42*c8dee2aaSAndroid Build Coastguard Worker MatrixConvolutionGM(SkColor colorOne, SkColor colorTwo, KernelFixture kernelFixture, const char* nameSuffix) 43*c8dee2aaSAndroid Build Coastguard Worker : fNameSuffix(nameSuffix), 44*c8dee2aaSAndroid Build Coastguard Worker fKernelFixture(kernelFixture) { 45*c8dee2aaSAndroid Build Coastguard Worker this->setBGColor(0x00000000); 46*c8dee2aaSAndroid Build Coastguard Worker fColors[0] = colorOne; 47*c8dee2aaSAndroid Build Coastguard Worker fColors[1] = colorTwo; 48*c8dee2aaSAndroid Build Coastguard Worker } 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Worker protected: runAsBench() const51*c8dee2aaSAndroid Build Coastguard Worker bool runAsBench() const override { return true; } 52*c8dee2aaSAndroid Build Coastguard Worker getName() const53*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkStringPrintf("matrixconvolution%s", fNameSuffix); } 54*c8dee2aaSAndroid Build Coastguard Worker makeBitmap()55*c8dee2aaSAndroid Build Coastguard Worker void makeBitmap() { 56*c8dee2aaSAndroid Build Coastguard Worker // Draw our bitmap in N32, so legacy devices get "premul" values they understand 57*c8dee2aaSAndroid Build Coastguard Worker auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(80, 80)); 58*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint; 59*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(0xFFFFFFFF); 60*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2] = { {0, 0}, 61*c8dee2aaSAndroid Build Coastguard Worker {0, 80.0f} }; 62*c8dee2aaSAndroid Build Coastguard Worker SkScalar pos[2] = { 0, 80.0f }; 63*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkGradientShader::MakeLinear( 64*c8dee2aaSAndroid Build Coastguard Worker pts, fColors, pos, 2, SkTileMode::kClamp)); 65*c8dee2aaSAndroid Build Coastguard Worker SkFont font(ToolUtils::DefaultPortableTypeface(), 180.0f); 66*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->drawString("e", -10.0f, 80.0f, font, paint); 67*c8dee2aaSAndroid Build Coastguard Worker fImage = surf->makeImageSnapshot(); 68*c8dee2aaSAndroid Build Coastguard Worker } 69*c8dee2aaSAndroid Build Coastguard Worker getISize()70*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(500, 300); } 71*c8dee2aaSAndroid Build Coastguard Worker makeFilter(const SkIPoint & kernelOffsetIn,SkTileMode tileMode,bool convolveAlpha)72*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> makeFilter(const SkIPoint &kernelOffsetIn, 73*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tileMode, 74*c8dee2aaSAndroid Build Coastguard Worker bool convolveAlpha) { 75*c8dee2aaSAndroid Build Coastguard Worker // The kernelOffset is specified in a 0..2 coordinate space. 76*c8dee2aaSAndroid Build Coastguard Worker float normalizedXOffset = kernelOffsetIn.fX / 2.0f; 77*c8dee2aaSAndroid Build Coastguard Worker float normalizedYOffset = kernelOffsetIn.fY / 2.0f; 78*c8dee2aaSAndroid Build Coastguard Worker // Must provide a cropping geometry in order for 'tileMode' to be well defined. 79*c8dee2aaSAndroid Build Coastguard Worker SkIRect tileBoundary = fImage->bounds(); 80*c8dee2aaSAndroid Build Coastguard Worker switch (fKernelFixture) { 81*c8dee2aaSAndroid Build Coastguard Worker case kBasic_KernelFixture: { 82*c8dee2aaSAndroid Build Coastguard Worker SkIPoint kernelOffset {SkScalarRoundToInt(2*normalizedXOffset), 83*c8dee2aaSAndroid Build Coastguard Worker SkScalarRoundToInt(2*normalizedYOffset)}; 84*c8dee2aaSAndroid Build Coastguard Worker // All 1s except center value, which is -7 (sum of 1). 85*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkScalar> kernel(9, SkIntToScalar(1)); 86*c8dee2aaSAndroid Build Coastguard Worker kernel[4] = SkIntToScalar(-7); 87*c8dee2aaSAndroid Build Coastguard Worker return SkImageFilters::MatrixConvolution( 88*c8dee2aaSAndroid Build Coastguard Worker {3,3}, kernel.data(), /* gain= */ 0.3f, /* bias= */ 100.0f, 89*c8dee2aaSAndroid Build Coastguard Worker kernelOffset, tileMode, convolveAlpha, nullptr, tileBoundary); 90*c8dee2aaSAndroid Build Coastguard Worker } 91*c8dee2aaSAndroid Build Coastguard Worker case kLarge_KernelFixture: { 92*c8dee2aaSAndroid Build Coastguard Worker SkIPoint kernelOffset {SkScalarRoundToInt(6*normalizedXOffset), 93*c8dee2aaSAndroid Build Coastguard Worker SkScalarRoundToInt(6*normalizedYOffset)}; 94*c8dee2aaSAndroid Build Coastguard Worker // This ensures the texture fallback path will be taken 95*c8dee2aaSAndroid Build Coastguard Worker static_assert(49 > skgpu::kMaxBlurSamples); 96*c8dee2aaSAndroid Build Coastguard Worker // All 1s except center value, which is -47 (sum of 1). 97*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkScalar> kernel(49, SkIntToScalar(1)); 98*c8dee2aaSAndroid Build Coastguard Worker kernel[24] = SkIntToScalar(-47); 99*c8dee2aaSAndroid Build Coastguard Worker return SkImageFilters::MatrixConvolution( 100*c8dee2aaSAndroid Build Coastguard Worker {7,7}, kernel.data(), /* gain= */ 0.3f, /* bias= */ 100.0f, 101*c8dee2aaSAndroid Build Coastguard Worker kernelOffset, tileMode, convolveAlpha, nullptr, tileBoundary); 102*c8dee2aaSAndroid Build Coastguard Worker } 103*c8dee2aaSAndroid Build Coastguard Worker case kLarger_KernelFixture: { 104*c8dee2aaSAndroid Build Coastguard Worker SkIPoint kernelOffset {SkScalarRoundToInt(127*normalizedXOffset), 0}; 105*c8dee2aaSAndroid Build Coastguard Worker // This ensures the texture fallback path will be taken 106*c8dee2aaSAndroid Build Coastguard Worker static_assert(128 > skgpu::kMaxBlurSamples); 107*c8dee2aaSAndroid Build Coastguard Worker std::vector<float> kernel(128, 0.0f); 108*c8dee2aaSAndroid Build Coastguard Worker kernel[64] = 0.5f; 109*c8dee2aaSAndroid Build Coastguard Worker kernel[65] = -0.5f; 110*c8dee2aaSAndroid Build Coastguard Worker return SkImageFilters::MatrixConvolution( 111*c8dee2aaSAndroid Build Coastguard Worker {128,1}, kernel.data(), /* gain= */ 0.3f, /* bias= */ 100.0f, 112*c8dee2aaSAndroid Build Coastguard Worker kernelOffset, tileMode, convolveAlpha, nullptr, tileBoundary); 113*c8dee2aaSAndroid Build Coastguard Worker } 114*c8dee2aaSAndroid Build Coastguard Worker case kLargest_KernelFixture: { 115*c8dee2aaSAndroid Build Coastguard Worker SkIPoint kernelOffset {0, SkScalarRoundToInt(254*normalizedYOffset)}; 116*c8dee2aaSAndroid Build Coastguard Worker // This ensures the texture fallback path will be taken 117*c8dee2aaSAndroid Build Coastguard Worker static_assert(255 > skgpu::kMaxBlurSamples); 118*c8dee2aaSAndroid Build Coastguard Worker std::vector<float> kernel(255, 0.0f); 119*c8dee2aaSAndroid Build Coastguard Worker kernel[126] = 0.5f; 120*c8dee2aaSAndroid Build Coastguard Worker kernel[128] = -0.5f; 121*c8dee2aaSAndroid Build Coastguard Worker return SkImageFilters::MatrixConvolution( 122*c8dee2aaSAndroid Build Coastguard Worker {1,255}, kernel.data(), /* gain= */ 0.3f, /* bias= */ 100.0f, 123*c8dee2aaSAndroid Build Coastguard Worker kernelOffset, tileMode, convolveAlpha, nullptr, tileBoundary); 124*c8dee2aaSAndroid Build Coastguard Worker } 125*c8dee2aaSAndroid Build Coastguard Worker default: 126*c8dee2aaSAndroid Build Coastguard Worker return nullptr; 127*c8dee2aaSAndroid Build Coastguard Worker } 128*c8dee2aaSAndroid Build Coastguard Worker } 129*c8dee2aaSAndroid Build Coastguard Worker draw(SkCanvas * canvas,int x,int y,const SkIPoint & kernelOffset,SkTileMode tileMode,bool convolveAlpha,const SkIRect * cropRect=nullptr)130*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas, int x, int y, const SkIPoint& kernelOffset, 131*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tileMode, bool convolveAlpha, 132*c8dee2aaSAndroid Build Coastguard Worker const SkIRect* cropRect = nullptr) { 133*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint; 134*c8dee2aaSAndroid Build Coastguard Worker auto filter = this->makeFilter(kernelOffset, tileMode, convolveAlpha); 135*c8dee2aaSAndroid Build Coastguard Worker if (cropRect) { 136*c8dee2aaSAndroid Build Coastguard Worker filter = SkImageFilters::Crop(SkRect::Make(*cropRect), std::move(filter)); 137*c8dee2aaSAndroid Build Coastguard Worker } 138*c8dee2aaSAndroid Build Coastguard Worker paint.setImageFilter(std::move(filter)); 139*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 140*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 141*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(fImage, 0, 0, {}, &paint); 142*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 143*c8dee2aaSAndroid Build Coastguard Worker } 144*c8dee2aaSAndroid Build Coastguard Worker onOnceBeforeDraw()145*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { 146*c8dee2aaSAndroid Build Coastguard Worker this->makeBitmap(); 147*c8dee2aaSAndroid Build Coastguard Worker } 148*c8dee2aaSAndroid Build Coastguard Worker onDraw(SkCanvas * canvas)149*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override { 150*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorBLACK); 151*c8dee2aaSAndroid Build Coastguard Worker SkIPoint kernelOffset = SkIPoint::Make(1, 0); 152*c8dee2aaSAndroid Build Coastguard Worker for (int x = 10; x < 310; x += 100) { 153*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, x, 10, kernelOffset, SkTileMode::kClamp, true); 154*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, x, 110, kernelOffset, SkTileMode::kDecal, true); 155*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, x, 210, kernelOffset, SkTileMode::kRepeat, true); 156*c8dee2aaSAndroid Build Coastguard Worker kernelOffset.fY++; 157*c8dee2aaSAndroid Build Coastguard Worker } 158*c8dee2aaSAndroid Build Coastguard Worker kernelOffset.fY = 1; 159*c8dee2aaSAndroid Build Coastguard Worker SkIRect smallRect = SkIRect::MakeXYWH(10, 5, 60, 60); 160*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, 310, 10, kernelOffset, SkTileMode::kClamp, true, &smallRect); 161*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, 310, 110, kernelOffset, SkTileMode::kDecal, true, &smallRect); 162*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, 310, 210, kernelOffset, SkTileMode::kRepeat, true, &smallRect); 163*c8dee2aaSAndroid Build Coastguard Worker 164*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, 410, 10, kernelOffset, SkTileMode::kClamp, false); 165*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, 410, 110, kernelOffset, SkTileMode::kDecal, false); 166*c8dee2aaSAndroid Build Coastguard Worker this->draw(canvas, 410, 210, kernelOffset, SkTileMode::kRepeat, false); 167*c8dee2aaSAndroid Build Coastguard Worker } 168*c8dee2aaSAndroid Build Coastguard Worker 169*c8dee2aaSAndroid Build Coastguard Worker private: 170*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImage; 171*c8dee2aaSAndroid Build Coastguard Worker SkColor fColors[2]; 172*c8dee2aaSAndroid Build Coastguard Worker const char* fNameSuffix; 173*c8dee2aaSAndroid Build Coastguard Worker KernelFixture fKernelFixture; 174*c8dee2aaSAndroid Build Coastguard Worker 175*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM; 176*c8dee2aaSAndroid Build Coastguard Worker }; 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 179*c8dee2aaSAndroid Build Coastguard Worker 180*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, KernelFixture::kBasic_KernelFixture, "");) 181*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MatrixConvolutionGM(0xFFFF0000, 0xFF00FF00, KernelFixture::kBasic_KernelFixture, "_color");) 182*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, KernelFixture::kLarge_KernelFixture, "_big");) 183*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MatrixConvolutionGM(0xFFFF0000, 0xFF00FF00, KernelFixture::kLarge_KernelFixture, "_big_color");) 184*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, KernelFixture::kLarger_KernelFixture, "_bigger");) 185*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, KernelFixture::kLargest_KernelFixture, "_biggest");) 186*c8dee2aaSAndroid Build Coastguard Worker 187*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiagm 188