1/* 2 * Copyright 2019 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 8#include "include/core/SkBitmap.h" 9#include "include/core/SkCanvas.h" 10#include "include/core/SkSurface.h" 11#include "include/effects/SkImageFilters.h" 12#include "include/gpu/GrDirectContext.h" 13#include "src/gpu/GrDirectContextPriv.h" 14#include "src/gpu/GrResourceCache.h" 15#include "tests/Test.h" 16 17// This is the repro of a CastOS memory regression bug (b/138674523). 18// The test simply keeps calling SkImage::makeWithFilter (with a blur image filter) while 19// shrinking the clip. 20// When explicit resource allocation was enabled the last (re-expanded) image in the 21// blur creation process became exact. 22// This meant that its backing texture could no longer be reused. 23// In CastOS' case (and, presumably, Linux desktop) they were only using Ganesh for 24// 2D canvas and compositor image filtering. In this case Chrome doesn't regularly purge 25// the cache. This would result in Ganesh quickly running up to its max cache limit. 26DEF_GPUTEST_FOR_RENDERING_CONTEXTS(RepeatedClippedBlurTest, reporter, ctxInfo) { 27 auto dContext = ctxInfo.directContext(); 28 GrResourceCache* cache = dContext->priv().getResourceCache(); 29 30 const SkImageInfo ii = SkImageInfo::Make(1024, 600, kRGBA_8888_SkColorType, 31 kPremul_SkAlphaType); 32 33 sk_sp<SkSurface> dst(SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, ii)); 34 if (!dst) { 35 ERRORF(reporter, "Could not create surfaces for repeated clipped blur test."); 36 return; 37 } 38 39 SkCanvas* dstCanvas = dst->getCanvas(); 40 41 sk_sp<SkImage> bigImg; 42 43 // Create the initial big image (this corresponds to the album artwork - which is larger 44 // than the screen) 45 { 46 SkImageInfo srcImageII = SkImageInfo::Make(1280, 1280, kRGBA_8888_SkColorType, 47 kPremul_SkAlphaType); 48 49 // Make a red ring around a field of green. When rendered the blurred red ring 50 // should still be visible on all sides of the dest image. 51 SkBitmap bm; 52 bm.allocPixels(srcImageII); 53 bm.eraseColor(SK_ColorRED); 54 bm.eraseArea(SkIRect::MakeXYWH(1, 2, 1277, 1274), SK_ColorGREEN); 55 56 sk_sp<SkImage> rasterImg = bm.asImage(); 57 bigImg = rasterImg->makeTextureImage(dContext); 58 } 59 60 sk_sp<SkImage> smImg; 61 62 // Shrink the album artwork down to the screen's size 63 { 64 SkImageInfo screenII = SkImageInfo::Make(1024, 600, kRGBA_8888_SkColorType, 65 kPremul_SkAlphaType); 66 67 sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kYes, 68 screenII, 1, kTopLeft_GrSurfaceOrigin, 69 nullptr); 70 SkCanvas* c = s->getCanvas(); 71 72 c->drawImageRect(bigImg, SkRect::MakeWH(1024, 600), SkSamplingOptions()); 73 74 smImg = s->makeImageSnapshot(); 75 } 76 77 // flush here just to clear the playing field 78 dContext->flushAndSubmit(); 79 80 size_t beforeBytes = cache->getResourceBytes(); 81 82 // Now draw the screen-sized image, blurred, multiple times with a shrinking clip. 83 // This simulates the swipe away where the screen-sized album artwork is moved off 84 // screen. 85 // Note that the blur has to big enough to kick the blur code into the decimate then 86 // re-expand case. 87 const SkIRect subset = SkIRect::MakeWH(1024, 600); 88 SkIRect clip = SkIRect::MakeWH(1024, 600); 89 90 for (int i = 0; i < 30; ++i) { 91 dstCanvas->clear(SK_ColorBLUE); 92 93 sk_sp<SkImageFilter> blur = SkImageFilters::Blur(20, 20, nullptr); 94 95 SkIRect outSubset; 96 SkIPoint offset; 97 sk_sp<SkImage> filteredImg = smImg->makeWithFilter(dContext, blur.get(), subset, clip, 98 &outSubset, &offset); 99 100 SkRect dstRect = SkRect::MakeXYWH(offset.fX, offset.fY, 101 outSubset.width(), outSubset.height()); 102 dstCanvas->drawImageRect(filteredImg, SkRect::Make(outSubset), dstRect, SkSamplingOptions(), 103 nullptr, SkCanvas::kStrict_SrcRectConstraint); 104 105 // Flush here to mimic Chrome's SkiaHelper::ApplyImageFilter 106 dContext->flushAndSubmit(); 107 108 clip.fRight -= 16; 109 } 110 111 size_t afterBytes = cache->getResourceBytes(); 112 113 // When the bug manifests the resource cache will accumulate ~80MB. If texture recycling 114 // is working as expected the cache size will level off at ~20MB. 115 REPORTER_ASSERT(reporter, afterBytes < beforeBytes + 20000000); 116} 117