ResourceCacheTest.cpp 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763
  1. /*
  2. * Copyright 2013 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkTypes.h"
  8. #include "include/gpu/GrContext.h"
  9. #include "include/gpu/GrTexture.h"
  10. #include "src/gpu/GrContextPriv.h"
  11. #include "src/gpu/GrGpu.h"
  12. #include "src/gpu/GrGpuResourceCacheAccess.h"
  13. #include "src/gpu/GrGpuResourcePriv.h"
  14. #include "src/gpu/GrProxyProvider.h"
  15. #include "src/gpu/GrRenderTargetPriv.h"
  16. #include "src/gpu/GrResourceCache.h"
  17. #include "src/gpu/GrResourceProvider.h"
  18. #include "tools/gpu/GrContextFactory.h"
  19. #include "include/core/SkCanvas.h"
  20. #include "include/core/SkSurface.h"
  21. #include "src/core/SkMessageBus.h"
  22. #include "src/core/SkMipMap.h"
  23. #include "src/gpu/SkGr.h"
  24. #include "tests/Test.h"
  25. #include <thread>
  26. static const int gWidth = 640;
  27. static const int gHeight = 480;
  28. ////////////////////////////////////////////////////////////////////////////////
  29. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheCache, reporter, ctxInfo) {
  30. GrContext* context = ctxInfo.grContext();
  31. SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight);
  32. auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info));
  33. SkCanvas* canvas = surface->getCanvas();
  34. const SkIRect size = SkIRect::MakeWH(gWidth, gHeight);
  35. SkBitmap src;
  36. src.allocN32Pixels(size.width(), size.height());
  37. src.eraseColor(SK_ColorBLACK);
  38. size_t srcSize = src.computeByteSize();
  39. size_t initialCacheSize;
  40. context->getResourceCacheUsage(nullptr, &initialCacheSize);
  41. int oldMaxNum;
  42. size_t oldMaxBytes;
  43. context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes);
  44. // Set the cache limits so we can fit 10 "src" images and the
  45. // max number of textures doesn't matter
  46. size_t maxCacheSize = initialCacheSize + 10*srcSize;
  47. context->setResourceCacheLimits(1000, maxCacheSize);
  48. SkBitmap readback;
  49. readback.allocN32Pixels(size.width(), size.height());
  50. for (int i = 0; i < 100; ++i) {
  51. canvas->drawBitmap(src, 0, 0);
  52. surface->readPixels(readback, 0, 0);
  53. // "modify" the src texture
  54. src.notifyPixelsChanged();
  55. size_t curCacheSize;
  56. context->getResourceCacheUsage(nullptr, &curCacheSize);
  57. // we should never go over the size limit
  58. REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize);
  59. }
  60. context->setResourceCacheLimits(oldMaxNum, oldMaxBytes);
  61. }
  62. static bool is_rendering_and_not_angle_es3(sk_gpu_test::GrContextFactory::ContextType type) {
  63. if (type == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES3_ContextType ||
  64. type == sk_gpu_test::GrContextFactory::kANGLE_GL_ES3_ContextType) {
  65. return false;
  66. }
  67. return sk_gpu_test::GrContextFactory::IsRenderingContext(type);
  68. }
  69. static GrStencilAttachment* get_SB(GrRenderTarget* rt) {
  70. return rt->renderTargetPriv().getStencilAttachment();
  71. }
  72. static sk_sp<GrRenderTarget> create_RT_with_SB(GrResourceProvider* provider,
  73. int size, int sampleCount, SkBudgeted budgeted) {
  74. GrSurfaceDesc desc;
  75. desc.fWidth = size;
  76. desc.fHeight = size;
  77. desc.fConfig = kRGBA_8888_GrPixelConfig;
  78. sk_sp<GrTexture> tex(provider->createTexture(desc, GrRenderable::kYes, sampleCount, budgeted,
  79. GrProtected::kNo,
  80. GrResourceProvider::Flags::kNoPendingIO));
  81. if (!tex || !tex->asRenderTarget()) {
  82. return nullptr;
  83. }
  84. if (!provider->attachStencilAttachment(tex->asRenderTarget(), sampleCount)) {
  85. return nullptr;
  86. }
  87. SkASSERT(get_SB(tex->asRenderTarget()));
  88. return sk_ref_sp(tex->asRenderTarget());
  89. }
  90. // This currently fails on ES3 ANGLE contexts
  91. DEF_GPUTEST_FOR_CONTEXTS(ResourceCacheStencilBuffers, &is_rendering_and_not_angle_es3, reporter,
  92. ctxInfo, nullptr) {
  93. GrContext* context = ctxInfo.grContext();
  94. const GrCaps* caps = context->priv().caps();
  95. if (caps->avoidStencilBuffers()) {
  96. return;
  97. }
  98. GrResourceProvider* resourceProvider = context->priv().resourceProvider();
  99. GrColorType grColorType = GrColorType::kRGBA_8888;
  100. GrBackendFormat format = caps->getBackendFormatFromColorType(grColorType);
  101. sk_sp<GrRenderTarget> smallRT0 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes);
  102. REPORTER_ASSERT(reporter, smallRT0);
  103. {
  104. // Two budgeted RTs with the same desc should share a stencil buffer.
  105. sk_sp<GrRenderTarget> smallRT1 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes);
  106. REPORTER_ASSERT(reporter, smallRT1);
  107. REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT1.get()));
  108. }
  109. {
  110. // An unbudgeted RT with the same desc should also share.
  111. sk_sp<GrRenderTarget> smallRT2 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kNo);
  112. REPORTER_ASSERT(reporter, smallRT2);
  113. REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT2.get()));
  114. }
  115. {
  116. // An RT with a much larger size should not share.
  117. sk_sp<GrRenderTarget> bigRT = create_RT_with_SB(resourceProvider, 400, 1, SkBudgeted::kNo);
  118. REPORTER_ASSERT(reporter, bigRT);
  119. REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(bigRT.get()));
  120. }
  121. int smallSampleCount =
  122. context->priv().caps()->getRenderTargetSampleCount(2, grColorType, format);
  123. if (smallSampleCount > 1) {
  124. // An RT with a different sample count should not share.
  125. sk_sp<GrRenderTarget> smallMSAART0 = create_RT_with_SB(resourceProvider, 4,
  126. smallSampleCount, SkBudgeted::kNo);
  127. REPORTER_ASSERT(reporter, smallMSAART0);
  128. REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(smallMSAART0.get()));
  129. {
  130. // A second MSAA RT should share with the first MSAA RT.
  131. sk_sp<GrRenderTarget> smallMSAART1 = create_RT_with_SB(resourceProvider, 4,
  132. smallSampleCount,
  133. SkBudgeted::kNo);
  134. REPORTER_ASSERT(reporter, smallMSAART1);
  135. REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) == get_SB(smallMSAART1.get()));
  136. }
  137. // But one with a larger sample count should not. (Also check that the two requests didn't
  138. // rounded up to the same actual sample count or else they could share.).
  139. int bigSampleCount = context->priv().caps()->getRenderTargetSampleCount(
  140. 5, grColorType, format);
  141. if (bigSampleCount > 0 && bigSampleCount != smallSampleCount) {
  142. sk_sp<GrRenderTarget> smallMSAART2 = create_RT_with_SB(resourceProvider, 4,
  143. bigSampleCount,
  144. SkBudgeted::kNo);
  145. REPORTER_ASSERT(reporter, smallMSAART2);
  146. REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) != get_SB(smallMSAART2.get()));
  147. }
  148. }
  149. }
  150. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheWrappedResources, reporter, ctxInfo) {
  151. GrContext* context = ctxInfo.grContext();
  152. GrResourceProvider* resourceProvider = context->priv().resourceProvider();
  153. GrGpu* gpu = context->priv().getGpu();
  154. // this test is only valid for GL
  155. if (!gpu || !gpu->glContextForTesting()) {
  156. return;
  157. }
  158. GrBackendTexture backendTextures[2];
  159. static const int kW = 100;
  160. static const int kH = 100;
  161. backendTextures[0] = context->createBackendTexture(kW, kH, kRGBA_8888_SkColorType,
  162. SkColors::kTransparent,
  163. GrMipMapped::kNo, GrRenderable::kNo,
  164. GrProtected::kNo);
  165. backendTextures[1] = context->createBackendTexture(kW, kH, kRGBA_8888_SkColorType,
  166. SkColors::kTransparent,
  167. GrMipMapped::kNo, GrRenderable::kNo,
  168. GrProtected::kNo);
  169. REPORTER_ASSERT(reporter, backendTextures[0].isValid());
  170. REPORTER_ASSERT(reporter, backendTextures[1].isValid());
  171. if (!backendTextures[0].isValid() || !backendTextures[1].isValid()) {
  172. return;
  173. }
  174. context->resetContext();
  175. sk_sp<GrTexture> borrowed(resourceProvider->wrapBackendTexture(
  176. backendTextures[0], GrColorType::kRGBA_8888,
  177. kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRead_GrIOType));
  178. sk_sp<GrTexture> adopted(resourceProvider->wrapBackendTexture(
  179. backendTextures[1], GrColorType::kRGBA_8888,
  180. kAdopt_GrWrapOwnership, GrWrapCacheable::kNo, kRead_GrIOType));
  181. REPORTER_ASSERT(reporter, borrowed != nullptr && adopted != nullptr);
  182. if (!borrowed || !adopted) {
  183. return;
  184. }
  185. borrowed.reset(nullptr);
  186. adopted.reset(nullptr);
  187. context->flush();
  188. bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[0]);
  189. bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[1]);
  190. REPORTER_ASSERT(reporter, borrowedIsAlive);
  191. REPORTER_ASSERT(reporter, !adoptedIsAlive);
  192. if (borrowedIsAlive) {
  193. context->deleteBackendTexture(backendTextures[0]);
  194. }
  195. if (adoptedIsAlive) {
  196. context->deleteBackendTexture(backendTextures[1]);
  197. }
  198. context->resetContext();
  199. }
  200. class TestResource : public GrGpuResource {
  201. enum ScratchConstructor { kScratchConstructor };
  202. public:
  203. static const size_t kDefaultSize = 100;
  204. /** Property that distinctly categorizes the resource.
  205. * For example, textures have width, height, ... */
  206. enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty };
  207. TestResource(GrGpu* gpu, SkBudgeted budgeted = SkBudgeted::kYes, size_t size = kDefaultSize)
  208. : INHERITED(gpu)
  209. , fToDelete(nullptr)
  210. , fSize(size)
  211. , fProperty(kA_SimulatedProperty)
  212. , fIsScratch(false) {
  213. ++fNumAlive;
  214. this->registerWithCache(budgeted);
  215. }
  216. static TestResource* CreateScratch(GrGpu* gpu, SkBudgeted budgeted,
  217. SimulatedProperty property, size_t size = kDefaultSize) {
  218. return new TestResource(gpu, budgeted, property, kScratchConstructor, size);
  219. }
  220. static TestResource* CreateWrapped(GrGpu* gpu, GrWrapCacheable cacheable,
  221. size_t size = kDefaultSize) {
  222. return new TestResource(gpu, cacheable, size);
  223. }
  224. ~TestResource() override {
  225. --fNumAlive;
  226. }
  227. static int NumAlive() { return fNumAlive; }
  228. void setUnrefWhenDestroyed(sk_sp<TestResource> resource) {
  229. fToDelete = std::move(resource);
  230. }
  231. static void ComputeScratchKey(SimulatedProperty property, GrScratchKey* key) {
  232. static GrScratchKey::ResourceType t = GrScratchKey::GenerateResourceType();
  233. GrScratchKey::Builder builder(key, t, kScratchKeyFieldCnt);
  234. for (int i = 0; i < kScratchKeyFieldCnt; ++i) {
  235. builder[i] = static_cast<uint32_t>(i + property);
  236. }
  237. }
  238. static size_t ExpectedScratchKeySize() {
  239. return sizeof(uint32_t) * (kScratchKeyFieldCnt + GrScratchKey::kMetaDataCnt);
  240. }
  241. private:
  242. static const int kScratchKeyFieldCnt = 6;
  243. TestResource(GrGpu* gpu, SkBudgeted budgeted, SimulatedProperty property, ScratchConstructor,
  244. size_t size = kDefaultSize)
  245. : INHERITED(gpu)
  246. , fToDelete(nullptr)
  247. , fSize(size)
  248. , fProperty(property)
  249. , fIsScratch(true) {
  250. ++fNumAlive;
  251. this->registerWithCache(budgeted);
  252. }
  253. // Constructor for simulating resources that wrap backend objects.
  254. TestResource(GrGpu* gpu, GrWrapCacheable cacheable, size_t size)
  255. : INHERITED(gpu)
  256. , fToDelete(nullptr)
  257. , fSize(size)
  258. , fProperty(kA_SimulatedProperty)
  259. , fIsScratch(false) {
  260. ++fNumAlive;
  261. this->registerWithCacheWrapped(cacheable);
  262. }
  263. void computeScratchKey(GrScratchKey* key) const override {
  264. if (fIsScratch) {
  265. ComputeScratchKey(fProperty, key);
  266. }
  267. }
  268. size_t onGpuMemorySize() const override { return fSize; }
  269. const char* getResourceType() const override { return "Test"; }
  270. sk_sp<TestResource> fToDelete;
  271. size_t fSize;
  272. static int fNumAlive;
  273. SimulatedProperty fProperty;
  274. bool fIsScratch;
  275. typedef GrGpuResource INHERITED;
  276. };
  277. int TestResource::fNumAlive = 0;
  278. class Mock {
  279. public:
  280. Mock(int maxCnt, size_t maxBytes) {
  281. fContext = GrContext::MakeMock(nullptr);
  282. SkASSERT(fContext);
  283. fContext->setResourceCacheLimits(maxCnt, maxBytes);
  284. GrResourceCache* cache = fContext->priv().getResourceCache();
  285. cache->purgeAllUnlocked();
  286. SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes());
  287. }
  288. GrResourceCache* cache() { return fContext->priv().getResourceCache(); }
  289. GrContext* context() { return fContext.get(); }
  290. void reset() {
  291. fContext.reset();
  292. }
  293. private:
  294. sk_sp<GrContext> fContext;
  295. };
  296. static void test_no_key(skiatest::Reporter* reporter) {
  297. Mock mock(10, 30000);
  298. GrContext* context = mock.context();
  299. GrResourceCache* cache = mock.cache();
  300. GrGpu* gpu = context->priv().getGpu();
  301. // Create a bunch of resources with no keys
  302. TestResource* a = new TestResource(gpu, SkBudgeted::kYes, 11);
  303. TestResource* b = new TestResource(gpu, SkBudgeted::kYes, 12);
  304. TestResource* c = new TestResource(gpu, SkBudgeted::kYes, 13 );
  305. TestResource* d = new TestResource(gpu, SkBudgeted::kYes, 14 );
  306. REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
  307. REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
  308. REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
  309. d->gpuMemorySize() == cache->getResourceBytes());
  310. // Should be safe to purge without deleting the resources since we still have refs.
  311. cache->purgeAllUnlocked();
  312. REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
  313. // Since the resources have neither unique nor scratch keys, delete immediately upon unref.
  314. a->unref();
  315. REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
  316. REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
  317. REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() ==
  318. cache->getResourceBytes());
  319. c->unref();
  320. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  321. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  322. REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
  323. cache->getResourceBytes());
  324. d->unref();
  325. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  326. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  327. REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
  328. b->unref();
  329. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  330. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  331. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  332. }
  333. // Each integer passed as a template param creates a new domain.
  334. template <int>
  335. static void make_unique_key(GrUniqueKey* key, int data, const char* tag = nullptr) {
  336. static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
  337. GrUniqueKey::Builder builder(key, d, 1, tag);
  338. builder[0] = data;
  339. }
  340. static void test_purge_unlocked(skiatest::Reporter* reporter) {
  341. Mock mock(10, 30000);
  342. GrContext* context = mock.context();
  343. GrResourceCache* cache = mock.cache();
  344. GrGpu* gpu = context->priv().getGpu();
  345. // Create two resource w/ a unique key and two w/o but all of which have scratch keys.
  346. TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  347. TestResource::kA_SimulatedProperty, 11);
  348. GrUniqueKey uniqueKey;
  349. make_unique_key<0>(&uniqueKey, 0);
  350. TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  351. TestResource::kA_SimulatedProperty, 12);
  352. b->resourcePriv().setUniqueKey(uniqueKey);
  353. TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  354. TestResource::kA_SimulatedProperty, 13);
  355. GrUniqueKey uniqueKey2;
  356. make_unique_key<0>(&uniqueKey2, 1);
  357. TestResource* d = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  358. TestResource::kA_SimulatedProperty, 14);
  359. d->resourcePriv().setUniqueKey(uniqueKey2);
  360. REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
  361. REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
  362. REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
  363. d->gpuMemorySize() == cache->getResourceBytes());
  364. // Should be safe to purge without deleting the resources since we still have refs.
  365. cache->purgeUnlockedResources(false);
  366. REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
  367. // Unref them all. Since they all have keys they should remain in the cache.
  368. a->unref();
  369. b->unref();
  370. c->unref();
  371. d->unref();
  372. REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
  373. REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
  374. REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
  375. d->gpuMemorySize() == cache->getResourceBytes());
  376. // Purge only the two scratch resources
  377. cache->purgeUnlockedResources(true);
  378. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  379. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  380. REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
  381. cache->getResourceBytes());
  382. // Purge the uniquely keyed resources
  383. cache->purgeUnlockedResources(false);
  384. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  385. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  386. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  387. }
  388. static void test_budgeting(skiatest::Reporter* reporter) {
  389. Mock mock(10, 300);
  390. GrContext* context = mock.context();
  391. GrResourceCache* cache = mock.cache();
  392. GrGpu* gpu = context->priv().getGpu();
  393. GrUniqueKey uniqueKey;
  394. make_unique_key<0>(&uniqueKey, 0);
  395. // Create a scratch, a unique, and a wrapped resource
  396. TestResource* scratch =
  397. TestResource::CreateScratch(gpu, SkBudgeted::kYes, TestResource::kB_SimulatedProperty,
  398. 10);
  399. TestResource* unique = new TestResource(gpu, SkBudgeted::kYes, 11);
  400. unique->resourcePriv().setUniqueKey(uniqueKey);
  401. TestResource* wrappedCacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes, 12);
  402. TestResource* wrappedUncacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kNo, 13);
  403. TestResource* unbudgeted = new TestResource(gpu, SkBudgeted::kNo, 14);
  404. // Make sure we can add a unique key to the wrapped resources
  405. GrUniqueKey uniqueKey2;
  406. make_unique_key<0>(&uniqueKey2, 1);
  407. GrUniqueKey uniqueKey3;
  408. make_unique_key<0>(&uniqueKey3, 2);
  409. wrappedCacheable->resourcePriv().setUniqueKey(uniqueKey2);
  410. wrappedUncacheable->resourcePriv().setUniqueKey(uniqueKey3);
  411. GrGpuResource* wrappedCacheableViaKey = cache->findAndRefUniqueResource(uniqueKey2);
  412. REPORTER_ASSERT(reporter, wrappedCacheableViaKey);
  413. GrGpuResource* wrappedUncacheableViaKey = cache->findAndRefUniqueResource(uniqueKey3);
  414. REPORTER_ASSERT(reporter, wrappedUncacheableViaKey);
  415. // Remove the extra refs we just added.
  416. SkSafeUnref(wrappedCacheableViaKey);
  417. SkSafeUnref(wrappedUncacheableViaKey);
  418. // Make sure sizes are as we expect
  419. REPORTER_ASSERT(reporter, 5 == cache->getResourceCount());
  420. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
  421. wrappedCacheable->gpuMemorySize() +
  422. wrappedUncacheable->gpuMemorySize() +
  423. unbudgeted->gpuMemorySize() ==
  424. cache->getResourceBytes());
  425. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  426. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
  427. cache->getBudgetedResourceBytes());
  428. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  429. // Our refs mean that the resources are non purgeable.
  430. cache->purgeAllUnlocked();
  431. REPORTER_ASSERT(reporter, 5 == cache->getResourceCount());
  432. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
  433. wrappedCacheable->gpuMemorySize() +
  434. wrappedUncacheable->gpuMemorySize() +
  435. unbudgeted->gpuMemorySize() ==
  436. cache->getResourceBytes());
  437. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  438. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
  439. cache->getBudgetedResourceBytes());
  440. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  441. // Unreffing the cacheable wrapped resource with a unique key shouldn't free it right away.
  442. // However, unreffing the uncacheable wrapped resource should free it.
  443. wrappedCacheable->unref();
  444. wrappedUncacheable->unref();
  445. REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
  446. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
  447. wrappedCacheable->gpuMemorySize() +
  448. unbudgeted->gpuMemorySize() ==
  449. cache->getResourceBytes());
  450. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  451. // Now try freeing the budgeted resources first
  452. wrappedUncacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kNo);
  453. unique->unref();
  454. REPORTER_ASSERT(reporter, 11 == cache->getPurgeableBytes());
  455. // This will free 'unique' but not wrappedCacheable which has a key. That requires the key to be
  456. // removed to be freed.
  457. cache->purgeAllUnlocked();
  458. REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
  459. wrappedCacheableViaKey = cache->findAndRefUniqueResource(uniqueKey2);
  460. REPORTER_ASSERT(reporter, wrappedCacheableViaKey);
  461. if (wrappedCacheableViaKey) {
  462. wrappedCacheableViaKey->resourcePriv().removeUniqueKey();
  463. wrappedCacheable->unref();
  464. }
  465. // We shouldn't have to call purgeAllUnlocked as removing the key on a wrapped cacheable
  466. // resource should immediately delete it.
  467. REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
  468. wrappedCacheable = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes);
  469. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrappedCacheable->gpuMemorySize() +
  470. wrappedUncacheable->gpuMemorySize() +
  471. unbudgeted->gpuMemorySize() ==
  472. cache->getResourceBytes());
  473. REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
  474. REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes());
  475. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  476. scratch->unref();
  477. REPORTER_ASSERT(reporter, 10 == cache->getPurgeableBytes());
  478. cache->purgeAllUnlocked();
  479. REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
  480. REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrappedCacheable->gpuMemorySize() +
  481. wrappedUncacheable->gpuMemorySize() ==
  482. cache->getResourceBytes());
  483. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  484. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  485. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  486. // Unreffing the wrapped resources (with no unique key) should free them right away.
  487. wrappedUncacheable->unref();
  488. wrappedCacheable->unref();
  489. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  490. REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes());
  491. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  492. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  493. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  494. unbudgeted->unref();
  495. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  496. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  497. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  498. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  499. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  500. }
  501. static void test_unbudgeted(skiatest::Reporter* reporter) {
  502. Mock mock(10, 30000);
  503. GrContext* context = mock.context();
  504. GrResourceCache* cache = mock.cache();
  505. GrGpu* gpu = context->priv().getGpu();
  506. GrUniqueKey uniqueKey;
  507. make_unique_key<0>(&uniqueKey, 0);
  508. TestResource* scratch;
  509. TestResource* unique;
  510. TestResource* wrapped;
  511. TestResource* unbudgeted;
  512. // A large uncached or wrapped resource shouldn't evict anything.
  513. scratch = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  514. TestResource::kB_SimulatedProperty, 10);
  515. scratch->unref();
  516. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  517. REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes());
  518. REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
  519. REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes());
  520. REPORTER_ASSERT(reporter, 10 == cache->getPurgeableBytes());
  521. unique = new TestResource(gpu, SkBudgeted::kYes, 11);
  522. unique->resourcePriv().setUniqueKey(uniqueKey);
  523. unique->unref();
  524. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  525. REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
  526. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  527. REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
  528. REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
  529. size_t large = 2 * cache->getResourceBytes();
  530. unbudgeted = new TestResource(gpu, SkBudgeted::kNo, large);
  531. REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
  532. REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
  533. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  534. REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
  535. REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
  536. unbudgeted->unref();
  537. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  538. REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
  539. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  540. REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
  541. REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
  542. wrapped = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes, large);
  543. REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
  544. REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
  545. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  546. REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
  547. REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
  548. wrapped->unref();
  549. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  550. REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
  551. REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
  552. REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
  553. REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
  554. cache->purgeAllUnlocked();
  555. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  556. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  557. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  558. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  559. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  560. }
  561. // This method can't be static because it needs to friended in GrGpuResource::CacheAccess.
  562. void test_unbudgeted_to_scratch(skiatest::Reporter* reporter);
  563. /*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) {
  564. Mock mock(10, 300);
  565. GrContext* context = mock.context();
  566. GrResourceCache* cache = mock.cache();
  567. GrGpu* gpu = context->priv().getGpu();
  568. TestResource* resource =
  569. TestResource::CreateScratch(gpu, SkBudgeted::kNo, TestResource::kA_SimulatedProperty);
  570. GrScratchKey key;
  571. TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key);
  572. size_t size = resource->gpuMemorySize();
  573. for (int i = 0; i < 2; ++i) {
  574. // Since this resource is unbudgeted, it should not be reachable as scratch.
  575. REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
  576. REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
  577. REPORTER_ASSERT(reporter, GrBudgetedType::kUnbudgetedUncacheable ==
  578. resource->resourcePriv().budgetedType());
  579. REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(key, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone));
  580. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  581. REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
  582. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  583. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  584. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  585. // Once it is unrefed, it should become available as scratch.
  586. resource->unref();
  587. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  588. REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
  589. REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
  590. REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
  591. REPORTER_ASSERT(reporter, size == cache->getPurgeableBytes());
  592. resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone));
  593. REPORTER_ASSERT(reporter, resource);
  594. REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
  595. REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch());
  596. REPORTER_ASSERT(reporter,
  597. GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType());
  598. if (0 == i) {
  599. // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try
  600. // the above tests again.
  601. resource->resourcePriv().makeUnbudgeted();
  602. } else {
  603. // After the second time around, try removing the scratch key
  604. resource->resourcePriv().removeScratchKey();
  605. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  606. REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
  607. REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
  608. REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
  609. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  610. REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid());
  611. REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
  612. REPORTER_ASSERT(reporter,
  613. GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType());
  614. // now when it is unrefed it should die since it has no key.
  615. resource->unref();
  616. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  617. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  618. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  619. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  620. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  621. }
  622. }
  623. }
  624. static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
  625. Mock mock(5, 30000);
  626. GrContext* context = mock.context();
  627. GrResourceCache* cache = mock.cache();
  628. GrGpu* gpu = context->priv().getGpu();
  629. // Create two resources that have the same scratch key.
  630. TestResource* a = TestResource::CreateScratch(gpu,
  631. SkBudgeted::kYes,
  632. TestResource::kB_SimulatedProperty, 11);
  633. TestResource* b = TestResource::CreateScratch(gpu,
  634. SkBudgeted::kYes,
  635. TestResource::kB_SimulatedProperty, 12);
  636. GrScratchKey scratchKey1;
  637. TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
  638. // Check for negative case consistency. (leaks upon test failure.)
  639. REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(scratchKey1, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone));
  640. GrScratchKey scratchKey;
  641. TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
  642. // Scratch resources are registered with GrResourceCache just by existing. There are 2.
  643. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  644. SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
  645. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  646. REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
  647. cache->getResourceBytes());
  648. // Our refs mean that the resources are non purgeable.
  649. cache->purgeAllUnlocked();
  650. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  651. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  652. // Unref but don't purge
  653. a->unref();
  654. b->unref();
  655. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  656. SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
  657. // Purge again. This time resources should be purgeable.
  658. cache->purgeAllUnlocked();
  659. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  660. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  661. SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
  662. }
  663. static void test_remove_scratch_key(skiatest::Reporter* reporter) {
  664. Mock mock(5, 30000);
  665. GrContext* context = mock.context();
  666. GrResourceCache* cache = mock.cache();
  667. GrGpu* gpu = context->priv().getGpu();
  668. // Create two resources that have the same scratch key.
  669. TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  670. TestResource::kB_SimulatedProperty);
  671. TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  672. TestResource::kB_SimulatedProperty);
  673. a->unref();
  674. b->unref();
  675. GrScratchKey scratchKey;
  676. // Ensure that scratch key lookup is correct for negative case.
  677. TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
  678. // (following leaks upon test failure).
  679. REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone) == nullptr);
  680. // Scratch resources are registered with GrResourceCache just by existing. There are 2.
  681. TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
  682. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  683. SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
  684. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  685. // Find the first resource and remove its scratch key
  686. GrGpuResource* find;
  687. find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  688. find->resourcePriv().removeScratchKey();
  689. // It's still alive, but not cached by scratch key anymore
  690. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  691. SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
  692. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  693. // The cache should immediately delete it when it's unrefed since it isn't accessible.
  694. find->unref();
  695. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  696. SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
  697. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  698. // Repeat for the second resource.
  699. find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  700. find->resourcePriv().removeScratchKey();
  701. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  702. SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
  703. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  704. // Should be able to call this multiple times with no problem.
  705. find->resourcePriv().removeScratchKey();
  706. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  707. SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
  708. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  709. find->unref();
  710. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  711. SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
  712. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  713. }
  714. static void test_scratch_key_consistency(skiatest::Reporter* reporter) {
  715. Mock mock(5, 30000);
  716. GrContext* context = mock.context();
  717. GrResourceCache* cache = mock.cache();
  718. GrGpu* gpu = context->priv().getGpu();
  719. // Create two resources that have the same scratch key.
  720. TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  721. TestResource::kB_SimulatedProperty);
  722. TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  723. TestResource::kB_SimulatedProperty);
  724. a->unref();
  725. b->unref();
  726. GrScratchKey scratchKey;
  727. // Ensure that scratch key comparison and assignment is consistent.
  728. GrScratchKey scratchKey1;
  729. TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
  730. GrScratchKey scratchKey2;
  731. TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2);
  732. REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize());
  733. REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2);
  734. REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1);
  735. scratchKey = scratchKey1;
  736. REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
  737. REPORTER_ASSERT(reporter, scratchKey1 == scratchKey);
  738. REPORTER_ASSERT(reporter, scratchKey == scratchKey1);
  739. REPORTER_ASSERT(reporter, scratchKey2 != scratchKey);
  740. REPORTER_ASSERT(reporter, scratchKey != scratchKey2);
  741. scratchKey = scratchKey2;
  742. REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
  743. REPORTER_ASSERT(reporter, scratchKey1 != scratchKey);
  744. REPORTER_ASSERT(reporter, scratchKey != scratchKey1);
  745. REPORTER_ASSERT(reporter, scratchKey2 == scratchKey);
  746. REPORTER_ASSERT(reporter, scratchKey == scratchKey2);
  747. // Ensure that scratch key lookup is correct for negative case.
  748. TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
  749. // (following leaks upon test failure).
  750. REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone) == nullptr);
  751. // Find the first resource with a scratch key and a copy of a scratch key.
  752. TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
  753. GrGpuResource* find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  754. REPORTER_ASSERT(reporter, find != nullptr);
  755. find->unref();
  756. scratchKey2 = scratchKey;
  757. find = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  758. REPORTER_ASSERT(reporter, find != nullptr);
  759. REPORTER_ASSERT(reporter, find == a || find == b);
  760. GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  761. REPORTER_ASSERT(reporter, find2 != nullptr);
  762. REPORTER_ASSERT(reporter, find2 == a || find2 == b);
  763. REPORTER_ASSERT(reporter, find2 != find);
  764. find2->unref();
  765. find->unref();
  766. }
  767. static void test_duplicate_unique_key(skiatest::Reporter* reporter) {
  768. Mock mock(5, 30000);
  769. GrContext* context = mock.context();
  770. GrResourceCache* cache = mock.cache();
  771. GrGpu* gpu = context->priv().getGpu();
  772. GrUniqueKey key;
  773. make_unique_key<0>(&key, 0);
  774. // Create two resources that we will attempt to register with the same unique key.
  775. TestResource* a = new TestResource(gpu, SkBudgeted::kYes, 11);
  776. // Set key on resource a.
  777. a->resourcePriv().setUniqueKey(key);
  778. REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
  779. a->unref();
  780. // Make sure that redundantly setting a's key works.
  781. a->resourcePriv().setUniqueKey(key);
  782. REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
  783. a->unref();
  784. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  785. REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes());
  786. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  787. // Create resource b and set the same key. It should replace a's unique key cache entry.
  788. TestResource* b = new TestResource(gpu, SkBudgeted::kYes, 12);
  789. b->resourcePriv().setUniqueKey(key);
  790. REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key));
  791. b->unref();
  792. // Still have two resources because a is still reffed.
  793. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  794. REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes());
  795. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  796. a->unref();
  797. // Now a should be gone.
  798. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  799. REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
  800. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  801. // Now replace b with c, but make sure c can start with one unique key and change it to b's key.
  802. // Also make b be unreffed when replacement occurs.
  803. b->unref();
  804. TestResource* c = new TestResource(gpu, SkBudgeted::kYes, 13);
  805. GrUniqueKey differentKey;
  806. make_unique_key<0>(&differentKey, 1);
  807. c->resourcePriv().setUniqueKey(differentKey);
  808. REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
  809. REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes());
  810. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  811. // c replaces b and b should be immediately purged.
  812. c->resourcePriv().setUniqueKey(key);
  813. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  814. REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
  815. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  816. // c shouldn't be purged because it is ref'ed.
  817. cache->purgeAllUnlocked();
  818. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  819. REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
  820. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  821. // Drop the ref on c, it should be kept alive because it has a unique key.
  822. c->unref();
  823. REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
  824. REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
  825. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  826. // Verify that we can find c, then remove its unique key. It should get purged immediately.
  827. REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key));
  828. c->resourcePriv().removeUniqueKey();
  829. c->unref();
  830. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  831. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  832. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  833. {
  834. GrUniqueKey key2;
  835. make_unique_key<0>(&key2, 0);
  836. sk_sp<TestResource> d(new TestResource(gpu));
  837. int foo = 4132;
  838. key2.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo)));
  839. d->resourcePriv().setUniqueKey(key2);
  840. }
  841. GrUniqueKey key3;
  842. make_unique_key<0>(&key3, 0);
  843. sk_sp<GrGpuResource> d2(cache->findAndRefUniqueResource(key3));
  844. REPORTER_ASSERT(reporter, *(int*) d2->getUniqueKey().getCustomData()->data() == 4132);
  845. }
  846. static void test_purge_invalidated(skiatest::Reporter* reporter) {
  847. Mock mock(5, 30000);
  848. GrContext* context = mock.context();
  849. GrResourceCache* cache = mock.cache();
  850. GrGpu* gpu = context->priv().getGpu();
  851. GrUniqueKey key1, key2, key3;
  852. make_unique_key<0>(&key1, 1);
  853. make_unique_key<0>(&key2, 2);
  854. make_unique_key<0>(&key3, 3);
  855. // Add three resources to the cache. Only c is usable as scratch.
  856. TestResource* a = new TestResource(gpu);
  857. TestResource* b = new TestResource(gpu);
  858. TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  859. TestResource::kA_SimulatedProperty);
  860. a->resourcePriv().setUniqueKey(key1);
  861. b->resourcePriv().setUniqueKey(key2);
  862. c->resourcePriv().setUniqueKey(key3);
  863. a->unref();
  864. // hold b until *after* the message is sent.
  865. c->unref();
  866. REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
  867. REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
  868. REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
  869. REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
  870. typedef GrUniqueKeyInvalidatedMessage Msg;
  871. typedef SkMessageBus<GrUniqueKeyInvalidatedMessage> Bus;
  872. // Invalidate two of the three, they should be purged and no longer accessible via their keys.
  873. Bus::Post(Msg(key1, context->priv().contextID()));
  874. Bus::Post(Msg(key2, context->priv().contextID()));
  875. cache->purgeAsNeeded();
  876. // a should be deleted now, but we still have a ref on b.
  877. REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
  878. REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
  879. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  880. REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
  881. // Invalidate the third.
  882. Bus::Post(Msg(key3, context->priv().contextID()));
  883. cache->purgeAsNeeded();
  884. // we still have a ref on b, c should be recycled as scratch.
  885. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  886. REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3));
  887. // make b purgeable. It should be immediately deleted since it has no key.
  888. b->unref();
  889. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  890. // Make sure we actually get to c via it's scratch key, before we say goodbye.
  891. GrScratchKey scratchKey;
  892. TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
  893. GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  894. REPORTER_ASSERT(reporter, scratch == c);
  895. SkSafeUnref(scratch);
  896. // Get rid of c.
  897. cache->purgeAllUnlocked();
  898. scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, GrResourceCache::ScratchFlags::kNone);
  899. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  900. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  901. REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
  902. REPORTER_ASSERT(reporter, !scratch);
  903. SkSafeUnref(scratch);
  904. }
  905. static void test_cache_chained_purge(skiatest::Reporter* reporter) {
  906. Mock mock(3, 30000);
  907. GrContext* context = mock.context();
  908. GrResourceCache* cache = mock.cache();
  909. GrGpu* gpu = context->priv().getGpu();
  910. GrUniqueKey key1, key2;
  911. make_unique_key<0>(&key1, 1);
  912. make_unique_key<0>(&key2, 2);
  913. sk_sp<TestResource> a(new TestResource(gpu));
  914. sk_sp<TestResource> b(new TestResource(gpu));
  915. a->resourcePriv().setUniqueKey(key1);
  916. b->resourcePriv().setUniqueKey(key2);
  917. // Make a cycle
  918. a->setUnrefWhenDestroyed(b);
  919. b->setUnrefWhenDestroyed(a);
  920. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  921. TestResource* unownedA = a.release();
  922. unownedA->unref();
  923. b.reset();
  924. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  925. cache->purgeAllUnlocked();
  926. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  927. // Break the cycle
  928. unownedA->setUnrefWhenDestroyed(nullptr);
  929. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  930. cache->purgeAllUnlocked();
  931. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  932. }
  933. static void test_timestamp_wrap(skiatest::Reporter* reporter) {
  934. static const int kCount = 50;
  935. static const int kBudgetCnt = kCount / 2;
  936. static const int kLockedFreq = 8;
  937. static const int kBudgetSize = 0x80000000;
  938. SkRandom random;
  939. // Run the test 2*kCount times;
  940. for (int i = 0; i < 2 * kCount; ++i ) {
  941. Mock mock(kBudgetCnt, kBudgetSize);
  942. GrContext* context = mock.context();
  943. GrResourceCache* cache = mock.cache();
  944. GrGpu* gpu = context->priv().getGpu();
  945. // Pick a random number of resources to add before the timestamp will wrap.
  946. cache->changeTimestamp(UINT32_MAX - random.nextULessThan(kCount + 1));
  947. static const int kNumToPurge = kCount - kBudgetCnt;
  948. SkTDArray<int> shouldPurgeIdxs;
  949. int purgeableCnt = 0;
  950. SkTDArray<GrGpuResource*> resourcesToUnref;
  951. // Add kCount resources, holding onto resources at random so we have a mix of purgeable and
  952. // unpurgeable resources.
  953. for (int j = 0; j < kCount; ++j) {
  954. GrUniqueKey key;
  955. make_unique_key<0>(&key, j);
  956. TestResource* r = new TestResource(gpu);
  957. r->resourcePriv().setUniqueKey(key);
  958. if (random.nextU() % kLockedFreq) {
  959. // Make this is purgeable.
  960. r->unref();
  961. ++purgeableCnt;
  962. if (purgeableCnt <= kNumToPurge) {
  963. *shouldPurgeIdxs.append() = j;
  964. }
  965. } else {
  966. *resourcesToUnref.append() = r;
  967. }
  968. }
  969. // Verify that the correct resources were purged.
  970. int currShouldPurgeIdx = 0;
  971. for (int j = 0; j < kCount; ++j) {
  972. GrUniqueKey key;
  973. make_unique_key<0>(&key, j);
  974. GrGpuResource* res = cache->findAndRefUniqueResource(key);
  975. if (currShouldPurgeIdx < shouldPurgeIdxs.count() &&
  976. shouldPurgeIdxs[currShouldPurgeIdx] == j) {
  977. ++currShouldPurgeIdx;
  978. REPORTER_ASSERT(reporter, nullptr == res);
  979. } else {
  980. REPORTER_ASSERT(reporter, nullptr != res);
  981. }
  982. SkSafeUnref(res);
  983. }
  984. for (int j = 0; j < resourcesToUnref.count(); ++j) {
  985. resourcesToUnref[j]->unref();
  986. }
  987. }
  988. }
  989. static void test_time_purge(skiatest::Reporter* reporter) {
  990. Mock mock(1000000, 1000000);
  991. GrContext* context = mock.context();
  992. GrResourceCache* cache = mock.cache();
  993. GrGpu* gpu = context->priv().getGpu();
  994. static constexpr int kCnts[] = {1, 10, 1024};
  995. auto nowish = []() {
  996. // We sleep so that we ensure we get a value that is greater than the last call to
  997. // GrStdSteadyClock::now().
  998. std::this_thread::sleep_for(GrStdSteadyClock::duration(5));
  999. auto result = GrStdSteadyClock::now();
  1000. // Also sleep afterwards so we don't get this value again.
  1001. std::this_thread::sleep_for(GrStdSteadyClock::duration(5));
  1002. return result;
  1003. };
  1004. for (int cnt : kCnts) {
  1005. std::unique_ptr<GrStdSteadyClock::time_point[]> timeStamps(
  1006. new GrStdSteadyClock::time_point[cnt]);
  1007. {
  1008. // Insert resources and get time points between each addition.
  1009. for (int i = 0; i < cnt; ++i) {
  1010. TestResource* r = new TestResource(gpu);
  1011. GrUniqueKey k;
  1012. make_unique_key<1>(&k, i);
  1013. r->resourcePriv().setUniqueKey(k);
  1014. r->unref();
  1015. timeStamps.get()[i] = nowish();
  1016. }
  1017. // Purge based on the time points between resource additions. Each purge should remove
  1018. // the oldest resource.
  1019. for (int i = 0; i < cnt; ++i) {
  1020. cache->purgeResourcesNotUsedSince(timeStamps[i]);
  1021. REPORTER_ASSERT(reporter, cnt - i - 1 == cache->getResourceCount());
  1022. for (int j = 0; j < i; ++j) {
  1023. GrUniqueKey k;
  1024. make_unique_key<1>(&k, j);
  1025. GrGpuResource* r = cache->findAndRefUniqueResource(k);
  1026. REPORTER_ASSERT(reporter, !SkToBool(r));
  1027. SkSafeUnref(r);
  1028. }
  1029. }
  1030. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  1031. cache->purgeAllUnlocked();
  1032. }
  1033. // Do a similar test but where we leave refs on some resources to prevent them from being
  1034. // purged.
  1035. {
  1036. std::unique_ptr<GrGpuResource* []> refedResources(new GrGpuResource*[cnt / 2]);
  1037. for (int i = 0; i < cnt; ++i) {
  1038. TestResource* r = new TestResource(gpu);
  1039. GrUniqueKey k;
  1040. make_unique_key<1>(&k, i);
  1041. r->resourcePriv().setUniqueKey(k);
  1042. // Leave a ref on every other resource, beginning with the first.
  1043. if (SkToBool(i & 0x1)) {
  1044. refedResources.get()[i / 2] = r;
  1045. } else {
  1046. r->unref();
  1047. }
  1048. timeStamps.get()[i] = nowish();
  1049. }
  1050. for (int i = 0; i < cnt; ++i) {
  1051. // Should get a resource purged every other frame.
  1052. cache->purgeResourcesNotUsedSince(timeStamps[i]);
  1053. REPORTER_ASSERT(reporter, cnt - i / 2 - 1 == cache->getResourceCount());
  1054. }
  1055. // Unref all the resources that we kept refs on in the first loop.
  1056. for (int i = 0; i < (cnt / 2); ++i) {
  1057. refedResources.get()[i]->unref();
  1058. cache->purgeResourcesNotUsedSince(nowish());
  1059. REPORTER_ASSERT(reporter, cnt / 2 - i - 1 == cache->getResourceCount());
  1060. }
  1061. cache->purgeAllUnlocked();
  1062. }
  1063. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  1064. // Verify that calling flush() on a GrContext with nothing to do will not trigger resource
  1065. // eviction
  1066. context->flush();
  1067. for (int i = 0; i < 10; ++i) {
  1068. TestResource* r = new TestResource(gpu);
  1069. GrUniqueKey k;
  1070. make_unique_key<1>(&k, i);
  1071. r->resourcePriv().setUniqueKey(k);
  1072. r->unref();
  1073. }
  1074. REPORTER_ASSERT(reporter, 10 == cache->getResourceCount());
  1075. context->flush();
  1076. REPORTER_ASSERT(reporter, 10 == cache->getResourceCount());
  1077. cache->purgeResourcesNotUsedSince(nowish());
  1078. REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
  1079. }
  1080. }
  1081. static void test_partial_purge(skiatest::Reporter* reporter) {
  1082. Mock mock(6, 100);
  1083. GrContext* context = mock.context();
  1084. GrResourceCache* cache = mock.cache();
  1085. GrGpu* gpu = context->priv().getGpu();
  1086. enum TestsCase {
  1087. kOnlyScratch_TestCase = 0,
  1088. kPartialScratch_TestCase = 1,
  1089. kAllScratch_TestCase = 2,
  1090. kPartial_TestCase = 3,
  1091. kAll_TestCase = 4,
  1092. kNone_TestCase = 5,
  1093. kEndTests_TestCase = kNone_TestCase + 1
  1094. };
  1095. for (int testCase = 0; testCase < kEndTests_TestCase; testCase++) {
  1096. GrUniqueKey key1, key2, key3;
  1097. make_unique_key<0>(&key1, 1);
  1098. make_unique_key<0>(&key2, 2);
  1099. make_unique_key<0>(&key3, 3);
  1100. // Add three unique resources to the cache.
  1101. TestResource *unique1 = new TestResource(gpu, SkBudgeted::kYes, 10);
  1102. TestResource *unique2 = new TestResource(gpu, SkBudgeted::kYes, 11);
  1103. TestResource *unique3 = new TestResource(gpu, SkBudgeted::kYes, 12);
  1104. unique1->resourcePriv().setUniqueKey(key1);
  1105. unique2->resourcePriv().setUniqueKey(key2);
  1106. unique3->resourcePriv().setUniqueKey(key3);
  1107. // Add two scratch resources to the cache.
  1108. TestResource *scratch1 = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  1109. TestResource::kA_SimulatedProperty,
  1110. 13);
  1111. TestResource *scratch2 = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
  1112. TestResource::kB_SimulatedProperty,
  1113. 14);
  1114. REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount());
  1115. REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes());
  1116. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  1117. // Add resources to the purgeable queue
  1118. unique1->unref();
  1119. scratch1->unref();
  1120. unique2->unref();
  1121. scratch2->unref();
  1122. unique3->unref();
  1123. REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount());
  1124. REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes());
  1125. REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes());
  1126. switch(testCase) {
  1127. case kOnlyScratch_TestCase: {
  1128. context->purgeUnlockedResources(14, true);
  1129. REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount());
  1130. REPORTER_ASSERT(reporter, 33 == cache->getBudgetedResourceBytes());
  1131. break;
  1132. }
  1133. case kPartialScratch_TestCase: {
  1134. context->purgeUnlockedResources(3, true);
  1135. REPORTER_ASSERT(reporter, 4 == cache->getBudgetedResourceCount());
  1136. REPORTER_ASSERT(reporter, 47 == cache->getBudgetedResourceBytes());
  1137. break;
  1138. }
  1139. case kAllScratch_TestCase: {
  1140. context->purgeUnlockedResources(50, true);
  1141. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  1142. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  1143. break;
  1144. }
  1145. case kPartial_TestCase: {
  1146. context->purgeUnlockedResources(13, false);
  1147. REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount());
  1148. REPORTER_ASSERT(reporter, 37 == cache->getBudgetedResourceBytes());
  1149. break;
  1150. }
  1151. case kAll_TestCase: {
  1152. context->purgeUnlockedResources(50, false);
  1153. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  1154. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
  1155. break;
  1156. }
  1157. case kNone_TestCase: {
  1158. context->purgeUnlockedResources(0, true);
  1159. context->purgeUnlockedResources(0, false);
  1160. REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount());
  1161. REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes());
  1162. REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes());
  1163. break;
  1164. }
  1165. }
  1166. // ensure all are purged before the next
  1167. context->priv().testingOnly_purgeAllUnlockedResources();
  1168. REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
  1169. REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
  1170. }
  1171. }
  1172. static void test_large_resource_count(skiatest::Reporter* reporter) {
  1173. // Set the cache size to double the resource count because we're going to create 2x that number
  1174. // resources, using two different key domains. Add a little slop to the bytes because we resize
  1175. // down to 1 byte after creating the resource.
  1176. static const int kResourceCnt = 2000;
  1177. Mock mock(2 * kResourceCnt, 2 * kResourceCnt + 1000);
  1178. GrContext* context = mock.context();
  1179. GrResourceCache* cache = mock.cache();
  1180. GrGpu* gpu = context->priv().getGpu();
  1181. for (int i = 0; i < kResourceCnt; ++i) {
  1182. GrUniqueKey key1, key2;
  1183. make_unique_key<1>(&key1, i);
  1184. make_unique_key<2>(&key2, i);
  1185. TestResource* resource;
  1186. resource = new TestResource(gpu, SkBudgeted::kYes, 1);
  1187. resource->resourcePriv().setUniqueKey(key1);
  1188. resource->unref();
  1189. resource = new TestResource(gpu, SkBudgeted::kYes, 1);
  1190. resource->resourcePriv().setUniqueKey(key2);
  1191. resource->unref();
  1192. }
  1193. REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt);
  1194. REPORTER_ASSERT(reporter, cache->getPurgeableBytes() == 2 * kResourceCnt);
  1195. REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 2 * kResourceCnt);
  1196. REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 2 * kResourceCnt);
  1197. REPORTER_ASSERT(reporter, cache->getResourceBytes() == 2 * kResourceCnt);
  1198. REPORTER_ASSERT(reporter, cache->getResourceCount() == 2 * kResourceCnt);
  1199. for (int i = 0; i < kResourceCnt; ++i) {
  1200. GrUniqueKey key1, key2;
  1201. make_unique_key<1>(&key1, i);
  1202. make_unique_key<2>(&key2, i);
  1203. REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
  1204. REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
  1205. }
  1206. cache->purgeAllUnlocked();
  1207. REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0);
  1208. REPORTER_ASSERT(reporter, cache->getPurgeableBytes() == 0);
  1209. REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 0);
  1210. REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 0);
  1211. REPORTER_ASSERT(reporter, cache->getResourceBytes() == 0);
  1212. REPORTER_ASSERT(reporter, cache->getResourceCount() == 0);
  1213. for (int i = 0; i < kResourceCnt; ++i) {
  1214. GrUniqueKey key1, key2;
  1215. make_unique_key<1>(&key1, i);
  1216. make_unique_key<2>(&key2, i);
  1217. REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
  1218. REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
  1219. }
  1220. }
  1221. static void test_custom_data(skiatest::Reporter* reporter) {
  1222. GrUniqueKey key1, key2;
  1223. make_unique_key<0>(&key1, 1);
  1224. make_unique_key<0>(&key2, 2);
  1225. int foo = 4132;
  1226. key1.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo)));
  1227. REPORTER_ASSERT(reporter, *(int*) key1.getCustomData()->data() == 4132);
  1228. REPORTER_ASSERT(reporter, key2.getCustomData() == nullptr);
  1229. // Test that copying a key also takes a ref on its custom data.
  1230. GrUniqueKey key3 = key1;
  1231. REPORTER_ASSERT(reporter, *(int*) key3.getCustomData()->data() == 4132);
  1232. }
  1233. static void test_abandoned(skiatest::Reporter* reporter) {
  1234. Mock mock(10, 300);
  1235. GrContext* context = mock.context();
  1236. GrGpu* gpu = context->priv().getGpu();
  1237. sk_sp<GrGpuResource> resource(new TestResource(gpu));
  1238. context->abandonContext();
  1239. REPORTER_ASSERT(reporter, resource->wasDestroyed());
  1240. // Call all the public methods on resource in the abandoned state. They shouldn't crash.
  1241. resource->uniqueID();
  1242. resource->getUniqueKey();
  1243. resource->wasDestroyed();
  1244. resource->gpuMemorySize();
  1245. resource->getContext();
  1246. resource->resourcePriv().getScratchKey();
  1247. resource->resourcePriv().budgetedType();
  1248. resource->resourcePriv().makeBudgeted();
  1249. resource->resourcePriv().makeUnbudgeted();
  1250. resource->resourcePriv().removeScratchKey();
  1251. GrUniqueKey key;
  1252. make_unique_key<0>(&key, 1);
  1253. resource->resourcePriv().setUniqueKey(key);
  1254. resource->resourcePriv().removeUniqueKey();
  1255. }
  1256. static void test_tags(skiatest::Reporter* reporter) {
  1257. #ifdef SK_DEBUG
  1258. // We will insert 1 resource with tag "tag1", 2 with "tag2", and so on, up through kLastTagIdx.
  1259. static constexpr int kLastTagIdx = 10;
  1260. static constexpr int kNumResources = kLastTagIdx * (kLastTagIdx + 1) / 2;
  1261. Mock mock(kNumResources, kNumResources * TestResource::kDefaultSize);
  1262. GrContext* context = mock.context();
  1263. GrResourceCache* cache = mock.cache();
  1264. GrGpu* gpu = context->priv().getGpu();
  1265. // tag strings are expected to be long lived
  1266. std::vector<SkString> tagStrings;
  1267. SkString tagStr;
  1268. int tagIdx = 0;
  1269. int currTagCnt = 0;
  1270. for (int i = 0; i < kNumResources; ++i, ++currTagCnt) {
  1271. sk_sp<GrGpuResource> resource(new TestResource(gpu));
  1272. GrUniqueKey key;
  1273. if (currTagCnt == tagIdx) {
  1274. tagIdx += 1;
  1275. currTagCnt = 0;
  1276. tagStr.printf("tag%d", tagIdx);
  1277. tagStrings.emplace_back(tagStr);
  1278. }
  1279. make_unique_key<1>(&key, i, tagStrings.back().c_str());
  1280. resource->resourcePriv().setUniqueKey(key);
  1281. }
  1282. SkASSERT(kLastTagIdx == tagIdx);
  1283. SkASSERT(currTagCnt == kLastTagIdx);
  1284. // Test i = 0 to exercise unused tag string.
  1285. for (int i = 0; i <= kLastTagIdx; ++i) {
  1286. tagStr.printf("tag%d", i);
  1287. REPORTER_ASSERT(reporter, cache->countUniqueKeysWithTag(tagStr.c_str()) == i);
  1288. }
  1289. #endif
  1290. }
  1291. static void test_free_resource_messages(skiatest::Reporter* reporter) {
  1292. Mock mock(10, 30000);
  1293. GrContext* context = mock.context();
  1294. GrResourceCache* cache = mock.cache();
  1295. GrGpu* gpu = context->priv().getGpu();
  1296. TestResource* wrapped1 = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes);
  1297. cache->insertDelayedResourceUnref(wrapped1);
  1298. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  1299. TestResource* wrapped2 = TestResource::CreateWrapped(gpu, GrWrapCacheable::kYes);
  1300. cache->insertDelayedResourceUnref(wrapped2);
  1301. // An uncacheable cross-context should not be purged as soon as we drop our ref. This
  1302. // is because inserting it as a cross-context resource actually holds a ref until the
  1303. // message is received.
  1304. TestResource* wrapped3 = TestResource::CreateWrapped(gpu, GrWrapCacheable::kNo);
  1305. cache->insertDelayedResourceUnref(wrapped3);
  1306. REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
  1307. // Have only ref waiting on message.
  1308. wrapped1->unref();
  1309. wrapped2->unref();
  1310. wrapped3->unref();
  1311. REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
  1312. // This should free nothing since no messages were sent.
  1313. cache->purgeAsNeeded();
  1314. // Send message to free the first resource
  1315. GrGpuResourceFreedMessage msg1{wrapped1, context->priv().contextID()};
  1316. SkMessageBus<GrGpuResourceFreedMessage>::Post(msg1);
  1317. cache->purgeAsNeeded();
  1318. REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
  1319. GrGpuResourceFreedMessage msg2{wrapped3, context->priv().contextID()};
  1320. SkMessageBus<GrGpuResourceFreedMessage>::Post(msg2);
  1321. cache->purgeAsNeeded();
  1322. REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
  1323. mock.reset();
  1324. REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
  1325. }
  1326. DEF_GPUTEST(ResourceCacheMisc, reporter, /* options */) {
  1327. // The below tests create their own mock contexts.
  1328. test_no_key(reporter);
  1329. test_purge_unlocked(reporter);
  1330. test_budgeting(reporter);
  1331. test_unbudgeted(reporter);
  1332. test_unbudgeted_to_scratch(reporter);
  1333. test_duplicate_unique_key(reporter);
  1334. test_duplicate_scratch_key(reporter);
  1335. test_remove_scratch_key(reporter);
  1336. test_scratch_key_consistency(reporter);
  1337. test_purge_invalidated(reporter);
  1338. test_cache_chained_purge(reporter);
  1339. test_timestamp_wrap(reporter);
  1340. test_time_purge(reporter);
  1341. test_partial_purge(reporter);
  1342. test_large_resource_count(reporter);
  1343. test_custom_data(reporter);
  1344. test_abandoned(reporter);
  1345. test_tags(reporter);
  1346. test_free_resource_messages(reporter);
  1347. }
  1348. ////////////////////////////////////////////////////////////////////////////////
  1349. static sk_sp<GrTexture> make_normal_texture(GrResourceProvider* provider,
  1350. GrRenderable renderable,
  1351. int width, int height,
  1352. int sampleCnt) {
  1353. GrSurfaceDesc desc;
  1354. desc.fWidth = width;
  1355. desc.fHeight = height;
  1356. desc.fConfig = kRGBA_8888_GrPixelConfig;
  1357. return provider->createTexture(desc, renderable, sampleCnt, SkBudgeted::kYes, GrProtected::kNo,
  1358. GrResourceProvider::Flags::kNoPendingIO);
  1359. }
  1360. static sk_sp<GrTextureProxy> make_mipmap_proxy(GrProxyProvider* proxyProvider,
  1361. const GrCaps* caps,
  1362. GrRenderable renderable,
  1363. int width, int height,
  1364. int sampleCnt) {
  1365. GrSurfaceDesc desc;
  1366. desc.fWidth = width;
  1367. desc.fHeight = height;
  1368. desc.fConfig = kRGBA_8888_GrPixelConfig;
  1369. const GrBackendFormat format = caps->getBackendFormatFromColorType(GrColorType::kRGBA_8888);
  1370. auto origin = renderable == GrRenderable::kYes ? kBottomLeft_GrSurfaceOrigin
  1371. : kTopLeft_GrSurfaceOrigin;
  1372. return proxyProvider->createMipMapProxy(format, desc, renderable, sampleCnt, origin,
  1373. SkBudgeted::kYes, GrProtected::kNo);
  1374. }
  1375. // Exercise GrSurface::gpuMemorySize for different combos of MSAA, RT-only,
  1376. // Texture-only, both-RT-and-Texture and MIPmapped
  1377. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GPUMemorySize, reporter, ctxInfo) {
  1378. GrContext* context = ctxInfo.grContext();
  1379. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  1380. GrResourceProvider* resourceProvider = context->priv().resourceProvider();
  1381. static const int kSize = 64;
  1382. // Normal versions
  1383. {
  1384. sk_sp<GrTexture> tex;
  1385. tex = make_normal_texture(resourceProvider, GrRenderable::kYes, kSize, kSize, 1);
  1386. size_t size = tex->gpuMemorySize();
  1387. REPORTER_ASSERT(reporter, kSize*kSize*4 == size);
  1388. size_t sampleCount = (size_t)context->priv().caps()->getRenderTargetSampleCount(
  1389. 4, kRGBA_8888_GrPixelConfig);
  1390. if (sampleCount >= 4) {
  1391. tex = make_normal_texture(resourceProvider, GrRenderable::kYes, kSize, kSize,
  1392. sampleCount);
  1393. size = tex->gpuMemorySize();
  1394. REPORTER_ASSERT(reporter,
  1395. kSize*kSize*4 == size || // msaa4 failed
  1396. kSize*kSize*4*sampleCount == size || // auto-resolving
  1397. kSize*kSize*4*(sampleCount+1) == size); // explicit resolve buffer
  1398. }
  1399. tex = make_normal_texture(resourceProvider, GrRenderable::kNo, kSize, kSize, 1);
  1400. size = tex->gpuMemorySize();
  1401. REPORTER_ASSERT(reporter, kSize*kSize*4 == size);
  1402. }
  1403. // Mipmapped versions
  1404. const GrCaps* caps = context->priv().caps();
  1405. if (caps->mipMapSupport()) {
  1406. sk_sp<GrTextureProxy> proxy;
  1407. proxy = make_mipmap_proxy(proxyProvider, caps, GrRenderable::kYes, kSize, kSize, 1);
  1408. size_t size = proxy->gpuMemorySize();
  1409. REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size);
  1410. size_t sampleCount = (size_t)context->priv().caps()->getRenderTargetSampleCount(
  1411. 4, kRGBA_8888_GrPixelConfig);
  1412. if (sampleCount >= 4) {
  1413. proxy = make_mipmap_proxy(proxyProvider, caps, GrRenderable::kYes, kSize, kSize,
  1414. sampleCount);
  1415. size = proxy->gpuMemorySize();
  1416. REPORTER_ASSERT(reporter,
  1417. kSize*kSize*4+(kSize*kSize*4)/3 == size || // msaa4 failed
  1418. kSize*kSize*4*sampleCount+(kSize*kSize*4)/3 == size || // auto-resolving
  1419. kSize*kSize*4*(sampleCount+1)+(kSize*kSize*4)/3 == size); // explicit resolve buffer
  1420. }
  1421. proxy = make_mipmap_proxy(proxyProvider, caps, GrRenderable::kNo, kSize, kSize, 1);
  1422. size = proxy->gpuMemorySize();
  1423. REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size);
  1424. }
  1425. }
  1426. #if GR_GPU_STATS
  1427. DEF_GPUTEST_FOR_MOCK_CONTEXT(OverbudgetFlush, reporter, ctxInfo) {
  1428. GrContext* context = ctxInfo.grContext();
  1429. context->setResourceCacheLimits(1, 1);
  1430. // Helper that determines if cache is overbudget.
  1431. auto overbudget = [context] {
  1432. int uNum;
  1433. size_t uSize;
  1434. context->getResourceCacheUsage(&uNum, &uSize);
  1435. int bNum;
  1436. size_t bSize;
  1437. context->getResourceCacheLimits(&bNum, &bSize);
  1438. return uNum > bNum || uSize > bSize;
  1439. };
  1440. // Helper that does a trivial draw to a surface.
  1441. auto drawToSurf = [](SkSurface* surf) {
  1442. surf->getCanvas()->drawRect(SkRect::MakeWH(1,1), SkPaint());
  1443. };
  1444. // Helper that checks whether a flush has occurred between calls.
  1445. int baseFlushCount = 0;
  1446. auto getFlushCountDelta = [context, &baseFlushCount]() {
  1447. int cur = context->priv().getGpu()->stats()->numFinishFlushes();
  1448. int delta = cur - baseFlushCount;
  1449. baseFlushCount = cur;
  1450. return delta;
  1451. };
  1452. auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  1453. auto surf1 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 1, nullptr);
  1454. auto surf2 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 1, nullptr);
  1455. drawToSurf(surf1.get());
  1456. drawToSurf(surf2.get());
  1457. // Flush each surface once to ensure that their backing stores are allocated.
  1458. surf1->flush();
  1459. surf2->flush();
  1460. REPORTER_ASSERT(reporter, overbudget());
  1461. getFlushCountDelta();
  1462. // Nothing should be purgeable so drawing to either surface doesn't cause a flush.
  1463. drawToSurf(surf1.get());
  1464. REPORTER_ASSERT(reporter, !getFlushCountDelta());
  1465. drawToSurf(surf2.get());
  1466. REPORTER_ASSERT(reporter, !getFlushCountDelta());
  1467. REPORTER_ASSERT(reporter, overbudget());
  1468. // Make surf1 purgeable. Drawing to surf2 should flush.
  1469. surf1->flush();
  1470. surf1.reset();
  1471. drawToSurf(surf2.get());
  1472. REPORTER_ASSERT(reporter, getFlushCountDelta());
  1473. REPORTER_ASSERT(reporter, overbudget());
  1474. }
  1475. #endif