1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 Google LLC. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "gm/gm.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h" 11cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 12cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h" 13cb93a386Sopenharmony_ci#include "src/core/SkGpuBlurUtils.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 16cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 17cb93a386Sopenharmony_ci#include "src/gpu/effects/GrBlendFragmentProcessor.h" 18cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 19cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 20cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_cinamespace { 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_cistatic GrSurfaceProxyView blur(GrRecordingContext* ctx, 25cb93a386Sopenharmony_ci GrSurfaceProxyView src, 26cb93a386Sopenharmony_ci SkIRect dstB, 27cb93a386Sopenharmony_ci SkIRect srcB, 28cb93a386Sopenharmony_ci float sigmaX, 29cb93a386Sopenharmony_ci float sigmaY, 30cb93a386Sopenharmony_ci SkTileMode mode) { 31cb93a386Sopenharmony_ci auto resultSDC = SkGpuBlurUtils::GaussianBlur(ctx, 32cb93a386Sopenharmony_ci src, 33cb93a386Sopenharmony_ci GrColorType::kRGBA_8888, 34cb93a386Sopenharmony_ci kPremul_SkAlphaType, 35cb93a386Sopenharmony_ci nullptr, 36cb93a386Sopenharmony_ci dstB, 37cb93a386Sopenharmony_ci srcB, 38cb93a386Sopenharmony_ci sigmaX, 39cb93a386Sopenharmony_ci sigmaY, 40cb93a386Sopenharmony_ci mode); 41cb93a386Sopenharmony_ci if (!resultSDC) { 42cb93a386Sopenharmony_ci return {}; 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci return resultSDC->readSurfaceView(); 45cb93a386Sopenharmony_ci}; 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci// Performs tiling first of the src into dst bounds with a surrounding skirt so the blur can use 48cb93a386Sopenharmony_ci// clamp. Does repeated blurs rather than invoking downsampling. 49cb93a386Sopenharmony_cistatic GrSurfaceProxyView slow_blur(GrRecordingContext* rContext, 50cb93a386Sopenharmony_ci GrSurfaceProxyView src, 51cb93a386Sopenharmony_ci SkIRect dstB, 52cb93a386Sopenharmony_ci SkIRect srcB, 53cb93a386Sopenharmony_ci float sigmaX, 54cb93a386Sopenharmony_ci float sigmaY, 55cb93a386Sopenharmony_ci SkTileMode mode) { 56cb93a386Sopenharmony_ci auto tileInto = [rContext](GrSurfaceProxyView src, 57cb93a386Sopenharmony_ci SkIRect srcTileRect, 58cb93a386Sopenharmony_ci SkISize resultSize, 59cb93a386Sopenharmony_ci SkIPoint offset, 60cb93a386Sopenharmony_ci SkTileMode mode) { 61cb93a386Sopenharmony_ci GrImageInfo info(GrColorType::kRGBA_8888, kPremul_SkAlphaType, nullptr, resultSize); 62cb93a386Sopenharmony_ci auto sfc = rContext->priv().makeSFC(info); 63cb93a386Sopenharmony_ci if (!sfc) { 64cb93a386Sopenharmony_ci return GrSurfaceProxyView{}; 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci GrSamplerState sampler(SkTileModeToWrapMode(mode), SkFilterMode::kNearest); 67cb93a386Sopenharmony_ci auto fp = GrTextureEffect::MakeSubset(src, 68cb93a386Sopenharmony_ci kPremul_SkAlphaType, 69cb93a386Sopenharmony_ci SkMatrix::Translate(-offset.x(), -offset.y()), 70cb93a386Sopenharmony_ci sampler, 71cb93a386Sopenharmony_ci SkRect::Make(srcTileRect), 72cb93a386Sopenharmony_ci *rContext->priv().caps()); 73cb93a386Sopenharmony_ci sfc->fillWithFP(std::move(fp)); 74cb93a386Sopenharmony_ci return sfc->readSurfaceView(); 75cb93a386Sopenharmony_ci }; 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci SkIPoint outset = {SkGpuBlurUtils::SigmaRadius(sigmaX), SkGpuBlurUtils::SigmaRadius(sigmaY)}; 78cb93a386Sopenharmony_ci SkISize size = {dstB.width() + 2*outset.x(), dstB.height() + 2*outset.y()}; 79cb93a386Sopenharmony_ci src = tileInto(std::move(src), srcB, size, outset - dstB.topLeft(), mode); 80cb93a386Sopenharmony_ci if (!src) { 81cb93a386Sopenharmony_ci return {}; 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci dstB = SkIRect::MakePtSize(outset, dstB.size()); 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci while (sigmaX || sigmaY) { 86cb93a386Sopenharmony_ci float stepX = sigmaX; 87cb93a386Sopenharmony_ci if (stepX > SkGpuBlurUtils::kMaxSigma) { 88cb93a386Sopenharmony_ci stepX = SkGpuBlurUtils::kMaxSigma; 89cb93a386Sopenharmony_ci // A blur of sigma1 followed by a blur of sigma2 is equiv. to a single blur of 90cb93a386Sopenharmony_ci // sqrt(sigma1^2 + sigma2^2). 91cb93a386Sopenharmony_ci sigmaX = sqrt(sigmaX*sigmaX - SkGpuBlurUtils::kMaxSigma*SkGpuBlurUtils::kMaxSigma); 92cb93a386Sopenharmony_ci } else { 93cb93a386Sopenharmony_ci sigmaX = 0.f; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci float stepY = sigmaY; 96cb93a386Sopenharmony_ci if (stepY > SkGpuBlurUtils::kMaxSigma) { 97cb93a386Sopenharmony_ci stepY = SkGpuBlurUtils::kMaxSigma; 98cb93a386Sopenharmony_ci sigmaY = sqrt(sigmaY*sigmaY- SkGpuBlurUtils::kMaxSigma*SkGpuBlurUtils::kMaxSigma); 99cb93a386Sopenharmony_ci } else { 100cb93a386Sopenharmony_ci sigmaY = 0.f; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci auto bounds = SkIRect::MakeSize(src.dimensions()); 103cb93a386Sopenharmony_ci auto sdc = SkGpuBlurUtils::GaussianBlur(rContext, 104cb93a386Sopenharmony_ci std::move(src), 105cb93a386Sopenharmony_ci GrColorType::kRGBA_8888, 106cb93a386Sopenharmony_ci kPremul_SkAlphaType, 107cb93a386Sopenharmony_ci nullptr, 108cb93a386Sopenharmony_ci bounds, 109cb93a386Sopenharmony_ci bounds, 110cb93a386Sopenharmony_ci stepX, 111cb93a386Sopenharmony_ci stepY, 112cb93a386Sopenharmony_ci SkTileMode::kClamp); 113cb93a386Sopenharmony_ci if (!sdc) { 114cb93a386Sopenharmony_ci return {}; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci src = sdc->readSurfaceView(); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci // We have o use the original mode here because we may have only blurred in X or Y and then 119cb93a386Sopenharmony_ci // the other dimension was not expanded. 120cb93a386Sopenharmony_ci auto srcRect = SkIRect::MakeSize(src.dimensions()); 121cb93a386Sopenharmony_ci return tileInto(std::move(src), srcRect, dstB.size(), -outset, SkTileMode::kClamp); 122cb93a386Sopenharmony_ci}; 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci// Makes a src texture for as a source for blurs. If 'contentArea' then the content will 125cb93a386Sopenharmony_ci// be in that rect, the 1-pixel surrounding border will be transparent black, and red outside of 126cb93a386Sopenharmony_ci// that. Otherwise, the content fills the dimensions. 127cb93a386Sopenharmony_ciGrSurfaceProxyView make_src_image(GrRecordingContext* rContext, 128cb93a386Sopenharmony_ci SkISize dimensions, 129cb93a386Sopenharmony_ci const SkIRect* contentArea = nullptr) { 130cb93a386Sopenharmony_ci auto srcII = SkImageInfo::Make(dimensions, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 131cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRenderTarget(rContext, SkBudgeted::kYes, srcII); 132cb93a386Sopenharmony_ci if (!surf) { 133cb93a386Sopenharmony_ci return {}; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci float w, h; 137cb93a386Sopenharmony_ci if (contentArea) { 138cb93a386Sopenharmony_ci surf->getCanvas()->clear(SK_ColorRED); 139cb93a386Sopenharmony_ci surf->getCanvas()->clipIRect(contentArea->makeOutset(1, 1)); 140cb93a386Sopenharmony_ci surf->getCanvas()->clear(SK_ColorTRANSPARENT); 141cb93a386Sopenharmony_ci surf->getCanvas()->clipIRect(*contentArea); 142cb93a386Sopenharmony_ci surf->getCanvas()->translate(contentArea->top(), contentArea->left()); 143cb93a386Sopenharmony_ci w = contentArea->width(); 144cb93a386Sopenharmony_ci h = contentArea->height(); 145cb93a386Sopenharmony_ci } else { 146cb93a386Sopenharmony_ci w = dimensions.width(); 147cb93a386Sopenharmony_ci h = dimensions.height(); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci surf->getCanvas()->drawColor(SK_ColorDKGRAY); 151cb93a386Sopenharmony_ci SkPaint paint; 152cb93a386Sopenharmony_ci paint.setAntiAlias(true); 153cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 154cb93a386Sopenharmony_ci // Draw four horizontal lines at 1/8, 1/4, 3/4, 7/8. 155cb93a386Sopenharmony_ci paint.setStrokeWidth(h/12.f); 156cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 157cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({0.f, 1.f*h/8.f}, {w, 1.f*h/8.f}, paint); 158cb93a386Sopenharmony_ci paint.setColor(/* sea foam */ 0xFF71EEB8); 159cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({0.f, 1.f*h/4.f}, {w, 1.f*h/4.f}, paint); 160cb93a386Sopenharmony_ci paint.setColor(SK_ColorYELLOW); 161cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({0.f, 3.f*h/4.f}, {w, 3.f*h/4.f}, paint); 162cb93a386Sopenharmony_ci paint.setColor(SK_ColorCYAN); 163cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({0.f, 7.f*h/8.f}, {w, 7.f*h/8.f}, paint); 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci // Draw four vertical lines at 1/8, 1/4, 3/4, 7/8. 166cb93a386Sopenharmony_ci paint.setStrokeWidth(w/12.f); 167cb93a386Sopenharmony_ci paint.setColor(/* orange */ 0xFFFFA500); 168cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({1.f*w/8.f, 0.f}, {1.f*h/8.f, h}, paint); 169cb93a386Sopenharmony_ci paint.setColor(SK_ColorBLUE); 170cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({1.f*w/4.f, 0.f}, {1.f*h/4.f, h}, paint); 171cb93a386Sopenharmony_ci paint.setColor(SK_ColorMAGENTA); 172cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({3.f*w/4.f, 0.f}, {3.f*h/4.f, h}, paint); 173cb93a386Sopenharmony_ci paint.setColor(SK_ColorGREEN); 174cb93a386Sopenharmony_ci surf->getCanvas()->drawLine({7.f*w/8.f, 0.f}, {7.f*h/8.f, h}, paint); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci auto img = surf->makeImageSnapshot(); 177cb93a386Sopenharmony_ci auto [src, ct] = as_IB(img)->asView(rContext, GrMipmapped::kNo); 178cb93a386Sopenharmony_ci return src; 179cb93a386Sopenharmony_ci} 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci} // namespace 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_cinamespace skiagm { 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_cistatic GM::DrawResult run(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg, 186cb93a386Sopenharmony_ci bool subsetSrc, bool ref) { 187cb93a386Sopenharmony_ci GrSurfaceProxyView src = make_src_image(rContext, {60, 60}); 188cb93a386Sopenharmony_ci if (!src) { 189cb93a386Sopenharmony_ci *errorMsg = "Failed to create source image"; 190cb93a386Sopenharmony_ci return DrawResult::kSkip; 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 194cb93a386Sopenharmony_ci if (!sdc) { 195cb93a386Sopenharmony_ci *errorMsg = GM::kErrorMsg_DrawSkippedGpuOnly; 196cb93a386Sopenharmony_ci return DrawResult::kSkip; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci SkIRect srcRect = SkIRect::MakeSize(src.dimensions()); 200cb93a386Sopenharmony_ci if (subsetSrc) { 201cb93a386Sopenharmony_ci srcRect = SkIRect::MakeXYWH(2.f*srcRect.width() /8.f, 202cb93a386Sopenharmony_ci 1.f*srcRect.height()/8.f, 203cb93a386Sopenharmony_ci 5.f*srcRect.width() /8.f, 204cb93a386Sopenharmony_ci 6.f*srcRect.height()/8.f); 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci int srcW = srcRect.width(); 207cb93a386Sopenharmony_ci int srcH = srcRect.height(); 208cb93a386Sopenharmony_ci // Each set of rects is drawn in one test area so they probably should not abut or overlap 209cb93a386Sopenharmony_ci // to visualize the blurs separately. 210cb93a386Sopenharmony_ci const std::vector<SkIRect> dstRectSets[] = { 211cb93a386Sopenharmony_ci // encloses source bounds. 212cb93a386Sopenharmony_ci { 213cb93a386Sopenharmony_ci srcRect.makeOutset(srcW/5, srcH/5) 214cb93a386Sopenharmony_ci }, 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci // partial overlap from above/below. 217cb93a386Sopenharmony_ci { 218cb93a386Sopenharmony_ci SkIRect::MakeXYWH(srcRect.x(), srcRect.y() + 3*srcH/4, srcW, srcH), 219cb93a386Sopenharmony_ci SkIRect::MakeXYWH(srcRect.x(), srcRect.y() - 3*srcH/4, srcW, srcH) 220cb93a386Sopenharmony_ci }, 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci // adjacent to each side of src bounds. 223cb93a386Sopenharmony_ci { 224cb93a386Sopenharmony_ci srcRect.makeOffset( 0, srcH), 225cb93a386Sopenharmony_ci srcRect.makeOffset( srcW, 0), 226cb93a386Sopenharmony_ci srcRect.makeOffset( 0, -srcH), 227cb93a386Sopenharmony_ci srcRect.makeOffset(-srcW, 0), 228cb93a386Sopenharmony_ci }, 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci // fully outside src bounds in one direction. 231cb93a386Sopenharmony_ci { 232cb93a386Sopenharmony_ci SkIRect::MakeXYWH(-6.f*srcW/8.f, -7.f*srcH/8.f, 4.f*srcW/8.f, 20.f*srcH/8.f) 233cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 234cb93a386Sopenharmony_ci SkIRect::MakeXYWH(-1.f*srcW/8.f, -7.f*srcH/8.f, 16.f*srcW/8.f, 2.f*srcH/8.f) 235cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 236cb93a386Sopenharmony_ci SkIRect::MakeXYWH(10.f*srcW/8.f, -3.f*srcH/8.f, 4.f*srcW/8.f, 16.f*srcH/8.f) 237cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 238cb93a386Sopenharmony_ci SkIRect::MakeXYWH(-7.f*srcW/8.f, 14.f*srcH/8.f, 18.f*srcW/8.f, 1.f*srcH/8.f) 239cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 240cb93a386Sopenharmony_ci }, 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ci // outside of src bounds in both directions. 243cb93a386Sopenharmony_ci { 244cb93a386Sopenharmony_ci SkIRect::MakeXYWH(-5.f*srcW/8.f, -5.f*srcH/8.f, 2.f*srcW/8.f, 2.f*srcH/8.f) 245cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 246cb93a386Sopenharmony_ci SkIRect::MakeXYWH(-5.f*srcW/8.f, 12.f*srcH/8.f, 2.f*srcW/8.f, 2.f*srcH/8.f) 247cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 248cb93a386Sopenharmony_ci SkIRect::MakeXYWH(12.f*srcW/8.f, -5.f*srcH/8.f, 2.f*srcW/8.f, 2.f*srcH/8.f) 249cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 250cb93a386Sopenharmony_ci SkIRect::MakeXYWH(12.f*srcW/8.f, 12.f*srcH/8.f, 2.f*srcW/8.f, 2.f*srcH/8.f) 251cb93a386Sopenharmony_ci .makeOffset(srcRect.topLeft()), 252cb93a386Sopenharmony_ci }, 253cb93a386Sopenharmony_ci }; 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci const auto& caps = *rContext->priv().caps(); 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci static constexpr SkScalar kPad = 10; 258cb93a386Sopenharmony_ci SkVector trans = {kPad, kPad}; 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci sdc->clear(SK_PMColor4fWHITE); 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci SkIRect testArea = srcRect; 263cb93a386Sopenharmony_ci testArea.outset(testArea.width(), testArea.height()); 264cb93a386Sopenharmony_ci for (const auto& dstRectSet : dstRectSets) { 265cb93a386Sopenharmony_ci for (int t = 0; t < kSkTileModeCount; ++t) { 266cb93a386Sopenharmony_ci auto mode = static_cast<SkTileMode>(t); 267cb93a386Sopenharmony_ci GrSamplerState sampler(SkTileModeToWrapMode(mode), GrSamplerState::Filter::kNearest); 268cb93a386Sopenharmony_ci SkMatrix m = SkMatrix::Translate(trans.x() - testArea.x(), trans.y() - testArea.y()); 269cb93a386Sopenharmony_ci // Draw the src subset in the tile mode faded as a reference before drawing the blur 270cb93a386Sopenharmony_ci // on top. 271cb93a386Sopenharmony_ci { 272cb93a386Sopenharmony_ci static constexpr float kAlpha = 0.2f; 273cb93a386Sopenharmony_ci auto fp = GrTextureEffect::MakeSubset(src, kPremul_SkAlphaType, SkMatrix::I(), 274cb93a386Sopenharmony_ci sampler, SkRect::Make(srcRect), caps); 275cb93a386Sopenharmony_ci fp = GrFragmentProcessor::ModulateRGBA(std::move(fp), 276cb93a386Sopenharmony_ci {kAlpha, kAlpha, kAlpha, kAlpha}); 277cb93a386Sopenharmony_ci GrPaint paint; 278cb93a386Sopenharmony_ci paint.setColorFragmentProcessor(std::move(fp)); 279cb93a386Sopenharmony_ci sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, m, SkRect::Make(testArea)); 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci // Do a blur for each dstRect in the set over our testArea-sized background. 282cb93a386Sopenharmony_ci for (const auto& dstRect : dstRectSet) { 283cb93a386Sopenharmony_ci const SkScalar sigmaX = src.width() / 10.f; 284cb93a386Sopenharmony_ci const SkScalar sigmaY = src.height() / 10.f; 285cb93a386Sopenharmony_ci auto blurFn = ref ? slow_blur : blur; 286cb93a386Sopenharmony_ci // Blur using the rect and draw on top. 287cb93a386Sopenharmony_ci if (auto blurView = blurFn(rContext, 288cb93a386Sopenharmony_ci src, 289cb93a386Sopenharmony_ci dstRect, 290cb93a386Sopenharmony_ci srcRect, 291cb93a386Sopenharmony_ci sigmaX, 292cb93a386Sopenharmony_ci sigmaY, 293cb93a386Sopenharmony_ci mode)) { 294cb93a386Sopenharmony_ci auto fp = GrTextureEffect::Make(blurView, 295cb93a386Sopenharmony_ci kPremul_SkAlphaType, 296cb93a386Sopenharmony_ci SkMatrix::I(), 297cb93a386Sopenharmony_ci sampler, 298cb93a386Sopenharmony_ci caps); 299cb93a386Sopenharmony_ci // Compose against white (default paint color) 300cb93a386Sopenharmony_ci fp = GrBlendFragmentProcessor::Make(std::move(fp), 301cb93a386Sopenharmony_ci /*dst=*/nullptr, 302cb93a386Sopenharmony_ci SkBlendMode::kSrcOver); 303cb93a386Sopenharmony_ci GrPaint paint; 304cb93a386Sopenharmony_ci // Compose against white (default paint color) and then replace the dst 305cb93a386Sopenharmony_ci // (SkBlendMode::kSrc). 306cb93a386Sopenharmony_ci fp = GrBlendFragmentProcessor::Make(std::move(fp), 307cb93a386Sopenharmony_ci /*dst=*/nullptr, 308cb93a386Sopenharmony_ci SkBlendMode::kSrcOver); 309cb93a386Sopenharmony_ci paint.setColorFragmentProcessor(std::move(fp)); 310cb93a386Sopenharmony_ci paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 311cb93a386Sopenharmony_ci sdc->fillRectToRect(nullptr, 312cb93a386Sopenharmony_ci std::move(paint), 313cb93a386Sopenharmony_ci GrAA::kNo, 314cb93a386Sopenharmony_ci m, 315cb93a386Sopenharmony_ci SkRect::Make(dstRect), 316cb93a386Sopenharmony_ci SkRect::Make(blurView.dimensions())); 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci // Show the outline of the dst rect. Mostly for kDecal but also allows visual 319cb93a386Sopenharmony_ci // confirmation that the resulting blur is the right size and in the right place. 320cb93a386Sopenharmony_ci { 321cb93a386Sopenharmony_ci GrPaint paint; 322cb93a386Sopenharmony_ci static constexpr float kAlpha = 0.6f; 323cb93a386Sopenharmony_ci paint.setColor4f({0, kAlpha, 0, kAlpha}); 324cb93a386Sopenharmony_ci SkPaint stroke; 325cb93a386Sopenharmony_ci stroke.setStyle(SkPaint::kStroke_Style); 326cb93a386Sopenharmony_ci stroke.setStrokeWidth(1.f); 327cb93a386Sopenharmony_ci GrStyle style(stroke); 328cb93a386Sopenharmony_ci auto dstR = SkRect::Make(dstRect).makeOutset(0.5f, 0.5f); 329cb93a386Sopenharmony_ci sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, m, dstR, &style); 330cb93a386Sopenharmony_ci } 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci // Show the rect that's being blurred. 333cb93a386Sopenharmony_ci { 334cb93a386Sopenharmony_ci GrPaint paint; 335cb93a386Sopenharmony_ci static constexpr float kAlpha = 0.3f; 336cb93a386Sopenharmony_ci paint.setColor4f({0, 0, 0, kAlpha}); 337cb93a386Sopenharmony_ci SkPaint stroke; 338cb93a386Sopenharmony_ci stroke.setStyle(SkPaint::kStroke_Style); 339cb93a386Sopenharmony_ci stroke.setStrokeWidth(1.f); 340cb93a386Sopenharmony_ci GrStyle style(stroke); 341cb93a386Sopenharmony_ci auto srcR = SkRect::Make(srcRect).makeOutset(0.5f, 0.5f); 342cb93a386Sopenharmony_ci sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, m, srcR, &style); 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci trans.fX += testArea.width() + kPad; 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci trans.fX = kPad; 347cb93a386Sopenharmony_ci trans.fY += testArea.height() + kPad; 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci return DrawResult::kOk; 351cb93a386Sopenharmony_ci} 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(gpu_blur_utils, rContext, canvas, errorMsg, 765, 955) { 354cb93a386Sopenharmony_ci return run(rContext, canvas, errorMsg, false, false); 355cb93a386Sopenharmony_ci} 356cb93a386Sopenharmony_ci 357cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(gpu_blur_utils_ref, rContext, canvas, errorMsg, 765, 955) { 358cb93a386Sopenharmony_ci return run(rContext, canvas, errorMsg, false, true); 359cb93a386Sopenharmony_ci} 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(gpu_blur_utils_subset_rect, rContext, canvas, errorMsg, 485, 730) { 362cb93a386Sopenharmony_ci return run(rContext, canvas, errorMsg, true, false); 363cb93a386Sopenharmony_ci} 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(gpu_blur_utils_subset_ref, rContext, canvas, errorMsg, 485, 730) { 366cb93a386Sopenharmony_ci return run(rContext, canvas, errorMsg, true, true); 367cb93a386Sopenharmony_ci} 368cb93a386Sopenharmony_ci 369cb93a386Sopenharmony_ci// Because of the way blur sigmas concat (sigTotal = sqrt(sig1^2 + sig2^2) generating these images 370cb93a386Sopenharmony_ci// for very large sigmas is incredibly slow. This can be enabled while working on the blur code to 371cb93a386Sopenharmony_ci// check results. 372cb93a386Sopenharmony_cistatic bool constexpr kShowSlowRefImages = false; 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_cistatic DrawResult do_very_large_blur_gm(GrRecordingContext* rContext, 375cb93a386Sopenharmony_ci SkCanvas* canvas, 376cb93a386Sopenharmony_ci SkString* errorMsg, 377cb93a386Sopenharmony_ci GrSurfaceProxyView src, 378cb93a386Sopenharmony_ci SkIRect srcB) { 379cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 380cb93a386Sopenharmony_ci if (!sdc) { 381cb93a386Sopenharmony_ci *errorMsg = GM::kErrorMsg_DrawSkippedGpuOnly; 382cb93a386Sopenharmony_ci return DrawResult::kSkip; 383cb93a386Sopenharmony_ci } 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_ci // Clear to a color other than gray to contrast with test image. 386cb93a386Sopenharmony_ci sdc->clear(SkColor4f{0.3f, 0.4f, 0.2f, 1}); 387cb93a386Sopenharmony_ci 388cb93a386Sopenharmony_ci int x = 10; 389cb93a386Sopenharmony_ci int y = 10; 390cb93a386Sopenharmony_ci for (auto blurDirs : {0b01, 0b10, 0b11}) { 391cb93a386Sopenharmony_ci for (int t = 0; t <= static_cast<int>(SkTileMode::kLastTileMode); ++t) { 392cb93a386Sopenharmony_ci auto tm = static_cast<SkTileMode>(t); 393cb93a386Sopenharmony_ci auto dstB = srcB.makeOutset(30, 30); 394cb93a386Sopenharmony_ci for (float sigma : {0.f, 5.f, 25.f, 80.f}) { 395cb93a386Sopenharmony_ci std::vector<decltype(blur)*> blurs; 396cb93a386Sopenharmony_ci blurs.push_back(blur); 397cb93a386Sopenharmony_ci if (kShowSlowRefImages) { 398cb93a386Sopenharmony_ci blurs.push_back(slow_blur); 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci for (auto b : blurs) { 401cb93a386Sopenharmony_ci float sigX = sigma*((blurDirs & 0b01) >> 0); 402cb93a386Sopenharmony_ci float sigY = sigma*((blurDirs & 0b10) >> 1); 403cb93a386Sopenharmony_ci GrSurfaceProxyView result = b(rContext, src, dstB, srcB, sigX, sigY, tm); 404cb93a386Sopenharmony_ci auto dstRect = SkIRect::MakeSize(dstB.size()).makeOffset(x, y); 405cb93a386Sopenharmony_ci // Draw a rect to show where the result should be so it's obvious if it's 406cb93a386Sopenharmony_ci // missing. 407cb93a386Sopenharmony_ci GrPaint paint; 408cb93a386Sopenharmony_ci paint.setColor4f(b == blur ? SkPMColor4f{0, 0, 1, 1} : SkPMColor4f{1, 0, 0, 1}); 409cb93a386Sopenharmony_ci sdc->drawRect(nullptr, 410cb93a386Sopenharmony_ci std::move(paint), 411cb93a386Sopenharmony_ci GrAA::kNo, 412cb93a386Sopenharmony_ci SkMatrix::I(), 413cb93a386Sopenharmony_ci SkRect::Make(dstRect).makeOutset(0.5, 0.5), 414cb93a386Sopenharmony_ci &GrStyle::SimpleHairline()); 415cb93a386Sopenharmony_ci if (result) { 416cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp = 417cb93a386Sopenharmony_ci GrTextureEffect::Make(std::move(result), kPremul_SkAlphaType); 418cb93a386Sopenharmony_ci fp = GrBlendFragmentProcessor::Make(std::move(fp), 419cb93a386Sopenharmony_ci /*dst=*/nullptr, 420cb93a386Sopenharmony_ci SkBlendMode::kSrcOver); 421cb93a386Sopenharmony_ci sdc->fillRectToRectWithFP(SkIRect::MakeSize(dstB.size()), 422cb93a386Sopenharmony_ci dstRect, 423cb93a386Sopenharmony_ci std::move(fp)); 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci x += dstB.width() + 10; 426cb93a386Sopenharmony_ci } 427cb93a386Sopenharmony_ci } 428cb93a386Sopenharmony_ci x = 10; 429cb93a386Sopenharmony_ci y += dstB.height() + 10; 430cb93a386Sopenharmony_ci } 431cb93a386Sopenharmony_ci } 432cb93a386Sopenharmony_ci 433cb93a386Sopenharmony_ci return DrawResult::kOk; 434cb93a386Sopenharmony_ci} 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(very_large_sigma_gpu_blur, rContext, canvas, errorMsg, 350, 1030) { 437cb93a386Sopenharmony_ci auto src = make_src_image(rContext, {15, 15}); 438cb93a386Sopenharmony_ci auto srcB = SkIRect::MakeSize(src.dimensions()); 439cb93a386Sopenharmony_ci return do_very_large_blur_gm(rContext, canvas, errorMsg, std::move(src), srcB); 440cb93a386Sopenharmony_ci} 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(very_large_sigma_gpu_blur_subset, 443cb93a386Sopenharmony_ci rContext, 444cb93a386Sopenharmony_ci canvas, 445cb93a386Sopenharmony_ci errorMsg, 446cb93a386Sopenharmony_ci 350, 1030) { 447cb93a386Sopenharmony_ci auto srcB = SkIRect::MakeXYWH(2, 2, 15, 15); 448cb93a386Sopenharmony_ci SkISize imageSize = SkISize{srcB.width() + 4, srcB.height() + 4}; 449cb93a386Sopenharmony_ci auto src = make_src_image(rContext, imageSize, &srcB); 450cb93a386Sopenharmony_ci return do_very_large_blur_gm(rContext, canvas, errorMsg, std::move(src), srcB); 451cb93a386Sopenharmony_ci} 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(very_large_sigma_gpu_blur_subset_transparent_border, 454cb93a386Sopenharmony_ci rContext, 455cb93a386Sopenharmony_ci canvas, 456cb93a386Sopenharmony_ci errorMsg, 457cb93a386Sopenharmony_ci 355, 1055) { 458cb93a386Sopenharmony_ci auto srcB = SkIRect::MakeXYWH(3, 3, 15, 15); 459cb93a386Sopenharmony_ci SkISize imageSize = SkISize{srcB.width() + 4, srcB.height() + 4}; 460cb93a386Sopenharmony_ci auto src = make_src_image(rContext, imageSize, &srcB); 461cb93a386Sopenharmony_ci return do_very_large_blur_gm(rContext, canvas, errorMsg, std::move(src), srcB.makeOutset(1, 1)); 462cb93a386Sopenharmony_ci} 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ci} // namespace skiagm 465