1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 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 "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 11cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 12cb93a386Sopenharmony_ci#include "src/core/SkMessageBus.h" 13cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrGpu.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResourceCacheAccess.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResourcePriv.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrRenderTarget.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrResourceCache.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h" 24cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 25cb93a386Sopenharmony_ci#include "tests/Test.h" 26cb93a386Sopenharmony_ci#include "tools/gpu/GrContextFactory.h" 27cb93a386Sopenharmony_ci#include "tools/gpu/ManagedBackendTexture.h" 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci#include <thread> 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_cistatic const int gWidth = 640; 32cb93a386Sopenharmony_cistatic const int gHeight = 480; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 35cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheCache, reporter, ctxInfo) { 36cb93a386Sopenharmony_ci auto context = ctxInfo.directContext(); 37cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight); 38cb93a386Sopenharmony_ci auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info)); 39cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci const SkIRect size = SkIRect::MakeWH(gWidth, gHeight); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci SkBitmap src; 44cb93a386Sopenharmony_ci src.allocN32Pixels(size.width(), size.height()); 45cb93a386Sopenharmony_ci src.eraseColor(SK_ColorBLACK); 46cb93a386Sopenharmony_ci size_t srcSize = src.computeByteSize(); 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci size_t initialCacheSize; 49cb93a386Sopenharmony_ci context->getResourceCacheUsage(nullptr, &initialCacheSize); 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci size_t oldMaxBytes = context->getResourceCacheLimit(); 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci // Set the cache limits so we can fit 10 "src" images and the 54cb93a386Sopenharmony_ci // max number of textures doesn't matter 55cb93a386Sopenharmony_ci size_t maxCacheSize = initialCacheSize + 10*srcSize; 56cb93a386Sopenharmony_ci context->setResourceCacheLimit(maxCacheSize); 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci SkBitmap readback; 59cb93a386Sopenharmony_ci readback.allocN32Pixels(size.width(), size.height()); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci for (int i = 0; i < 100; ++i) { 62cb93a386Sopenharmony_ci canvas->drawImage(src.asImage(), 0, 0); 63cb93a386Sopenharmony_ci surface->readPixels(readback, 0, 0); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci // "modify" the src texture 66cb93a386Sopenharmony_ci src.notifyPixelsChanged(); 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci size_t curCacheSize; 69cb93a386Sopenharmony_ci context->getResourceCacheUsage(nullptr, &curCacheSize); 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci // we should never go over the size limit 72cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize); 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci context->setResourceCacheLimit(oldMaxBytes); 76cb93a386Sopenharmony_ci} 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_cistatic bool is_rendering_and_not_angle_es3(sk_gpu_test::GrContextFactory::ContextType type) { 79cb93a386Sopenharmony_ci if (type == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES3_ContextType || 80cb93a386Sopenharmony_ci type == sk_gpu_test::GrContextFactory::kANGLE_GL_ES3_ContextType) { 81cb93a386Sopenharmony_ci return false; 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci return sk_gpu_test::GrContextFactory::IsRenderingContext(type); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_cistatic GrAttachment* get_SB(GrRenderTarget* rt) { return rt->getStencilAttachment(); } 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_cistatic sk_sp<GrRenderTarget> create_RT_with_SB(GrResourceProvider* provider, 89cb93a386Sopenharmony_ci int size, int sampleCount, SkBudgeted budgeted) { 90cb93a386Sopenharmony_ci auto format = 91cb93a386Sopenharmony_ci provider->caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, GrRenderable::kYes); 92cb93a386Sopenharmony_ci sk_sp<GrTexture> tex(provider->createTexture({size, size}, format, GrTextureType::k2D, 93cb93a386Sopenharmony_ci GrRenderable::kYes, sampleCount, GrMipmapped::kNo, 94cb93a386Sopenharmony_ci budgeted, GrProtected::kNo)); 95cb93a386Sopenharmony_ci if (!tex || !tex->asRenderTarget()) { 96cb93a386Sopenharmony_ci return nullptr; 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci if (!provider->attachStencilAttachment(tex->asRenderTarget(), sampleCount > 1)) { 100cb93a386Sopenharmony_ci return nullptr; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci SkASSERT(get_SB(tex->asRenderTarget())); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci return sk_ref_sp(tex->asRenderTarget()); 105cb93a386Sopenharmony_ci} 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci// This currently fails on ES3 ANGLE contexts 108cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_CONTEXTS(ResourceCacheStencilBuffers, &is_rendering_and_not_angle_es3, reporter, 109cb93a386Sopenharmony_ci ctxInfo, nullptr) { 110cb93a386Sopenharmony_ci auto context = ctxInfo.directContext(); 111cb93a386Sopenharmony_ci const GrCaps* caps = context->priv().caps(); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci if (caps->avoidStencilBuffers()) { 114cb93a386Sopenharmony_ci return; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci GrResourceProvider* resourceProvider = context->priv().resourceProvider(); 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci GrColorType grColorType = GrColorType::kRGBA_8888; 120cb93a386Sopenharmony_ci GrBackendFormat format = caps->getDefaultBackendFormat(grColorType, GrRenderable::kYes); 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> smallRT0 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes); 123cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, smallRT0); 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci { 126cb93a386Sopenharmony_ci // Two budgeted RTs with the same desc should share a stencil buffer. 127cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> smallRT1 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes); 128cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, smallRT1); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT1.get())); 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci { 134cb93a386Sopenharmony_ci // An unbudgeted RT with the same desc should also share. 135cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> smallRT2 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kNo); 136cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, smallRT2); 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT2.get())); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci { 142cb93a386Sopenharmony_ci // An RT with a much larger size should not share. 143cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> bigRT = create_RT_with_SB(resourceProvider, 400, 1, SkBudgeted::kNo); 144cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bigRT); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(bigRT.get())); 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci int smallSampleCount = 150cb93a386Sopenharmony_ci context->priv().caps()->getRenderTargetSampleCount(2, format); 151cb93a386Sopenharmony_ci if (smallSampleCount > 1) { 152cb93a386Sopenharmony_ci // An RT with a different sample count should not share. 153cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> smallMSAART0 = create_RT_with_SB(resourceProvider, 4, 154cb93a386Sopenharmony_ci smallSampleCount, SkBudgeted::kNo); 155cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, smallMSAART0); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(smallMSAART0.get())); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci { 160cb93a386Sopenharmony_ci // A second MSAA RT should share with the first MSAA RT. 161cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> smallMSAART1 = create_RT_with_SB(resourceProvider, 4, 162cb93a386Sopenharmony_ci smallSampleCount, 163cb93a386Sopenharmony_ci SkBudgeted::kNo); 164cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, smallMSAART1); 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) == get_SB(smallMSAART1.get())); 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // But one with a larger sample count should not. (Also check that the two requests didn't 170cb93a386Sopenharmony_ci // rounded up to the same actual sample count or else they could share.). 171cb93a386Sopenharmony_ci int bigSampleCount = context->priv().caps()->getRenderTargetSampleCount(5, format); 172cb93a386Sopenharmony_ci if (bigSampleCount > 0 && bigSampleCount != smallSampleCount) { 173cb93a386Sopenharmony_ci sk_sp<GrRenderTarget> smallMSAART2 = create_RT_with_SB(resourceProvider, 4, 174cb93a386Sopenharmony_ci bigSampleCount, 175cb93a386Sopenharmony_ci SkBudgeted::kNo); 176cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, smallMSAART2); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) != get_SB(smallMSAART2.get())); 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci} 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheWrappedResources, reporter, ctxInfo) { 184cb93a386Sopenharmony_ci auto context = ctxInfo.directContext(); 185cb93a386Sopenharmony_ci GrResourceProvider* resourceProvider = context->priv().resourceProvider(); 186cb93a386Sopenharmony_ci GrGpu* gpu = context->priv().getGpu(); 187cb93a386Sopenharmony_ci // this test is only valid for GL 188cb93a386Sopenharmony_ci if (!gpu || !gpu->glContextForTesting()) { 189cb93a386Sopenharmony_ci return; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci static const int kW = 100; 193cb93a386Sopenharmony_ci static const int kH = 100; 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData( 196cb93a386Sopenharmony_ci context, kW, kH, kRGBA_8888_SkColorType, GrMipmapped::kNo, GrRenderable::kNo); 197cb93a386Sopenharmony_ci GrBackendTexture unmbet = context->createBackendTexture( 198cb93a386Sopenharmony_ci kW, kH, kRGBA_8888_SkColorType, GrMipmapped::kNo, GrRenderable::kNo); 199cb93a386Sopenharmony_ci if (!mbet || !unmbet.isValid()) { 200cb93a386Sopenharmony_ci ERRORF(reporter, "Could not create backend texture."); 201cb93a386Sopenharmony_ci return; 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci context->resetContext(); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci sk_sp<GrTexture> borrowed(resourceProvider->wrapBackendTexture( 207cb93a386Sopenharmony_ci mbet->texture(), kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRead_GrIOType)); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci sk_sp<GrTexture> adopted(resourceProvider->wrapBackendTexture( 210cb93a386Sopenharmony_ci unmbet, kAdopt_GrWrapOwnership, GrWrapCacheable::kNo, kRead_GrIOType)); 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, borrowed != nullptr && adopted != nullptr); 213cb93a386Sopenharmony_ci if (!borrowed || !adopted) { 214cb93a386Sopenharmony_ci return; 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci borrowed.reset(); 218cb93a386Sopenharmony_ci adopted.reset(); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci context->flushAndSubmit(/*sync*/ true); 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(mbet->texture()); 223cb93a386Sopenharmony_ci bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(unmbet); 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, borrowedIsAlive); 226cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !adoptedIsAlive); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci if (adoptedIsAlive) { 229cb93a386Sopenharmony_ci context->deleteBackendTexture(unmbet); 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci context->resetContext(); 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ciclass TestResource : public GrGpuResource { 236cb93a386Sopenharmony_ci enum ScratchConstructor { kScratchConstructor }; 237cb93a386Sopenharmony_cipublic: 238cb93a386Sopenharmony_ci static const size_t kDefaultSize = 100; 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci /** Property that distinctly categorizes the resource. 241cb93a386Sopenharmony_ci * For example, textures have width, height, ... */ 242cb93a386Sopenharmony_ci enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty }; 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci TestResource(GrGpu* gpu, SkBudgeted budgeted = SkBudgeted::kYes, size_t size = kDefaultSize) 245cb93a386Sopenharmony_ci : INHERITED(gpu) 246cb93a386Sopenharmony_ci , fToDelete(nullptr) 247cb93a386Sopenharmony_ci , fSize(size) 248cb93a386Sopenharmony_ci , fProperty(kA_SimulatedProperty) 249cb93a386Sopenharmony_ci , fIsScratch(false) { 250cb93a386Sopenharmony_ci ++fNumAlive; 251cb93a386Sopenharmony_ci this->registerWithCache(budgeted); 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci static TestResource* CreateScratch(GrGpu* gpu, SkBudgeted budgeted, 255cb93a386Sopenharmony_ci SimulatedProperty property, size_t size = kDefaultSize) { 256cb93a386Sopenharmony_ci return new TestResource(gpu, budgeted, property, kScratchConstructor, size); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci static TestResource* CreateWrapped(GrGpu* gpu, GrWrapCacheable cacheable, 259cb93a386Sopenharmony_ci size_t size = kDefaultSize) { 260cb93a386Sopenharmony_ci return new TestResource(gpu, cacheable, size); 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci ~TestResource() override { 264cb93a386Sopenharmony_ci --fNumAlive; 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci static int NumAlive() { return fNumAlive; } 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci void setUnrefWhenDestroyed(sk_sp<TestResource> resource) { 270cb93a386Sopenharmony_ci fToDelete = std::move(resource); 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci static void ComputeScratchKey(SimulatedProperty property, GrScratchKey* key) { 274cb93a386Sopenharmony_ci static GrScratchKey::ResourceType t = GrScratchKey::GenerateResourceType(); 275cb93a386Sopenharmony_ci GrScratchKey::Builder builder(key, t, kScratchKeyFieldCnt); 276cb93a386Sopenharmony_ci for (int i = 0; i < kScratchKeyFieldCnt; ++i) { 277cb93a386Sopenharmony_ci builder[i] = static_cast<uint32_t>(i + property); 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci static size_t ExpectedScratchKeySize() { 282cb93a386Sopenharmony_ci return sizeof(uint32_t) * (kScratchKeyFieldCnt + GrScratchKey::kMetaDataCnt); 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ciprivate: 285cb93a386Sopenharmony_ci static const int kScratchKeyFieldCnt = 6; 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci TestResource(GrGpu* gpu, SkBudgeted budgeted, SimulatedProperty property, ScratchConstructor, 288cb93a386Sopenharmony_ci size_t size = kDefaultSize) 289cb93a386Sopenharmony_ci : INHERITED(gpu) 290cb93a386Sopenharmony_ci , fToDelete(nullptr) 291cb93a386Sopenharmony_ci , fSize(size) 292cb93a386Sopenharmony_ci , fProperty(property) 293cb93a386Sopenharmony_ci , fIsScratch(true) { 294cb93a386Sopenharmony_ci ++fNumAlive; 295cb93a386Sopenharmony_ci this->registerWithCache(budgeted); 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci // Constructor for simulating resources that wrap backend objects. 299cb93a386Sopenharmony_ci TestResource(GrGpu* gpu, GrWrapCacheable cacheable, size_t size) 300cb93a386Sopenharmony_ci : INHERITED(gpu) 301cb93a386Sopenharmony_ci , fToDelete(nullptr) 302cb93a386Sopenharmony_ci , fSize(size) 303cb93a386Sopenharmony_ci , fProperty(kA_SimulatedProperty) 304cb93a386Sopenharmony_ci , fIsScratch(false) { 305cb93a386Sopenharmony_ci ++fNumAlive; 306cb93a386Sopenharmony_ci this->registerWithCacheWrapped(cacheable); 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci void computeScratchKey(GrScratchKey* key) const override { 310cb93a386Sopenharmony_ci if (fIsScratch) { 311cb93a386Sopenharmony_ci ComputeScratchKey(fProperty, key); 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci size_t onGpuMemorySize() const override { return fSize; } 316cb93a386Sopenharmony_ci const char* getResourceType() const override { return "Test"; } 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci sk_sp<TestResource> fToDelete; 319cb93a386Sopenharmony_ci size_t fSize; 320cb93a386Sopenharmony_ci static int fNumAlive; 321cb93a386Sopenharmony_ci SimulatedProperty fProperty; 322cb93a386Sopenharmony_ci bool fIsScratch; 323cb93a386Sopenharmony_ci using INHERITED = GrGpuResource; 324cb93a386Sopenharmony_ci}; 325cb93a386Sopenharmony_ciint TestResource::fNumAlive = 0; 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ciclass Mock { 328cb93a386Sopenharmony_cipublic: 329cb93a386Sopenharmony_ci Mock(size_t maxBytes) { 330cb93a386Sopenharmony_ci fDContext = GrDirectContext::MakeMock(nullptr); 331cb93a386Sopenharmony_ci SkASSERT(fDContext); 332cb93a386Sopenharmony_ci fDContext->setResourceCacheLimit(maxBytes); 333cb93a386Sopenharmony_ci GrResourceCache* cache = fDContext->priv().getResourceCache(); 334cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 335cb93a386Sopenharmony_ci SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes()); 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci 338cb93a386Sopenharmony_ci GrResourceCache* cache() { return fDContext->priv().getResourceCache(); } 339cb93a386Sopenharmony_ci GrGpu* gpu() { return fDContext->priv().getGpu(); } 340cb93a386Sopenharmony_ci GrDirectContext* dContext() { return fDContext.get(); } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci void reset() { 343cb93a386Sopenharmony_ci fDContext.reset(); 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ciprivate: 347cb93a386Sopenharmony_ci sk_sp<GrDirectContext> fDContext; 348cb93a386Sopenharmony_ci}; 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_cistatic void test_no_key(skiatest::Reporter* reporter) { 351cb93a386Sopenharmony_ci Mock mock(30000); 352cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 353cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 354cb93a386Sopenharmony_ci 355cb93a386Sopenharmony_ci // Create a bunch of resources with no keys 356cb93a386Sopenharmony_ci TestResource* a = new TestResource(gpu, SkBudgeted::kYes, 11); 357cb93a386Sopenharmony_ci TestResource* b = new TestResource(gpu, SkBudgeted::kYes, 12); 358cb93a386Sopenharmony_ci TestResource* c = new TestResource(gpu, SkBudgeted::kYes, 13 ); 359cb93a386Sopenharmony_ci TestResource* d = new TestResource(gpu, SkBudgeted::kYes, 14 ); 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 362cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 363cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() + 364cb93a386Sopenharmony_ci d->gpuMemorySize() == cache->getResourceBytes()); 365cb93a386Sopenharmony_ci 366cb93a386Sopenharmony_ci // Should be safe to purge without deleting the resources since we still have refs. 367cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 368cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_ci // Since the resources have neither unique nor scratch keys, delete immediately upon unref. 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci a->unref(); 373cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive()); 374cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 375cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() == 376cb93a386Sopenharmony_ci cache->getResourceBytes()); 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_ci c->unref(); 379cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 380cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 381cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() == 382cb93a386Sopenharmony_ci cache->getResourceBytes()); 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci d->unref(); 385cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 386cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 387cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci b->unref(); 390cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 391cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 392cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 393cb93a386Sopenharmony_ci} 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci// Each integer passed as a template param creates a new domain. 396cb93a386Sopenharmony_citemplate <int> 397cb93a386Sopenharmony_cistatic void make_unique_key(GrUniqueKey* key, int data, const char* tag = nullptr) { 398cb93a386Sopenharmony_ci static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); 399cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(key, d, 1, tag); 400cb93a386Sopenharmony_ci builder[0] = data; 401cb93a386Sopenharmony_ci} 402cb93a386Sopenharmony_ci 403cb93a386Sopenharmony_cistatic void test_purge_unlocked(skiatest::Reporter* reporter) { 404cb93a386Sopenharmony_ci Mock mock(30000); 405cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 406cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci // Create two resource w/ a unique key and two w/o but all of which have scratch keys. 409cb93a386Sopenharmony_ci TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 410cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 11); 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ci GrUniqueKey uniqueKey; 413cb93a386Sopenharmony_ci make_unique_key<0>(&uniqueKey, 0); 414cb93a386Sopenharmony_ci 415cb93a386Sopenharmony_ci TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 416cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 12); 417cb93a386Sopenharmony_ci b->resourcePriv().setUniqueKey(uniqueKey); 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 420cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 13); 421cb93a386Sopenharmony_ci 422cb93a386Sopenharmony_ci GrUniqueKey uniqueKey2; 423cb93a386Sopenharmony_ci make_unique_key<0>(&uniqueKey2, 1); 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci TestResource* d = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 426cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 14); 427cb93a386Sopenharmony_ci d->resourcePriv().setUniqueKey(uniqueKey2); 428cb93a386Sopenharmony_ci 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 431cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 432cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() + 433cb93a386Sopenharmony_ci d->gpuMemorySize() == cache->getResourceBytes()); 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci // Should be safe to purge without deleting the resources since we still have refs. 436cb93a386Sopenharmony_ci cache->purgeUnlockedResources(false); 437cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci // Unref them all. Since they all have keys they should remain in the cache. 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci a->unref(); 442cb93a386Sopenharmony_ci b->unref(); 443cb93a386Sopenharmony_ci c->unref(); 444cb93a386Sopenharmony_ci d->unref(); 445cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 446cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 447cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() + 448cb93a386Sopenharmony_ci d->gpuMemorySize() == cache->getResourceBytes()); 449cb93a386Sopenharmony_ci 450cb93a386Sopenharmony_ci // Purge only the two scratch resources 451cb93a386Sopenharmony_ci cache->purgeUnlockedResources(true); 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 454cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 455cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() == 456cb93a386Sopenharmony_ci cache->getResourceBytes()); 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_ci // Purge the uniquely keyed resources 459cb93a386Sopenharmony_ci cache->purgeUnlockedResources(false); 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 462cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 463cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 464cb93a386Sopenharmony_ci} 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_cistatic void test_purge_command_buffer_usage(skiatest::Reporter* reporter) { 467cb93a386Sopenharmony_ci Mock mock(30000); 468cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 469cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci // Create two resource w/ scratch keys. 472cb93a386Sopenharmony_ci TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 473cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 11); 474cb93a386Sopenharmony_ci 475cb93a386Sopenharmony_ci TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 476cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 12); 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 479cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 480cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes()); 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ci // Should be safe to purge without deleting the resources since we still have refs. 483cb93a386Sopenharmony_ci cache->purgeUnlockedResources(true); 484cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ci // Add command buffer usages to all resources 487cb93a386Sopenharmony_ci a->addCommandBufferUsage(); 488cb93a386Sopenharmony_ci b->addCommandBufferUsage(); 489cb93a386Sopenharmony_ci 490cb93a386Sopenharmony_ci // Should be safe to purge without deleting the resources since we still have refs and command 491cb93a386Sopenharmony_ci // buffer usages. 492cb93a386Sopenharmony_ci cache->purgeUnlockedResources(true); 493cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci // Unref the first resource 496cb93a386Sopenharmony_ci a->unref(); 497cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 498cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 499cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes()); 500cb93a386Sopenharmony_ci 501cb93a386Sopenharmony_ci // Should be safe to purge without deleting the resources since we still have command buffer 502cb93a386Sopenharmony_ci // usages and the second still has a ref. 503cb93a386Sopenharmony_ci cache->purgeUnlockedResources(true); 504cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci // Remove command buffer usages 507cb93a386Sopenharmony_ci a->removeCommandBufferUsage(); 508cb93a386Sopenharmony_ci b->removeCommandBufferUsage(); 509cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 510cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 511cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes()); 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ci // Purge this time should remove the first resources since it no longer has any refs or command 514cb93a386Sopenharmony_ci // buffer usages. 515cb93a386Sopenharmony_ci cache->purgeUnlockedResources(true); 516cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 517cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 518cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci // Unref the second resource 521cb93a386Sopenharmony_ci b->unref(); 522cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 523cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 524cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_ci // Purge the last resource 527cb93a386Sopenharmony_ci cache->purgeUnlockedResources(false); 528cb93a386Sopenharmony_ci 529cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 530cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 531cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 532cb93a386Sopenharmony_ci} 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_cistatic void test_budgeting(skiatest::Reporter* reporter) { 535cb93a386Sopenharmony_ci Mock mock(300); 536cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 537cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 538cb93a386Sopenharmony_ci 539cb93a386Sopenharmony_ci GrUniqueKey uniqueKey; 540cb93a386Sopenharmony_ci make_unique_key<0>(&uniqueKey, 0); 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ci // Create a scratch, a unique, and a wrapped resource 543cb93a386Sopenharmony_ci TestResource* scratch = 544cb93a386Sopenharmony_ci TestResource::CreateScratch(gpu, SkBudgeted::kYes, TestResource::kB_SimulatedProperty, 545cb93a386Sopenharmony_ci 10); 546cb93a386Sopenharmony_ci TestResource* unique = new TestResource(gpu, SkBudgeted::kYes, 11); 547cb93a386Sopenharmony_ci unique->resourcePriv().setUniqueKey(uniqueKey); 548cb93a386Sopenharmony_ci TestResource* wrappedCacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes, 12); 549cb93a386Sopenharmony_ci TestResource* wrappedUncacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kNo, 13); 550cb93a386Sopenharmony_ci TestResource* unbudgeted = new TestResource(gpu, SkBudgeted::kNo, 14); 551cb93a386Sopenharmony_ci 552cb93a386Sopenharmony_ci // Make sure we can add a unique key to the wrapped resources 553cb93a386Sopenharmony_ci GrUniqueKey uniqueKey2; 554cb93a386Sopenharmony_ci make_unique_key<0>(&uniqueKey2, 1); 555cb93a386Sopenharmony_ci GrUniqueKey uniqueKey3; 556cb93a386Sopenharmony_ci make_unique_key<0>(&uniqueKey3, 2); 557cb93a386Sopenharmony_ci wrappedCacheable->resourcePriv().setUniqueKey(uniqueKey2); 558cb93a386Sopenharmony_ci wrappedUncacheable->resourcePriv().setUniqueKey(uniqueKey3); 559cb93a386Sopenharmony_ci GrGpuResource* wrappedCacheableViaKey = cache->findAndRefUniqueResource(uniqueKey2); 560cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, wrappedCacheableViaKey); 561cb93a386Sopenharmony_ci GrGpuResource* wrappedUncacheableViaKey = cache->findAndRefUniqueResource(uniqueKey3); 562cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, wrappedUncacheableViaKey); 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci // Remove the extra refs we just added. 565cb93a386Sopenharmony_ci SkSafeUnref(wrappedCacheableViaKey); 566cb93a386Sopenharmony_ci SkSafeUnref(wrappedUncacheableViaKey); 567cb93a386Sopenharmony_ci 568cb93a386Sopenharmony_ci // Make sure sizes are as we expect 569cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 5 == cache->getResourceCount()); 570cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 571cb93a386Sopenharmony_ci wrappedCacheable->gpuMemorySize() + 572cb93a386Sopenharmony_ci wrappedUncacheable->gpuMemorySize() + 573cb93a386Sopenharmony_ci unbudgeted->gpuMemorySize() == 574cb93a386Sopenharmony_ci cache->getResourceBytes()); 575cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 576cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() == 577cb93a386Sopenharmony_ci cache->getBudgetedResourceBytes()); 578cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci // Our refs mean that the resources are non purgeable. 581cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 582cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 5 == cache->getResourceCount()); 583cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 584cb93a386Sopenharmony_ci wrappedCacheable->gpuMemorySize() + 585cb93a386Sopenharmony_ci wrappedUncacheable->gpuMemorySize() + 586cb93a386Sopenharmony_ci unbudgeted->gpuMemorySize() == 587cb93a386Sopenharmony_ci cache->getResourceBytes()); 588cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 589cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() == 590cb93a386Sopenharmony_ci cache->getBudgetedResourceBytes()); 591cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 592cb93a386Sopenharmony_ci 593cb93a386Sopenharmony_ci // Unreffing the cacheable wrapped resource with a unique key shouldn't free it right away. 594cb93a386Sopenharmony_ci // However, unreffing the uncacheable wrapped resource should free it. 595cb93a386Sopenharmony_ci wrappedCacheable->unref(); 596cb93a386Sopenharmony_ci wrappedUncacheable->unref(); 597cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 598cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 599cb93a386Sopenharmony_ci wrappedCacheable->gpuMemorySize() + 600cb93a386Sopenharmony_ci unbudgeted->gpuMemorySize() == 601cb93a386Sopenharmony_ci cache->getResourceBytes()); 602cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 603cb93a386Sopenharmony_ci 604cb93a386Sopenharmony_ci // Now try freeing the budgeted resources first 605cb93a386Sopenharmony_ci wrappedUncacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kNo); 606cb93a386Sopenharmony_ci unique->unref(); 607cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 11 == cache->getPurgeableBytes()); 608cb93a386Sopenharmony_ci // This will free 'unique' but not wrappedCacheable which has a key. That requires the key to be 609cb93a386Sopenharmony_ci // removed to be freed. 610cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 611cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_ci wrappedCacheableViaKey = cache->findAndRefUniqueResource(uniqueKey2); 614cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, wrappedCacheableViaKey); 615cb93a386Sopenharmony_ci if (wrappedCacheableViaKey) { 616cb93a386Sopenharmony_ci wrappedCacheableViaKey->resourcePriv().removeUniqueKey(); 617cb93a386Sopenharmony_ci wrappedCacheable->unref(); 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci // We shouldn't have to call purgeAllUnlocked as removing the key on a wrapped cacheable 620cb93a386Sopenharmony_ci // resource should immediately delete it. 621cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 622cb93a386Sopenharmony_ci 623cb93a386Sopenharmony_ci wrappedCacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes); 624cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrappedCacheable->gpuMemorySize() + 625cb93a386Sopenharmony_ci wrappedUncacheable->gpuMemorySize() + 626cb93a386Sopenharmony_ci unbudgeted->gpuMemorySize() == 627cb93a386Sopenharmony_ci cache->getResourceBytes()); 628cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 629cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes()); 630cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 631cb93a386Sopenharmony_ci 632cb93a386Sopenharmony_ci scratch->unref(); 633cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 10 == cache->getPurgeableBytes()); 634cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 635cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 636cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrappedCacheable->gpuMemorySize() + 637cb93a386Sopenharmony_ci wrappedUncacheable->gpuMemorySize() == 638cb93a386Sopenharmony_ci cache->getResourceBytes()); 639cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 640cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 641cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 642cb93a386Sopenharmony_ci 643cb93a386Sopenharmony_ci // Unreffing the wrapped resources (with no unique key) should free them right away. 644cb93a386Sopenharmony_ci wrappedUncacheable->unref(); 645cb93a386Sopenharmony_ci wrappedCacheable->unref(); 646cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 647cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 648cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 649cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 650cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 651cb93a386Sopenharmony_ci 652cb93a386Sopenharmony_ci unbudgeted->unref(); 653cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 654cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 655cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 656cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 657cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 658cb93a386Sopenharmony_ci} 659cb93a386Sopenharmony_ci 660cb93a386Sopenharmony_cistatic void test_unbudgeted(skiatest::Reporter* reporter) { 661cb93a386Sopenharmony_ci Mock mock(30000); 662cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 663cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 664cb93a386Sopenharmony_ci 665cb93a386Sopenharmony_ci GrUniqueKey uniqueKey; 666cb93a386Sopenharmony_ci make_unique_key<0>(&uniqueKey, 0); 667cb93a386Sopenharmony_ci 668cb93a386Sopenharmony_ci TestResource* scratch; 669cb93a386Sopenharmony_ci TestResource* unique; 670cb93a386Sopenharmony_ci TestResource* wrapped; 671cb93a386Sopenharmony_ci TestResource* unbudgeted; 672cb93a386Sopenharmony_ci 673cb93a386Sopenharmony_ci // A large uncached or wrapped resource shouldn't evict anything. 674cb93a386Sopenharmony_ci scratch = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 675cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty, 10); 676cb93a386Sopenharmony_ci 677cb93a386Sopenharmony_ci scratch->unref(); 678cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 679cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes()); 680cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 681cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes()); 682cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 10 == cache->getPurgeableBytes()); 683cb93a386Sopenharmony_ci 684cb93a386Sopenharmony_ci unique = new TestResource(gpu, SkBudgeted::kYes, 11); 685cb93a386Sopenharmony_ci unique->resourcePriv().setUniqueKey(uniqueKey); 686cb93a386Sopenharmony_ci unique->unref(); 687cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 688cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 689cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 690cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 691cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 692cb93a386Sopenharmony_ci 693cb93a386Sopenharmony_ci size_t large = 2 * cache->getResourceBytes(); 694cb93a386Sopenharmony_ci unbudgeted = new TestResource(gpu, SkBudgeted::kNo, large); 695cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 696cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes()); 697cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 698cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 699cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_ci unbudgeted->unref(); 702cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 703cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 704cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 705cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 706cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 707cb93a386Sopenharmony_ci 708cb93a386Sopenharmony_ci wrapped = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes, large); 709cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 710cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes()); 711cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 712cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 713cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 714cb93a386Sopenharmony_ci 715cb93a386Sopenharmony_ci wrapped->unref(); 716cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 717cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 718cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 719cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 720cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 723cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 724cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 725cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 726cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 727cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 728cb93a386Sopenharmony_ci} 729cb93a386Sopenharmony_ci 730cb93a386Sopenharmony_ci// This method can't be static because it needs to friended in GrGpuResource::CacheAccess. 731cb93a386Sopenharmony_civoid test_unbudgeted_to_scratch(skiatest::Reporter* reporter); 732cb93a386Sopenharmony_ci/*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) { 733cb93a386Sopenharmony_ci Mock mock(300); 734cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 735cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 736cb93a386Sopenharmony_ci 737cb93a386Sopenharmony_ci TestResource* resource = 738cb93a386Sopenharmony_ci TestResource::CreateScratch(gpu, SkBudgeted::kNo, TestResource::kA_SimulatedProperty); 739cb93a386Sopenharmony_ci GrScratchKey key; 740cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key); 741cb93a386Sopenharmony_ci 742cb93a386Sopenharmony_ci size_t size = resource->gpuMemorySize(); 743cb93a386Sopenharmony_ci for (int i = 0; i < 2; ++i) { 744cb93a386Sopenharmony_ci // Since this resource is unbudgeted, it should not be reachable as scratch. 745cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key); 746cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch()); 747cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, GrBudgetedType::kUnbudgetedUncacheable == 748cb93a386Sopenharmony_ci resource->resourcePriv().budgetedType()); 749cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->findAndRefScratchResource(key)); 750cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 751cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 752cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 753cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 754cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_ci // Once it is unrefed, it should become available as scratch. 757cb93a386Sopenharmony_ci resource->unref(); 758cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 759cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 760cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 761cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes()); 762cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, size == cache->getPurgeableBytes()); 763cb93a386Sopenharmony_ci resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key)); 764cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, resource); 765cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key); 766cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch()); 767cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 768cb93a386Sopenharmony_ci GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()); 769cb93a386Sopenharmony_ci 770cb93a386Sopenharmony_ci if (0 == i) { 771cb93a386Sopenharmony_ci // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try 772cb93a386Sopenharmony_ci // the above tests again. 773cb93a386Sopenharmony_ci resource->resourcePriv().makeUnbudgeted(); 774cb93a386Sopenharmony_ci } else { 775cb93a386Sopenharmony_ci // After the second time around, try removing the scratch key 776cb93a386Sopenharmony_ci resource->resourcePriv().removeScratchKey(); 777cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 778cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 779cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 780cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes()); 781cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 782cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid()); 783cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch()); 784cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 785cb93a386Sopenharmony_ci GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()); 786cb93a386Sopenharmony_ci 787cb93a386Sopenharmony_ci // now when it is unrefed it should die since it has no key. 788cb93a386Sopenharmony_ci resource->unref(); 789cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 790cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 791cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 792cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 793cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 794cb93a386Sopenharmony_ci } 795cb93a386Sopenharmony_ci } 796cb93a386Sopenharmony_ci} 797cb93a386Sopenharmony_ci 798cb93a386Sopenharmony_cistatic void test_duplicate_scratch_key(skiatest::Reporter* reporter) { 799cb93a386Sopenharmony_ci Mock mock(30000); 800cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 801cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 802cb93a386Sopenharmony_ci 803cb93a386Sopenharmony_ci // Create two resources that have the same scratch key. 804cb93a386Sopenharmony_ci TestResource* a = TestResource::CreateScratch(gpu, 805cb93a386Sopenharmony_ci SkBudgeted::kYes, 806cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty, 11); 807cb93a386Sopenharmony_ci TestResource* b = TestResource::CreateScratch(gpu, 808cb93a386Sopenharmony_ci SkBudgeted::kYes, 809cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty, 12); 810cb93a386Sopenharmony_ci GrScratchKey scratchKey1; 811cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1); 812cb93a386Sopenharmony_ci // Check for negative case consistency. (leaks upon test failure.) 813cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->findAndRefScratchResource(scratchKey1)); 814cb93a386Sopenharmony_ci 815cb93a386Sopenharmony_ci GrScratchKey scratchKey; 816cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 817cb93a386Sopenharmony_ci 818cb93a386Sopenharmony_ci // Scratch resources are registered with GrResourceCache just by existing. There are 2. 819cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 820cb93a386Sopenharmony_ci // As long as there are outstanding refs on the resources they will not be in the scratch map 821cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 822cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 823cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == 824cb93a386Sopenharmony_ci cache->getResourceBytes()); 825cb93a386Sopenharmony_ci 826cb93a386Sopenharmony_ci // Our refs mean that the resources are non purgeable. 827cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 828cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 829cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci // Unref but don't purge 832cb93a386Sopenharmony_ci a->unref(); 833cb93a386Sopenharmony_ci b->unref(); 834cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 835cb93a386Sopenharmony_ci // Since we removed the refs to the resources they will now be in the scratch map 836cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 837cb93a386Sopenharmony_ci 838cb93a386Sopenharmony_ci // Purge again. This time resources should be purgeable. 839cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 840cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 841cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 842cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 843cb93a386Sopenharmony_ci} 844cb93a386Sopenharmony_ci 845cb93a386Sopenharmony_cistatic void test_remove_scratch_key(skiatest::Reporter* reporter) { 846cb93a386Sopenharmony_ci Mock mock(30000); 847cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 848cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 849cb93a386Sopenharmony_ci 850cb93a386Sopenharmony_ci // Create two resources that have the same scratch key. 851cb93a386Sopenharmony_ci TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 852cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty); 853cb93a386Sopenharmony_ci TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 854cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty); 855cb93a386Sopenharmony_ci a->unref(); 856cb93a386Sopenharmony_ci b->unref(); 857cb93a386Sopenharmony_ci 858cb93a386Sopenharmony_ci GrScratchKey scratchKey; 859cb93a386Sopenharmony_ci // Ensure that scratch key lookup is correct for negative case. 860cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 861cb93a386Sopenharmony_ci // (following leaks upon test failure). 862cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->findAndRefScratchResource(scratchKey)); 863cb93a386Sopenharmony_ci 864cb93a386Sopenharmony_ci // Scratch resources are registered with GrResourceCache just by existing. There are 2. 865cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 866cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 867cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 868cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 869cb93a386Sopenharmony_ci 870cb93a386Sopenharmony_ci // Find the first resource and remove its scratch key 871cb93a386Sopenharmony_ci GrGpuResource* find = cache->findAndRefScratchResource(scratchKey); 872cb93a386Sopenharmony_ci find->resourcePriv().removeScratchKey(); 873cb93a386Sopenharmony_ci // It's still alive, but not cached by scratch key anymore 874cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 875cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));) 876cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 877cb93a386Sopenharmony_ci 878cb93a386Sopenharmony_ci // The cache should immediately delete it when it's unrefed since it isn't accessible. 879cb93a386Sopenharmony_ci find->unref(); 880cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 881cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));) 882cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 883cb93a386Sopenharmony_ci 884cb93a386Sopenharmony_ci // Repeat for the second resource. 885cb93a386Sopenharmony_ci find = cache->findAndRefScratchResource(scratchKey); 886cb93a386Sopenharmony_ci find->resourcePriv().removeScratchKey(); 887cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 888cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 889cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 890cb93a386Sopenharmony_ci 891cb93a386Sopenharmony_ci // Should be able to call this multiple times with no problem. 892cb93a386Sopenharmony_ci find->resourcePriv().removeScratchKey(); 893cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 894cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 895cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 896cb93a386Sopenharmony_ci 897cb93a386Sopenharmony_ci find->unref(); 898cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 899cb93a386Sopenharmony_ci SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 900cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 901cb93a386Sopenharmony_ci} 902cb93a386Sopenharmony_ci 903cb93a386Sopenharmony_cistatic void test_scratch_key_consistency(skiatest::Reporter* reporter) { 904cb93a386Sopenharmony_ci Mock mock(30000); 905cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 906cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 907cb93a386Sopenharmony_ci 908cb93a386Sopenharmony_ci // Create two resources that have the same scratch key. 909cb93a386Sopenharmony_ci TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 910cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty); 911cb93a386Sopenharmony_ci TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 912cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty); 913cb93a386Sopenharmony_ci a->unref(); 914cb93a386Sopenharmony_ci b->unref(); 915cb93a386Sopenharmony_ci 916cb93a386Sopenharmony_ci GrScratchKey scratchKey; 917cb93a386Sopenharmony_ci // Ensure that scratch key comparison and assignment is consistent. 918cb93a386Sopenharmony_ci GrScratchKey scratchKey1; 919cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1); 920cb93a386Sopenharmony_ci GrScratchKey scratchKey2; 921cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2); 922cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize()); 923cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2); 924cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1); 925cb93a386Sopenharmony_ci scratchKey = scratchKey1; 926cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize()); 927cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey1 == scratchKey); 928cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey == scratchKey1); 929cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey2 != scratchKey); 930cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey != scratchKey2); 931cb93a386Sopenharmony_ci scratchKey = scratchKey2; 932cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize()); 933cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey1 != scratchKey); 934cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey != scratchKey1); 935cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey2 == scratchKey); 936cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratchKey == scratchKey2); 937cb93a386Sopenharmony_ci 938cb93a386Sopenharmony_ci // Ensure that scratch key lookup is correct for negative case. 939cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 940cb93a386Sopenharmony_ci // (following leaks upon test failure). 941cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->findAndRefScratchResource(scratchKey)); 942cb93a386Sopenharmony_ci 943cb93a386Sopenharmony_ci // Find the first resource with a scratch key and a copy of a scratch key. 944cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 945cb93a386Sopenharmony_ci GrGpuResource* find = cache->findAndRefScratchResource(scratchKey); 946cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, find != nullptr); 947cb93a386Sopenharmony_ci find->unref(); 948cb93a386Sopenharmony_ci 949cb93a386Sopenharmony_ci scratchKey2 = scratchKey; 950cb93a386Sopenharmony_ci find = cache->findAndRefScratchResource(scratchKey2); 951cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, find != nullptr); 952cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, find == a || find == b); 953cb93a386Sopenharmony_ci 954cb93a386Sopenharmony_ci GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2); 955cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, find2 != nullptr); 956cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, find2 == a || find2 == b); 957cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, find2 != find); 958cb93a386Sopenharmony_ci find2->unref(); 959cb93a386Sopenharmony_ci find->unref(); 960cb93a386Sopenharmony_ci} 961cb93a386Sopenharmony_ci 962cb93a386Sopenharmony_cistatic void test_duplicate_unique_key(skiatest::Reporter* reporter) { 963cb93a386Sopenharmony_ci Mock mock(30000); 964cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 965cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 966cb93a386Sopenharmony_ci 967cb93a386Sopenharmony_ci GrUniqueKey key; 968cb93a386Sopenharmony_ci make_unique_key<0>(&key, 0); 969cb93a386Sopenharmony_ci 970cb93a386Sopenharmony_ci // Create two resources that we will attempt to register with the same unique key. 971cb93a386Sopenharmony_ci TestResource* a = new TestResource(gpu, SkBudgeted::kYes, 11); 972cb93a386Sopenharmony_ci 973cb93a386Sopenharmony_ci // Set key on resource a. 974cb93a386Sopenharmony_ci a->resourcePriv().setUniqueKey(key); 975cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key)); 976cb93a386Sopenharmony_ci a->unref(); 977cb93a386Sopenharmony_ci 978cb93a386Sopenharmony_ci // Make sure that redundantly setting a's key works. 979cb93a386Sopenharmony_ci a->resourcePriv().setUniqueKey(key); 980cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key)); 981cb93a386Sopenharmony_ci a->unref(); 982cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 983cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes()); 984cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 985cb93a386Sopenharmony_ci 986cb93a386Sopenharmony_ci // Create resource b and set the same key. It should replace a's unique key cache entry. 987cb93a386Sopenharmony_ci TestResource* b = new TestResource(gpu, SkBudgeted::kYes, 12); 988cb93a386Sopenharmony_ci b->resourcePriv().setUniqueKey(key); 989cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key)); 990cb93a386Sopenharmony_ci b->unref(); 991cb93a386Sopenharmony_ci 992cb93a386Sopenharmony_ci // Still have two resources because a is still reffed. 993cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 994cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes()); 995cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 996cb93a386Sopenharmony_ci 997cb93a386Sopenharmony_ci a->unref(); 998cb93a386Sopenharmony_ci // Now a should be gone. 999cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 1000cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 1001cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 1002cb93a386Sopenharmony_ci 1003cb93a386Sopenharmony_ci // Now replace b with c, but make sure c can start with one unique key and change it to b's key. 1004cb93a386Sopenharmony_ci // Also make b be unreffed when replacement occurs. 1005cb93a386Sopenharmony_ci b->unref(); 1006cb93a386Sopenharmony_ci TestResource* c = new TestResource(gpu, SkBudgeted::kYes, 13); 1007cb93a386Sopenharmony_ci GrUniqueKey differentKey; 1008cb93a386Sopenharmony_ci make_unique_key<0>(&differentKey, 1); 1009cb93a386Sopenharmony_ci c->resourcePriv().setUniqueKey(differentKey); 1010cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 1011cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes()); 1012cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1013cb93a386Sopenharmony_ci // c replaces b and b should be immediately purged. 1014cb93a386Sopenharmony_ci c->resourcePriv().setUniqueKey(key); 1015cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 1016cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 1017cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 1018cb93a386Sopenharmony_ci 1019cb93a386Sopenharmony_ci // c shouldn't be purged because it is ref'ed. 1020cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 1021cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 1022cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 1023cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 1024cb93a386Sopenharmony_ci 1025cb93a386Sopenharmony_ci // Drop the ref on c, it should be kept alive because it has a unique key. 1026cb93a386Sopenharmony_ci c->unref(); 1027cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 1028cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 1029cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 1030cb93a386Sopenharmony_ci 1031cb93a386Sopenharmony_ci // Verify that we can find c, then remove its unique key. It should get purged immediately. 1032cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key)); 1033cb93a386Sopenharmony_ci c->resourcePriv().removeUniqueKey(); 1034cb93a386Sopenharmony_ci c->unref(); 1035cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1036cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 1037cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 1038cb93a386Sopenharmony_ci 1039cb93a386Sopenharmony_ci { 1040cb93a386Sopenharmony_ci GrUniqueKey key2; 1041cb93a386Sopenharmony_ci make_unique_key<0>(&key2, 0); 1042cb93a386Sopenharmony_ci sk_sp<TestResource> d(new TestResource(gpu)); 1043cb93a386Sopenharmony_ci int foo = 4132; 1044cb93a386Sopenharmony_ci key2.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo))); 1045cb93a386Sopenharmony_ci d->resourcePriv().setUniqueKey(key2); 1046cb93a386Sopenharmony_ci } 1047cb93a386Sopenharmony_ci 1048cb93a386Sopenharmony_ci GrUniqueKey key3; 1049cb93a386Sopenharmony_ci make_unique_key<0>(&key3, 0); 1050cb93a386Sopenharmony_ci sk_sp<GrGpuResource> d2(cache->findAndRefUniqueResource(key3)); 1051cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, *(int*) d2->getUniqueKey().getCustomData()->data() == 4132); 1052cb93a386Sopenharmony_ci} 1053cb93a386Sopenharmony_ci 1054cb93a386Sopenharmony_cistatic void test_purge_invalidated(skiatest::Reporter* reporter) { 1055cb93a386Sopenharmony_ci Mock mock(30000); 1056cb93a386Sopenharmony_ci auto dContext = mock.dContext(); 1057cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1058cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1059cb93a386Sopenharmony_ci 1060cb93a386Sopenharmony_ci GrUniqueKey key1, key2, key3; 1061cb93a386Sopenharmony_ci make_unique_key<0>(&key1, 1); 1062cb93a386Sopenharmony_ci make_unique_key<0>(&key2, 2); 1063cb93a386Sopenharmony_ci make_unique_key<0>(&key3, 3); 1064cb93a386Sopenharmony_ci 1065cb93a386Sopenharmony_ci // Add three resources to the cache. Only c is usable as scratch. 1066cb93a386Sopenharmony_ci TestResource* a = new TestResource(gpu); 1067cb93a386Sopenharmony_ci TestResource* b = new TestResource(gpu); 1068cb93a386Sopenharmony_ci TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 1069cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty); 1070cb93a386Sopenharmony_ci a->resourcePriv().setUniqueKey(key1); 1071cb93a386Sopenharmony_ci b->resourcePriv().setUniqueKey(key2); 1072cb93a386Sopenharmony_ci c->resourcePriv().setUniqueKey(key3); 1073cb93a386Sopenharmony_ci a->unref(); 1074cb93a386Sopenharmony_ci // hold b until *after* the message is sent. 1075cb93a386Sopenharmony_ci c->unref(); 1076cb93a386Sopenharmony_ci 1077cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1)); 1078cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2)); 1079cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3)); 1080cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive()); 1081cb93a386Sopenharmony_ci 1082cb93a386Sopenharmony_ci typedef GrUniqueKeyInvalidatedMessage Msg; 1083cb93a386Sopenharmony_ci typedef SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t> Bus; 1084cb93a386Sopenharmony_ci 1085cb93a386Sopenharmony_ci // Invalidate two of the three, they should be purged and no longer accessible via their keys. 1086cb93a386Sopenharmony_ci Bus::Post(Msg(key1, dContext->priv().contextID())); 1087cb93a386Sopenharmony_ci Bus::Post(Msg(key2, dContext->priv().contextID())); 1088cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 1089cb93a386Sopenharmony_ci // a should be deleted now, but we still have a ref on b. 1090cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 1091cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2)); 1092cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1093cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3)); 1094cb93a386Sopenharmony_ci 1095cb93a386Sopenharmony_ci // Invalidate the third. 1096cb93a386Sopenharmony_ci Bus::Post(Msg(key3, dContext->priv().contextID())); 1097cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 1098cb93a386Sopenharmony_ci // we still have a ref on b, c should be recycled as scratch. 1099cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1100cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3)); 1101cb93a386Sopenharmony_ci 1102cb93a386Sopenharmony_ci // make b purgeable. It should be immediately deleted since it has no key. 1103cb93a386Sopenharmony_ci b->unref(); 1104cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 1105cb93a386Sopenharmony_ci 1106cb93a386Sopenharmony_ci // Make sure we actually get to c via it's scratch key, before we say goodbye. 1107cb93a386Sopenharmony_ci GrScratchKey scratchKey; 1108cb93a386Sopenharmony_ci TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 1109cb93a386Sopenharmony_ci GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey); 1110cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, scratch == c); 1111cb93a386Sopenharmony_ci SkSafeUnref(scratch); 1112cb93a386Sopenharmony_ci 1113cb93a386Sopenharmony_ci // Get rid of c. 1114cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 1115cb93a386Sopenharmony_ci scratch = cache->findAndRefScratchResource(scratchKey); 1116cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 1117cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1118cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 1119cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !scratch); 1120cb93a386Sopenharmony_ci SkSafeUnref(scratch); 1121cb93a386Sopenharmony_ci} 1122cb93a386Sopenharmony_ci 1123cb93a386Sopenharmony_cistatic void test_cache_chained_purge(skiatest::Reporter* reporter) { 1124cb93a386Sopenharmony_ci Mock mock(30000); 1125cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1126cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1127cb93a386Sopenharmony_ci 1128cb93a386Sopenharmony_ci GrUniqueKey key1, key2; 1129cb93a386Sopenharmony_ci make_unique_key<0>(&key1, 1); 1130cb93a386Sopenharmony_ci make_unique_key<0>(&key2, 2); 1131cb93a386Sopenharmony_ci 1132cb93a386Sopenharmony_ci sk_sp<TestResource> a(new TestResource(gpu)); 1133cb93a386Sopenharmony_ci sk_sp<TestResource> b(new TestResource(gpu)); 1134cb93a386Sopenharmony_ci a->resourcePriv().setUniqueKey(key1); 1135cb93a386Sopenharmony_ci b->resourcePriv().setUniqueKey(key2); 1136cb93a386Sopenharmony_ci 1137cb93a386Sopenharmony_ci // Make a cycle 1138cb93a386Sopenharmony_ci a->setUnrefWhenDestroyed(b); 1139cb93a386Sopenharmony_ci b->setUnrefWhenDestroyed(a); 1140cb93a386Sopenharmony_ci 1141cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1142cb93a386Sopenharmony_ci 1143cb93a386Sopenharmony_ci TestResource* unownedA = a.release(); 1144cb93a386Sopenharmony_ci unownedA->unref(); 1145cb93a386Sopenharmony_ci b.reset(); 1146cb93a386Sopenharmony_ci 1147cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1148cb93a386Sopenharmony_ci 1149cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 1150cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1151cb93a386Sopenharmony_ci 1152cb93a386Sopenharmony_ci // Break the cycle 1153cb93a386Sopenharmony_ci unownedA->setUnrefWhenDestroyed(nullptr); 1154cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1155cb93a386Sopenharmony_ci 1156cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 1157cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 1158cb93a386Sopenharmony_ci} 1159cb93a386Sopenharmony_ci 1160cb93a386Sopenharmony_cistatic void test_timestamp_wrap(skiatest::Reporter* reporter) { 1161cb93a386Sopenharmony_ci static const int kCount = 50; 1162cb93a386Sopenharmony_ci static const int kLockedFreq = 8; 1163cb93a386Sopenharmony_ci static const int kBudgetSize = 0; // always over budget 1164cb93a386Sopenharmony_ci 1165cb93a386Sopenharmony_ci SkRandom random; 1166cb93a386Sopenharmony_ci 1167cb93a386Sopenharmony_ci // Run the test 2*kCount times; 1168cb93a386Sopenharmony_ci for (int i = 0; i < 2 * kCount; ++i ) { 1169cb93a386Sopenharmony_ci Mock mock(kBudgetSize); 1170cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1171cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1172cb93a386Sopenharmony_ci 1173cb93a386Sopenharmony_ci // Pick a random number of resources to add before the timestamp will wrap. 1174cb93a386Sopenharmony_ci cache->changeTimestamp(UINT32_MAX - random.nextULessThan(kCount + 1)); 1175cb93a386Sopenharmony_ci 1176cb93a386Sopenharmony_ci static const int kNumToPurge = kCount; 1177cb93a386Sopenharmony_ci 1178cb93a386Sopenharmony_ci SkTDArray<int> shouldPurgeIdxs; 1179cb93a386Sopenharmony_ci int purgeableCnt = 0; 1180cb93a386Sopenharmony_ci SkTDArray<GrGpuResource*> resourcesToUnref; 1181cb93a386Sopenharmony_ci 1182cb93a386Sopenharmony_ci // Add kCount resources, holding onto resources at random so we have a mix of purgeable and 1183cb93a386Sopenharmony_ci // unpurgeable resources. 1184cb93a386Sopenharmony_ci for (int j = 0; j < kCount; ++j) { 1185cb93a386Sopenharmony_ci GrUniqueKey key; 1186cb93a386Sopenharmony_ci make_unique_key<0>(&key, j); 1187cb93a386Sopenharmony_ci 1188cb93a386Sopenharmony_ci TestResource* r = new TestResource(gpu); 1189cb93a386Sopenharmony_ci r->resourcePriv().setUniqueKey(key); 1190cb93a386Sopenharmony_ci if (random.nextU() % kLockedFreq) { 1191cb93a386Sopenharmony_ci // Make this is purgeable. 1192cb93a386Sopenharmony_ci r->unref(); 1193cb93a386Sopenharmony_ci ++purgeableCnt; 1194cb93a386Sopenharmony_ci if (purgeableCnt <= kNumToPurge) { 1195cb93a386Sopenharmony_ci *shouldPurgeIdxs.append() = j; 1196cb93a386Sopenharmony_ci } 1197cb93a386Sopenharmony_ci } else { 1198cb93a386Sopenharmony_ci *resourcesToUnref.append() = r; 1199cb93a386Sopenharmony_ci } 1200cb93a386Sopenharmony_ci } 1201cb93a386Sopenharmony_ci 1202cb93a386Sopenharmony_ci // Verify that the correct resources were purged. 1203cb93a386Sopenharmony_ci int currShouldPurgeIdx = 0; 1204cb93a386Sopenharmony_ci for (int j = 0; j < kCount; ++j) { 1205cb93a386Sopenharmony_ci GrUniqueKey key; 1206cb93a386Sopenharmony_ci make_unique_key<0>(&key, j); 1207cb93a386Sopenharmony_ci GrGpuResource* res = cache->findAndRefUniqueResource(key); 1208cb93a386Sopenharmony_ci if (currShouldPurgeIdx < shouldPurgeIdxs.count() && 1209cb93a386Sopenharmony_ci shouldPurgeIdxs[currShouldPurgeIdx] == j) { 1210cb93a386Sopenharmony_ci ++currShouldPurgeIdx; 1211cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, nullptr == res); 1212cb93a386Sopenharmony_ci } else { 1213cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, nullptr != res); 1214cb93a386Sopenharmony_ci } 1215cb93a386Sopenharmony_ci SkSafeUnref(res); 1216cb93a386Sopenharmony_ci } 1217cb93a386Sopenharmony_ci 1218cb93a386Sopenharmony_ci for (int j = 0; j < resourcesToUnref.count(); ++j) { 1219cb93a386Sopenharmony_ci resourcesToUnref[j]->unref(); 1220cb93a386Sopenharmony_ci } 1221cb93a386Sopenharmony_ci } 1222cb93a386Sopenharmony_ci} 1223cb93a386Sopenharmony_ci 1224cb93a386Sopenharmony_cistatic void test_time_purge(skiatest::Reporter* reporter) { 1225cb93a386Sopenharmony_ci Mock mock(1000000); 1226cb93a386Sopenharmony_ci auto dContext = mock.dContext(); 1227cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1228cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1229cb93a386Sopenharmony_ci 1230cb93a386Sopenharmony_ci static constexpr int kCnts[] = {1, 10, 1024}; 1231cb93a386Sopenharmony_ci auto nowish = []() { 1232cb93a386Sopenharmony_ci // We sleep so that we ensure we get a value that is greater than the last call to 1233cb93a386Sopenharmony_ci // GrStdSteadyClock::now(). 1234cb93a386Sopenharmony_ci std::this_thread::sleep_for(GrStdSteadyClock::duration(5)); 1235cb93a386Sopenharmony_ci auto result = GrStdSteadyClock::now(); 1236cb93a386Sopenharmony_ci // Also sleep afterwards so we don't get this value again. 1237cb93a386Sopenharmony_ci std::this_thread::sleep_for(GrStdSteadyClock::duration(5)); 1238cb93a386Sopenharmony_ci return result; 1239cb93a386Sopenharmony_ci }; 1240cb93a386Sopenharmony_ci 1241cb93a386Sopenharmony_ci for (int cnt : kCnts) { 1242cb93a386Sopenharmony_ci std::unique_ptr<GrStdSteadyClock::time_point[]> timeStamps( 1243cb93a386Sopenharmony_ci new GrStdSteadyClock::time_point[cnt]); 1244cb93a386Sopenharmony_ci { 1245cb93a386Sopenharmony_ci // Insert resources and get time points between each addition. 1246cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 1247cb93a386Sopenharmony_ci TestResource* r = new TestResource(gpu); 1248cb93a386Sopenharmony_ci GrUniqueKey k; 1249cb93a386Sopenharmony_ci make_unique_key<1>(&k, i); 1250cb93a386Sopenharmony_ci r->resourcePriv().setUniqueKey(k); 1251cb93a386Sopenharmony_ci r->unref(); 1252cb93a386Sopenharmony_ci timeStamps.get()[i] = nowish(); 1253cb93a386Sopenharmony_ci } 1254cb93a386Sopenharmony_ci 1255cb93a386Sopenharmony_ci // Purge based on the time points between resource additions. Each purge should remove 1256cb93a386Sopenharmony_ci // the oldest resource. 1257cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 1258cb93a386Sopenharmony_ci cache->purgeResourcesNotUsedSince(timeStamps[i]); 1259cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt - i - 1 == cache->getResourceCount()); 1260cb93a386Sopenharmony_ci for (int j = 0; j < i; ++j) { 1261cb93a386Sopenharmony_ci GrUniqueKey k; 1262cb93a386Sopenharmony_ci make_unique_key<1>(&k, j); 1263cb93a386Sopenharmony_ci GrGpuResource* r = cache->findAndRefUniqueResource(k); 1264cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !SkToBool(r)); 1265cb93a386Sopenharmony_ci SkSafeUnref(r); 1266cb93a386Sopenharmony_ci } 1267cb93a386Sopenharmony_ci } 1268cb93a386Sopenharmony_ci 1269cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1270cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 1271cb93a386Sopenharmony_ci } 1272cb93a386Sopenharmony_ci 1273cb93a386Sopenharmony_ci // Do a similar test but where we leave refs on some resources to prevent them from being 1274cb93a386Sopenharmony_ci // purged. 1275cb93a386Sopenharmony_ci { 1276cb93a386Sopenharmony_ci std::unique_ptr<GrGpuResource* []> refedResources(new GrGpuResource*[cnt / 2]); 1277cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 1278cb93a386Sopenharmony_ci TestResource* r = new TestResource(gpu); 1279cb93a386Sopenharmony_ci GrUniqueKey k; 1280cb93a386Sopenharmony_ci make_unique_key<1>(&k, i); 1281cb93a386Sopenharmony_ci r->resourcePriv().setUniqueKey(k); 1282cb93a386Sopenharmony_ci // Leave a ref on every other resource, beginning with the first. 1283cb93a386Sopenharmony_ci if (SkToBool(i & 0x1)) { 1284cb93a386Sopenharmony_ci refedResources.get()[i / 2] = r; 1285cb93a386Sopenharmony_ci } else { 1286cb93a386Sopenharmony_ci r->unref(); 1287cb93a386Sopenharmony_ci } 1288cb93a386Sopenharmony_ci timeStamps.get()[i] = nowish(); 1289cb93a386Sopenharmony_ci } 1290cb93a386Sopenharmony_ci 1291cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 1292cb93a386Sopenharmony_ci // Should get a resource purged every other frame. 1293cb93a386Sopenharmony_ci cache->purgeResourcesNotUsedSince(timeStamps[i]); 1294cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt - i / 2 - 1 == cache->getResourceCount()); 1295cb93a386Sopenharmony_ci } 1296cb93a386Sopenharmony_ci 1297cb93a386Sopenharmony_ci // Unref all the resources that we kept refs on in the first loop. 1298cb93a386Sopenharmony_ci for (int i = 0; i < (cnt / 2); ++i) { 1299cb93a386Sopenharmony_ci refedResources.get()[i]->unref(); 1300cb93a386Sopenharmony_ci cache->purgeResourcesNotUsedSince(nowish()); 1301cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt / 2 - i - 1 == cache->getResourceCount()); 1302cb93a386Sopenharmony_ci } 1303cb93a386Sopenharmony_ci 1304cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 1305cb93a386Sopenharmony_ci } 1306cb93a386Sopenharmony_ci 1307cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1308cb93a386Sopenharmony_ci 1309cb93a386Sopenharmony_ci // Do a similar test where we alternate adding scratch and uniquely keyed resources, but 1310cb93a386Sopenharmony_ci // then purge old scratch resources. 1311cb93a386Sopenharmony_ci { 1312cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 1313cb93a386Sopenharmony_ci const bool isScratch = (i % 2 == 0); 1314cb93a386Sopenharmony_ci const SkBudgeted budgeted = SkBudgeted::kYes; 1315cb93a386Sopenharmony_ci const TestResource::SimulatedProperty property = TestResource::kA_SimulatedProperty; 1316cb93a386Sopenharmony_ci TestResource* r = isScratch ? TestResource::CreateScratch(gpu, budgeted, property) 1317cb93a386Sopenharmony_ci : new TestResource(gpu, budgeted, property); 1318cb93a386Sopenharmony_ci if (!isScratch) { 1319cb93a386Sopenharmony_ci GrUniqueKey k; 1320cb93a386Sopenharmony_ci make_unique_key<1>(&k, i); 1321cb93a386Sopenharmony_ci r->resourcePriv().setUniqueKey(k); 1322cb93a386Sopenharmony_ci } 1323cb93a386Sopenharmony_ci r->unref(); 1324cb93a386Sopenharmony_ci timeStamps.get()[i] = nowish(); 1325cb93a386Sopenharmony_ci } 1326cb93a386Sopenharmony_ci 1327cb93a386Sopenharmony_ci for (int i = 0; i < cnt; ++i) { 1328cb93a386Sopenharmony_ci // Should get a resource purged every other frame, since the uniquely keyed 1329cb93a386Sopenharmony_ci // resources will not be considered. 1330cb93a386Sopenharmony_ci cache->purgeResourcesNotUsedSince(timeStamps[i], /*scratchResourcesOnly=*/true); 1331cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cnt - i / 2 - 1 == cache->getResourceCount()); 1332cb93a386Sopenharmony_ci } 1333cb93a386Sopenharmony_ci // Unref remaining resources 1334cb93a386Sopenharmony_ci cache->purgeResourcesNotUsedSince(nowish()); 1335cb93a386Sopenharmony_ci } 1336cb93a386Sopenharmony_ci 1337cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1338cb93a386Sopenharmony_ci 1339cb93a386Sopenharmony_ci // Verify that calling flush() on a context with nothing to do will not trigger resource 1340cb93a386Sopenharmony_ci // eviction 1341cb93a386Sopenharmony_ci dContext->flushAndSubmit(); 1342cb93a386Sopenharmony_ci for (int i = 0; i < 10; ++i) { 1343cb93a386Sopenharmony_ci TestResource* r = new TestResource(gpu); 1344cb93a386Sopenharmony_ci GrUniqueKey k; 1345cb93a386Sopenharmony_ci make_unique_key<1>(&k, i); 1346cb93a386Sopenharmony_ci r->resourcePriv().setUniqueKey(k); 1347cb93a386Sopenharmony_ci r->unref(); 1348cb93a386Sopenharmony_ci } 1349cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 10 == cache->getResourceCount()); 1350cb93a386Sopenharmony_ci dContext->flushAndSubmit(); 1351cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 10 == cache->getResourceCount()); 1352cb93a386Sopenharmony_ci cache->purgeResourcesNotUsedSince(nowish()); 1353cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1354cb93a386Sopenharmony_ci } 1355cb93a386Sopenharmony_ci} 1356cb93a386Sopenharmony_ci 1357cb93a386Sopenharmony_cistatic void test_partial_purge(skiatest::Reporter* reporter) { 1358cb93a386Sopenharmony_ci Mock mock(100); 1359cb93a386Sopenharmony_ci auto dContext = mock.dContext(); 1360cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1361cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1362cb93a386Sopenharmony_ci 1363cb93a386Sopenharmony_ci enum TestsCase { 1364cb93a386Sopenharmony_ci kOnlyScratch_TestCase = 0, 1365cb93a386Sopenharmony_ci kPartialScratch_TestCase = 1, 1366cb93a386Sopenharmony_ci kAllScratch_TestCase = 2, 1367cb93a386Sopenharmony_ci kPartial_TestCase = 3, 1368cb93a386Sopenharmony_ci kAll_TestCase = 4, 1369cb93a386Sopenharmony_ci kNone_TestCase = 5, 1370cb93a386Sopenharmony_ci kEndTests_TestCase = kNone_TestCase + 1 1371cb93a386Sopenharmony_ci }; 1372cb93a386Sopenharmony_ci 1373cb93a386Sopenharmony_ci for (int testCase = 0; testCase < kEndTests_TestCase; testCase++) { 1374cb93a386Sopenharmony_ci 1375cb93a386Sopenharmony_ci GrUniqueKey key1, key2, key3; 1376cb93a386Sopenharmony_ci make_unique_key<0>(&key1, 1); 1377cb93a386Sopenharmony_ci make_unique_key<0>(&key2, 2); 1378cb93a386Sopenharmony_ci make_unique_key<0>(&key3, 3); 1379cb93a386Sopenharmony_ci 1380cb93a386Sopenharmony_ci // Add three unique resources to the cache. 1381cb93a386Sopenharmony_ci TestResource *unique1 = new TestResource(gpu, SkBudgeted::kYes, 10); 1382cb93a386Sopenharmony_ci TestResource *unique2 = new TestResource(gpu, SkBudgeted::kYes, 11); 1383cb93a386Sopenharmony_ci TestResource *unique3 = new TestResource(gpu, SkBudgeted::kYes, 12); 1384cb93a386Sopenharmony_ci 1385cb93a386Sopenharmony_ci unique1->resourcePriv().setUniqueKey(key1); 1386cb93a386Sopenharmony_ci unique2->resourcePriv().setUniqueKey(key2); 1387cb93a386Sopenharmony_ci unique3->resourcePriv().setUniqueKey(key3); 1388cb93a386Sopenharmony_ci 1389cb93a386Sopenharmony_ci // Add two scratch resources to the cache. 1390cb93a386Sopenharmony_ci TestResource *scratch1 = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 1391cb93a386Sopenharmony_ci TestResource::kA_SimulatedProperty, 1392cb93a386Sopenharmony_ci 13); 1393cb93a386Sopenharmony_ci TestResource *scratch2 = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 1394cb93a386Sopenharmony_ci TestResource::kB_SimulatedProperty, 1395cb93a386Sopenharmony_ci 14); 1396cb93a386Sopenharmony_ci 1397cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount()); 1398cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes()); 1399cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 1400cb93a386Sopenharmony_ci 1401cb93a386Sopenharmony_ci // Add resources to the purgeable queue 1402cb93a386Sopenharmony_ci unique1->unref(); 1403cb93a386Sopenharmony_ci scratch1->unref(); 1404cb93a386Sopenharmony_ci unique2->unref(); 1405cb93a386Sopenharmony_ci scratch2->unref(); 1406cb93a386Sopenharmony_ci unique3->unref(); 1407cb93a386Sopenharmony_ci 1408cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount()); 1409cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes()); 1410cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes()); 1411cb93a386Sopenharmony_ci 1412cb93a386Sopenharmony_ci switch(testCase) { 1413cb93a386Sopenharmony_ci case kOnlyScratch_TestCase: { 1414cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(14, true); 1415cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount()); 1416cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 33 == cache->getBudgetedResourceBytes()); 1417cb93a386Sopenharmony_ci break; 1418cb93a386Sopenharmony_ci } 1419cb93a386Sopenharmony_ci case kPartialScratch_TestCase: { 1420cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(3, true); 1421cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 4 == cache->getBudgetedResourceCount()); 1422cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 47 == cache->getBudgetedResourceBytes()); 1423cb93a386Sopenharmony_ci break; 1424cb93a386Sopenharmony_ci } 1425cb93a386Sopenharmony_ci case kAllScratch_TestCase: { 1426cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(50, true); 1427cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 1428cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 1429cb93a386Sopenharmony_ci break; 1430cb93a386Sopenharmony_ci } 1431cb93a386Sopenharmony_ci case kPartial_TestCase: { 1432cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(13, false); 1433cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount()); 1434cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 37 == cache->getBudgetedResourceBytes()); 1435cb93a386Sopenharmony_ci break; 1436cb93a386Sopenharmony_ci } 1437cb93a386Sopenharmony_ci case kAll_TestCase: { 1438cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(50, false); 1439cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 1440cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 1441cb93a386Sopenharmony_ci break; 1442cb93a386Sopenharmony_ci } 1443cb93a386Sopenharmony_ci case kNone_TestCase: { 1444cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(0, true); 1445cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(0, false); 1446cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount()); 1447cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes()); 1448cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes()); 1449cb93a386Sopenharmony_ci break; 1450cb93a386Sopenharmony_ci } 1451cb93a386Sopenharmony_ci } 1452cb93a386Sopenharmony_ci 1453cb93a386Sopenharmony_ci // ensure all are purged before the next 1454cb93a386Sopenharmony_ci dContext->priv().getResourceCache()->purgeUnlockedResources(); 1455cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 1456cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 1457cb93a386Sopenharmony_ci 1458cb93a386Sopenharmony_ci } 1459cb93a386Sopenharmony_ci} 1460cb93a386Sopenharmony_ci 1461cb93a386Sopenharmony_cistatic void test_custom_data(skiatest::Reporter* reporter) { 1462cb93a386Sopenharmony_ci GrUniqueKey key1, key2; 1463cb93a386Sopenharmony_ci make_unique_key<0>(&key1, 1); 1464cb93a386Sopenharmony_ci make_unique_key<0>(&key2, 2); 1465cb93a386Sopenharmony_ci int foo = 4132; 1466cb93a386Sopenharmony_ci key1.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo))); 1467cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, *(int*) key1.getCustomData()->data() == 4132); 1468cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, key2.getCustomData() == nullptr); 1469cb93a386Sopenharmony_ci 1470cb93a386Sopenharmony_ci // Test that copying a key also takes a ref on its custom data. 1471cb93a386Sopenharmony_ci GrUniqueKey key3 = key1; 1472cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, *(int*) key3.getCustomData()->data() == 4132); 1473cb93a386Sopenharmony_ci} 1474cb93a386Sopenharmony_ci 1475cb93a386Sopenharmony_cistatic void test_abandoned(skiatest::Reporter* reporter) { 1476cb93a386Sopenharmony_ci Mock mock(300); 1477cb93a386Sopenharmony_ci auto dContext = mock.dContext(); 1478cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1479cb93a386Sopenharmony_ci 1480cb93a386Sopenharmony_ci sk_sp<GrGpuResource> resource(new TestResource(gpu)); 1481cb93a386Sopenharmony_ci dContext->abandonContext(); 1482cb93a386Sopenharmony_ci 1483cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, resource->wasDestroyed()); 1484cb93a386Sopenharmony_ci 1485cb93a386Sopenharmony_ci // Call all the public methods on resource in the abandoned state. They shouldn't crash. 1486cb93a386Sopenharmony_ci 1487cb93a386Sopenharmony_ci resource->uniqueID(); 1488cb93a386Sopenharmony_ci resource->getUniqueKey(); 1489cb93a386Sopenharmony_ci resource->wasDestroyed(); 1490cb93a386Sopenharmony_ci resource->gpuMemorySize(); 1491cb93a386Sopenharmony_ci resource->getContext(); 1492cb93a386Sopenharmony_ci 1493cb93a386Sopenharmony_ci resource->resourcePriv().getScratchKey(); 1494cb93a386Sopenharmony_ci resource->resourcePriv().budgetedType(); 1495cb93a386Sopenharmony_ci resource->resourcePriv().makeBudgeted(); 1496cb93a386Sopenharmony_ci resource->resourcePriv().makeUnbudgeted(); 1497cb93a386Sopenharmony_ci resource->resourcePriv().removeScratchKey(); 1498cb93a386Sopenharmony_ci GrUniqueKey key; 1499cb93a386Sopenharmony_ci make_unique_key<0>(&key, 1); 1500cb93a386Sopenharmony_ci resource->resourcePriv().setUniqueKey(key); 1501cb93a386Sopenharmony_ci resource->resourcePriv().removeUniqueKey(); 1502cb93a386Sopenharmony_ci} 1503cb93a386Sopenharmony_ci 1504cb93a386Sopenharmony_cistatic void test_tags(skiatest::Reporter* reporter) { 1505cb93a386Sopenharmony_ci#ifdef SK_DEBUG 1506cb93a386Sopenharmony_ci // We will insert 1 resource with tag "tag1", 2 with "tag2", and so on, up through kLastTagIdx. 1507cb93a386Sopenharmony_ci static constexpr int kLastTagIdx = 10; 1508cb93a386Sopenharmony_ci static constexpr int kNumResources = kLastTagIdx * (kLastTagIdx + 1) / 2; 1509cb93a386Sopenharmony_ci 1510cb93a386Sopenharmony_ci Mock mock(kNumResources * TestResource::kDefaultSize); 1511cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1512cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1513cb93a386Sopenharmony_ci 1514cb93a386Sopenharmony_ci // tag strings are expected to be long lived 1515cb93a386Sopenharmony_ci std::vector<SkString> tagStrings; 1516cb93a386Sopenharmony_ci 1517cb93a386Sopenharmony_ci SkString tagStr; 1518cb93a386Sopenharmony_ci int tagIdx = 0; 1519cb93a386Sopenharmony_ci int currTagCnt = 0; 1520cb93a386Sopenharmony_ci 1521cb93a386Sopenharmony_ci for (int i = 0; i < kNumResources; ++i, ++currTagCnt) { 1522cb93a386Sopenharmony_ci 1523cb93a386Sopenharmony_ci sk_sp<GrGpuResource> resource(new TestResource(gpu)); 1524cb93a386Sopenharmony_ci GrUniqueKey key; 1525cb93a386Sopenharmony_ci if (currTagCnt == tagIdx) { 1526cb93a386Sopenharmony_ci tagIdx += 1; 1527cb93a386Sopenharmony_ci currTagCnt = 0; 1528cb93a386Sopenharmony_ci tagStr.printf("tag%d", tagIdx); 1529cb93a386Sopenharmony_ci tagStrings.emplace_back(tagStr); 1530cb93a386Sopenharmony_ci } 1531cb93a386Sopenharmony_ci make_unique_key<1>(&key, i, tagStrings.back().c_str()); 1532cb93a386Sopenharmony_ci resource->resourcePriv().setUniqueKey(key); 1533cb93a386Sopenharmony_ci } 1534cb93a386Sopenharmony_ci SkASSERT(kLastTagIdx == tagIdx); 1535cb93a386Sopenharmony_ci SkASSERT(currTagCnt == kLastTagIdx); 1536cb93a386Sopenharmony_ci 1537cb93a386Sopenharmony_ci // Test i = 0 to exercise unused tag string. 1538cb93a386Sopenharmony_ci for (int i = 0; i <= kLastTagIdx; ++i) { 1539cb93a386Sopenharmony_ci tagStr.printf("tag%d", i); 1540cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache->countUniqueKeysWithTag(tagStr.c_str()) == i); 1541cb93a386Sopenharmony_ci } 1542cb93a386Sopenharmony_ci#endif 1543cb93a386Sopenharmony_ci} 1544cb93a386Sopenharmony_ci 1545cb93a386Sopenharmony_cistatic void test_free_texture_messages(skiatest::Reporter* reporter) { 1546cb93a386Sopenharmony_ci Mock mock(30000); 1547cb93a386Sopenharmony_ci auto dContext = mock.dContext(); 1548cb93a386Sopenharmony_ci GrResourceCache* cache = mock.cache(); 1549cb93a386Sopenharmony_ci GrGpu* gpu = mock.gpu(); 1550cb93a386Sopenharmony_ci 1551cb93a386Sopenharmony_ci GrBackendTexture backends[3]; 1552cb93a386Sopenharmony_ci GrTexture* wrapped[3]; 1553cb93a386Sopenharmony_ci int freed[3] = { 0, 0, 0 }; 1554cb93a386Sopenharmony_ci 1555cb93a386Sopenharmony_ci auto releaseProc = [](void* ctx) { 1556cb93a386Sopenharmony_ci int* index = (int*) ctx; 1557cb93a386Sopenharmony_ci *index = 1; 1558cb93a386Sopenharmony_ci }; 1559cb93a386Sopenharmony_ci 1560cb93a386Sopenharmony_ci for (int i = 0; i < 3; ++i) { 1561cb93a386Sopenharmony_ci backends[i] = dContext->createBackendTexture(16, 16, SkColorType::kRGBA_8888_SkColorType, 1562cb93a386Sopenharmony_ci GrMipmapped::kNo, GrRenderable::kNo); 1563cb93a386Sopenharmony_ci wrapped[i] = gpu->wrapBackendTexture(backends[i], 1564cb93a386Sopenharmony_ci GrWrapOwnership::kBorrow_GrWrapOwnership, 1565cb93a386Sopenharmony_ci (i < 2) ? GrWrapCacheable::kYes : GrWrapCacheable::kNo, 1566cb93a386Sopenharmony_ci GrIOType::kRead_GrIOType) 1567cb93a386Sopenharmony_ci .release(); 1568cb93a386Sopenharmony_ci wrapped[i]->setRelease(releaseProc, &freed[i]); 1569cb93a386Sopenharmony_ci } 1570cb93a386Sopenharmony_ci 1571cb93a386Sopenharmony_ci cache->insertDelayedTextureUnref(wrapped[0]); 1572cb93a386Sopenharmony_ci cache->insertDelayedTextureUnref(wrapped[1]); 1573cb93a386Sopenharmony_ci 1574cb93a386Sopenharmony_ci // An uncacheable cross-context should not be purged as soon as we drop our ref. This 1575cb93a386Sopenharmony_ci // is because inserting it as a cross-context resource actually holds a ref until the 1576cb93a386Sopenharmony_ci // message is received. 1577cb93a386Sopenharmony_ci cache->insertDelayedTextureUnref(wrapped[2]); 1578cb93a386Sopenharmony_ci 1579cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == (freed[0] + freed[1] + freed[2])); 1580cb93a386Sopenharmony_ci 1581cb93a386Sopenharmony_ci // Have only ref waiting on message. 1582cb93a386Sopenharmony_ci wrapped[0]->unref(); 1583cb93a386Sopenharmony_ci wrapped[1]->unref(); 1584cb93a386Sopenharmony_ci wrapped[2]->unref(); 1585cb93a386Sopenharmony_ci 1586cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == (freed[0] + freed[1] + freed[2])); 1587cb93a386Sopenharmony_ci 1588cb93a386Sopenharmony_ci // This should free nothing since no messages were sent. 1589cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 1590cb93a386Sopenharmony_ci 1591cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == (freed[0] + freed[1] + freed[2])); 1592cb93a386Sopenharmony_ci 1593cb93a386Sopenharmony_ci // Send message to free the first resource 1594cb93a386Sopenharmony_ci GrTextureFreedMessage msg1{wrapped[0], dContext->directContextID()}; 1595cb93a386Sopenharmony_ci SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg1); 1596cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 1597cb93a386Sopenharmony_ci 1598cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == (freed[0] + freed[1] + freed[2])); 1599cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == freed[0]); 1600cb93a386Sopenharmony_ci 1601cb93a386Sopenharmony_ci GrTextureFreedMessage msg2{wrapped[2], dContext->directContextID()}; 1602cb93a386Sopenharmony_ci SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg2); 1603cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 1604cb93a386Sopenharmony_ci 1605cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == (freed[0] + freed[1] + freed[2])); 1606cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == freed[1]); 1607cb93a386Sopenharmony_ci 1608cb93a386Sopenharmony_ci mock.reset(); 1609cb93a386Sopenharmony_ci 1610cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == (freed[0] + freed[1] + freed[2])); 1611cb93a386Sopenharmony_ci} 1612cb93a386Sopenharmony_ci 1613cb93a386Sopenharmony_ciDEF_GPUTEST(ResourceCacheMisc, reporter, /* options */) { 1614cb93a386Sopenharmony_ci // The below tests create their own mock contexts. 1615cb93a386Sopenharmony_ci test_no_key(reporter); 1616cb93a386Sopenharmony_ci test_purge_unlocked(reporter); 1617cb93a386Sopenharmony_ci test_purge_command_buffer_usage(reporter); 1618cb93a386Sopenharmony_ci test_budgeting(reporter); 1619cb93a386Sopenharmony_ci test_unbudgeted(reporter); 1620cb93a386Sopenharmony_ci test_unbudgeted_to_scratch(reporter); 1621cb93a386Sopenharmony_ci test_duplicate_unique_key(reporter); 1622cb93a386Sopenharmony_ci test_duplicate_scratch_key(reporter); 1623cb93a386Sopenharmony_ci test_remove_scratch_key(reporter); 1624cb93a386Sopenharmony_ci test_scratch_key_consistency(reporter); 1625cb93a386Sopenharmony_ci test_purge_invalidated(reporter); 1626cb93a386Sopenharmony_ci test_cache_chained_purge(reporter); 1627cb93a386Sopenharmony_ci test_timestamp_wrap(reporter); 1628cb93a386Sopenharmony_ci test_time_purge(reporter); 1629cb93a386Sopenharmony_ci test_partial_purge(reporter); 1630cb93a386Sopenharmony_ci test_custom_data(reporter); 1631cb93a386Sopenharmony_ci test_abandoned(reporter); 1632cb93a386Sopenharmony_ci test_tags(reporter); 1633cb93a386Sopenharmony_ci test_free_texture_messages(reporter); 1634cb93a386Sopenharmony_ci} 1635cb93a386Sopenharmony_ci 1636cb93a386Sopenharmony_ci// This simulates a portion of Chrome's context abandonment processing. 1637cb93a386Sopenharmony_ci// Please see: crbug.com/1011368 and crbug.com/1014993 1638cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceMessagesAfterAbandon, reporter, ctxInfo) { 1639cb93a386Sopenharmony_ci auto dContext = ctxInfo.directContext(); 1640cb93a386Sopenharmony_ci GrGpu* gpu = dContext->priv().getGpu(); 1641cb93a386Sopenharmony_ci GrResourceCache* cache = dContext->priv().getResourceCache(); 1642cb93a386Sopenharmony_ci 1643cb93a386Sopenharmony_ci GrBackendTexture backend = dContext->createBackendTexture(16, 16, 1644cb93a386Sopenharmony_ci SkColorType::kRGBA_8888_SkColorType, 1645cb93a386Sopenharmony_ci GrMipmapped::kNo, GrRenderable::kNo); 1646cb93a386Sopenharmony_ci GrTexture* tex = gpu->wrapBackendTexture(backend, 1647cb93a386Sopenharmony_ci GrWrapOwnership::kBorrow_GrWrapOwnership, 1648cb93a386Sopenharmony_ci GrWrapCacheable::kYes, 1649cb93a386Sopenharmony_ci GrIOType::kRead_GrIOType) 1650cb93a386Sopenharmony_ci .release(); 1651cb93a386Sopenharmony_ci 1652cb93a386Sopenharmony_ci auto releaseProc = [](void* ctx) { 1653cb93a386Sopenharmony_ci int* index = (int*) ctx; 1654cb93a386Sopenharmony_ci *index = 1; 1655cb93a386Sopenharmony_ci }; 1656cb93a386Sopenharmony_ci 1657cb93a386Sopenharmony_ci int freed = 0; 1658cb93a386Sopenharmony_ci 1659cb93a386Sopenharmony_ci tex->setRelease(releaseProc, &freed); 1660cb93a386Sopenharmony_ci 1661cb93a386Sopenharmony_ci cache->insertDelayedTextureUnref(tex); 1662cb93a386Sopenharmony_ci 1663cb93a386Sopenharmony_ci // Now only the cache is holding a ref to this texture 1664cb93a386Sopenharmony_ci tex->unref(); 1665cb93a386Sopenharmony_ci 1666cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == freed); 1667cb93a386Sopenharmony_ci 1668cb93a386Sopenharmony_ci // We must delete the backend texture before abandoning the context in vulkan. We just do it 1669cb93a386Sopenharmony_ci // for all the backends for consistency. 1670cb93a386Sopenharmony_ci dContext->deleteBackendTexture(backend); 1671cb93a386Sopenharmony_ci dContext->abandonContext(); 1672cb93a386Sopenharmony_ci 1673cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == freed); 1674cb93a386Sopenharmony_ci 1675cb93a386Sopenharmony_ci // In the past, creating this message could cause an exception due to 1676cb93a386Sopenharmony_ci // an un-safe downcast from GrTexture to GrGpuResource 1677cb93a386Sopenharmony_ci GrTextureFreedMessage msg{tex, dContext->directContextID()}; 1678cb93a386Sopenharmony_ci SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg); 1679cb93a386Sopenharmony_ci 1680cb93a386Sopenharmony_ci // This doesn't actually do anything but it does trigger us to read messages 1681cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(false); 1682cb93a386Sopenharmony_ci} 1683cb93a386Sopenharmony_ci 1684cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 1685cb93a386Sopenharmony_cistatic sk_sp<GrTexture> make_normal_texture(GrResourceProvider* provider, 1686cb93a386Sopenharmony_ci GrRenderable renderable, 1687cb93a386Sopenharmony_ci SkISize dims, 1688cb93a386Sopenharmony_ci int sampleCnt) { 1689cb93a386Sopenharmony_ci auto format = provider->caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, renderable); 1690cb93a386Sopenharmony_ci return provider->createTexture(dims, format, GrTextureType::k2D, renderable, sampleCnt, 1691cb93a386Sopenharmony_ci GrMipmapped::kNo, SkBudgeted::kYes, GrProtected::kNo); 1692cb93a386Sopenharmony_ci} 1693cb93a386Sopenharmony_ci 1694cb93a386Sopenharmony_cistatic sk_sp<GrTextureProxy> make_mipmap_proxy(GrRecordingContext* rContext, 1695cb93a386Sopenharmony_ci GrRenderable renderable, 1696cb93a386Sopenharmony_ci SkISize dims, 1697cb93a386Sopenharmony_ci int sampleCnt) { 1698cb93a386Sopenharmony_ci GrProxyProvider* proxyProvider = rContext->priv().proxyProvider(); 1699cb93a386Sopenharmony_ci const GrCaps* caps = rContext->priv().caps(); 1700cb93a386Sopenharmony_ci 1701cb93a386Sopenharmony_ci 1702cb93a386Sopenharmony_ci const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 1703cb93a386Sopenharmony_ci GrRenderable::kNo); 1704cb93a386Sopenharmony_ci 1705cb93a386Sopenharmony_ci return proxyProvider->createProxy(format, dims, renderable, sampleCnt, GrMipmapped::kYes, 1706cb93a386Sopenharmony_ci SkBackingFit::kExact, SkBudgeted::kYes, GrProtected::kNo); 1707cb93a386Sopenharmony_ci} 1708cb93a386Sopenharmony_ci 1709cb93a386Sopenharmony_ci// Exercise GrSurface::gpuMemorySize for different combos of MSAA, RT-only, 1710cb93a386Sopenharmony_ci// Texture-only, both-RT-and-Texture and MIPmapped 1711cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GPUMemorySize, reporter, ctxInfo) { 1712cb93a386Sopenharmony_ci auto context = ctxInfo.directContext(); 1713cb93a386Sopenharmony_ci GrResourceProvider* resourceProvider = context->priv().resourceProvider(); 1714cb93a386Sopenharmony_ci const GrCaps* caps = context->priv().caps(); 1715cb93a386Sopenharmony_ci 1716cb93a386Sopenharmony_ci static constexpr SkISize kSize = {64, 64}; 1717cb93a386Sopenharmony_ci static constexpr auto kArea = kSize.area(); 1718cb93a386Sopenharmony_ci 1719cb93a386Sopenharmony_ci // Normal versions 1720cb93a386Sopenharmony_ci { 1721cb93a386Sopenharmony_ci sk_sp<GrTexture> tex; 1722cb93a386Sopenharmony_ci 1723cb93a386Sopenharmony_ci tex = make_normal_texture(resourceProvider, GrRenderable::kYes, kSize, 1); 1724cb93a386Sopenharmony_ci size_t size = tex->gpuMemorySize(); 1725cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, kArea*4 == size); 1726cb93a386Sopenharmony_ci 1727cb93a386Sopenharmony_ci size_t sampleCount = (size_t)caps->getRenderTargetSampleCount(4, tex->backendFormat()); 1728cb93a386Sopenharmony_ci if (sampleCount >= 4) { 1729cb93a386Sopenharmony_ci tex = make_normal_texture(resourceProvider, GrRenderable::kYes, kSize, sampleCount); 1730cb93a386Sopenharmony_ci size = tex->gpuMemorySize(); 1731cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1732cb93a386Sopenharmony_ci kArea*4 == size || // msaa4 failed 1733cb93a386Sopenharmony_ci kArea*4*sampleCount == size || // auto-resolving 1734cb93a386Sopenharmony_ci kArea*4*(sampleCount+1) == size); // explicit resolve buffer 1735cb93a386Sopenharmony_ci } 1736cb93a386Sopenharmony_ci 1737cb93a386Sopenharmony_ci tex = make_normal_texture(resourceProvider, GrRenderable::kNo, kSize, 1); 1738cb93a386Sopenharmony_ci size = tex->gpuMemorySize(); 1739cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, kArea*4 == size); 1740cb93a386Sopenharmony_ci } 1741cb93a386Sopenharmony_ci 1742cb93a386Sopenharmony_ci // Mipmapped versions 1743cb93a386Sopenharmony_ci if (caps->mipmapSupport()) { 1744cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> proxy; 1745cb93a386Sopenharmony_ci 1746cb93a386Sopenharmony_ci proxy = make_mipmap_proxy(context, GrRenderable::kYes, kSize, 1); 1747cb93a386Sopenharmony_ci size_t size = proxy->gpuMemorySize(); 1748cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, kArea*4 + (kArea*4)/3 == size); 1749cb93a386Sopenharmony_ci 1750cb93a386Sopenharmony_ci size_t sampleCount = (size_t)caps->getRenderTargetSampleCount(4, proxy->backendFormat()); 1751cb93a386Sopenharmony_ci if (sampleCount >= 4) { 1752cb93a386Sopenharmony_ci proxy = make_mipmap_proxy(context, GrRenderable::kYes, kSize, sampleCount); 1753cb93a386Sopenharmony_ci size = proxy->gpuMemorySize(); 1754cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1755cb93a386Sopenharmony_ci kArea*4 + (kArea*4)/3 == size || // msaa4 failed 1756cb93a386Sopenharmony_ci kArea*4*sampleCount + (kArea*4)/3 == size || // auto-resolving 1757cb93a386Sopenharmony_ci kArea*4*(sampleCount+1) + (kArea*4)/3 == size); // explicit resolve buffer 1758cb93a386Sopenharmony_ci } 1759cb93a386Sopenharmony_ci 1760cb93a386Sopenharmony_ci proxy = make_mipmap_proxy(context, GrRenderable::kNo, kSize, 1); 1761cb93a386Sopenharmony_ci size = proxy->gpuMemorySize(); 1762cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, kArea*4 + (kArea*4)/3 == size); 1763cb93a386Sopenharmony_ci } 1764cb93a386Sopenharmony_ci} 1765cb93a386Sopenharmony_ci 1766cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(PurgeToMakeHeadroom, reporter, ctxInfo) { 1767cb93a386Sopenharmony_ci constexpr size_t kTexSize = 16 * 16 * 4; 1768cb93a386Sopenharmony_ci 1769cb93a386Sopenharmony_ci auto dContext = ctxInfo.directContext(); 1770cb93a386Sopenharmony_ci dContext->setResourceCacheLimit(2 * kTexSize); 1771cb93a386Sopenharmony_ci auto resourceProvider = dContext->priv().resourceProvider(); 1772cb93a386Sopenharmony_ci auto resourceCache = dContext->priv().getResourceCache(); 1773cb93a386Sopenharmony_ci for (bool success : { true, false }) { 1774cb93a386Sopenharmony_ci reporter->push(SkString(success ? "success" : "failure")); 1775cb93a386Sopenharmony_ci 1776cb93a386Sopenharmony_ci resourceCache->releaseAll(); 1777cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, resourceCache->getBudgetedResourceBytes() == 0); 1778cb93a386Sopenharmony_ci 1779cb93a386Sopenharmony_ci // Make one unpurgeable texture and one purgeable texture. 1780cb93a386Sopenharmony_ci auto lockedTex = make_normal_texture(resourceProvider, GrRenderable::kNo, {16, 16}, 1); 1781cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, lockedTex->gpuMemorySize() == kTexSize); 1782cb93a386Sopenharmony_ci 1783cb93a386Sopenharmony_ci // N.b. this surface is renderable so "reuseScratchTextures = false" won't mess us up. 1784cb93a386Sopenharmony_ci auto purgeableTex = make_normal_texture(resourceProvider, GrRenderable::kYes, {16, 16}, 1); 1785cb93a386Sopenharmony_ci if (success) { 1786cb93a386Sopenharmony_ci purgeableTex = nullptr; 1787cb93a386Sopenharmony_ci } 1788cb93a386Sopenharmony_ci 1789cb93a386Sopenharmony_ci size_t expectedPurgeable = success ? kTexSize : 0; 1790cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, expectedPurgeable == resourceCache->getPurgeableBytes(), 1791cb93a386Sopenharmony_ci "%zu vs %zu", expectedPurgeable, resourceCache->getPurgeableBytes()); 1792cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, success == resourceCache->purgeToMakeHeadroom(kTexSize)); 1793cb93a386Sopenharmony_ci size_t expectedBudgeted = success ? kTexSize : (2 * kTexSize); 1794cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, expectedBudgeted == resourceCache->getBudgetedResourceBytes(), 1795cb93a386Sopenharmony_ci "%zu vs %zu", expectedBudgeted, resourceCache->getBudgetedResourceBytes()); 1796cb93a386Sopenharmony_ci reporter->pop(); 1797cb93a386Sopenharmony_ci } 1798cb93a386Sopenharmony_ci} 1799cb93a386Sopenharmony_ci 1800cb93a386Sopenharmony_ci#if GR_GPU_STATS 1801cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(OverbudgetFlush, reporter, ctxInfo) { 1802cb93a386Sopenharmony_ci auto context = ctxInfo.directContext(); 1803cb93a386Sopenharmony_ci context->setResourceCacheLimit(1); 1804cb93a386Sopenharmony_ci 1805cb93a386Sopenharmony_ci // Helper that determines if cache is overbudget. 1806cb93a386Sopenharmony_ci auto overbudget = [context] { 1807cb93a386Sopenharmony_ci int uNum; 1808cb93a386Sopenharmony_ci size_t uSize; 1809cb93a386Sopenharmony_ci context->getResourceCacheUsage(&uNum, &uSize); 1810cb93a386Sopenharmony_ci size_t bSize = context->getResourceCacheLimit(); 1811cb93a386Sopenharmony_ci return uSize > bSize; 1812cb93a386Sopenharmony_ci }; 1813cb93a386Sopenharmony_ci 1814cb93a386Sopenharmony_ci // Helper that does a trivial draw to a surface. 1815cb93a386Sopenharmony_ci auto drawToSurf = [](SkSurface* surf) { 1816cb93a386Sopenharmony_ci surf->getCanvas()->drawRect(SkRect::MakeWH(1,1), SkPaint()); 1817cb93a386Sopenharmony_ci }; 1818cb93a386Sopenharmony_ci 1819cb93a386Sopenharmony_ci // Helper that checks whether a flush has occurred between calls. 1820cb93a386Sopenharmony_ci int baseFlushCount = 0; 1821cb93a386Sopenharmony_ci auto getFlushCountDelta = [context, &baseFlushCount]() { 1822cb93a386Sopenharmony_ci int cur = context->priv().getGpu()->stats()->numSubmitToGpus(); 1823cb93a386Sopenharmony_ci int delta = cur - baseFlushCount; 1824cb93a386Sopenharmony_ci baseFlushCount = cur; 1825cb93a386Sopenharmony_ci return delta; 1826cb93a386Sopenharmony_ci }; 1827cb93a386Sopenharmony_ci 1828cb93a386Sopenharmony_ci auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 1829cb93a386Sopenharmony_ci auto surf1 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 1, nullptr); 1830cb93a386Sopenharmony_ci auto surf2 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 1, nullptr); 1831cb93a386Sopenharmony_ci 1832cb93a386Sopenharmony_ci drawToSurf(surf1.get()); 1833cb93a386Sopenharmony_ci drawToSurf(surf2.get()); 1834cb93a386Sopenharmony_ci 1835cb93a386Sopenharmony_ci // Flush each surface once to ensure that their backing stores are allocated. 1836cb93a386Sopenharmony_ci surf1->flushAndSubmit(); 1837cb93a386Sopenharmony_ci surf2->flushAndSubmit(); 1838cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, overbudget()); 1839cb93a386Sopenharmony_ci getFlushCountDelta(); 1840cb93a386Sopenharmony_ci 1841cb93a386Sopenharmony_ci // Nothing should be purgeable so drawing to either surface doesn't cause a flush. 1842cb93a386Sopenharmony_ci drawToSurf(surf1.get()); 1843cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !getFlushCountDelta()); 1844cb93a386Sopenharmony_ci drawToSurf(surf2.get()); 1845cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !getFlushCountDelta()); 1846cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, overbudget()); 1847cb93a386Sopenharmony_ci 1848cb93a386Sopenharmony_ci // Make surf1 purgeable. Drawing to surf2 should flush. 1849cb93a386Sopenharmony_ci surf1->flushAndSubmit(); 1850cb93a386Sopenharmony_ci surf1.reset(); 1851cb93a386Sopenharmony_ci drawToSurf(surf2.get()); 1852cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, getFlushCountDelta()); 1853cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, overbudget()); 1854cb93a386Sopenharmony_ci} 1855cb93a386Sopenharmony_ci#endif 1856