1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkString.h"
15 #include "include/core/SkSurface.h"
16 #include "include/core/SkTypes.h"
17 #include "include/gpu/GpuTypes.h"
18 #include "include/gpu/ganesh/GrBackendSurface.h"
19 #include "include/gpu/ganesh/GrDirectContext.h"
20 #include "include/gpu/ganesh/GrTypes.h"
21 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
22 #include "include/private/base/SkTArray.h"
23 #include "include/private/base/SkTo.h"
24 #include "include/private/gpu/ganesh/GrTypesPriv.h"
25 #include "src/gpu/ResourceKey.h"
26 #include "src/gpu/SkBackingFit.h"
27 #include "src/gpu/ganesh/GrCaps.h"
28 #include "src/gpu/ganesh/GrDirectContextPriv.h"
29 #include "src/gpu/ganesh/GrProxyProvider.h"
30 #include "src/gpu/ganesh/GrResourceAllocator.h"
31 #include "src/gpu/ganesh/GrResourceCache.h"
32 #include "src/gpu/ganesh/GrResourceProvider.h"
33 #include "src/gpu/ganesh/GrSurface.h"
34 #include "src/gpu/ganesh/GrSurfaceProxy.h"
35 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
36 #include "src/gpu/ganesh/GrTexture.h"
37 #include "src/gpu/ganesh/GrTextureProxy.h"
38 #include "tests/CtsEnforcement.h"
39 #include "tests/Test.h"
40 #include "tools/gpu/ManagedBackendTexture.h"
41
42 #include <array>
43 #include <cstddef>
44 #include <functional>
45 #include <utility>
46
47 using namespace skia_private;
48
49 class GrRecordingContext;
50 struct GrContextOptions;
51
52 namespace {
53 struct ProxyParams {
54 int fSize;
55 GrRenderable fRenderable;
56 GrColorType fColorType;
57 SkBackingFit fFit;
58 int fSampleCnt;
59 skgpu::Budgeted fBudgeted;
60 enum Kind {
61 kDeferred,
62 kBackend,
63 kFullyLazy,
64 kLazy,
65 kInstantiated
66 };
67 Kind fKind;
68 skgpu::UniqueKey fUniqueKey = skgpu::UniqueKey();
69 // TODO: do we care about mipmapping
70 };
71
72 constexpr GrRenderable kRT = GrRenderable::kYes;
73 constexpr GrRenderable kNotRT = GrRenderable::kNo;
74
75 constexpr GrColorType kRGBA = GrColorType::kRGBA_8888;
76 constexpr GrColorType kAlpha = GrColorType::kAlpha_8;
77
78 constexpr SkBackingFit kE = SkBackingFit::kExact;
79 constexpr SkBackingFit kA = SkBackingFit::kApprox;
80
81 constexpr skgpu::Budgeted kNotB = skgpu::Budgeted::kNo;
82 constexpr skgpu::Budgeted kB = skgpu::Budgeted::kYes;
83
84 constexpr ProxyParams::Kind kDeferred = ProxyParams::Kind::kDeferred;
85 constexpr ProxyParams::Kind kBackend = ProxyParams::Kind::kBackend;
86 constexpr ProxyParams::Kind kInstantiated = ProxyParams::Kind::kInstantiated;
87 constexpr ProxyParams::Kind kLazy = ProxyParams::Kind::kLazy;
88 constexpr ProxyParams::Kind kFullyLazy = ProxyParams::Kind::kFullyLazy;
89 }
90
make_deferred(GrProxyProvider * proxyProvider,const GrCaps * caps,const ProxyParams & p)91 static sk_sp<GrSurfaceProxy> make_deferred(GrProxyProvider* proxyProvider, const GrCaps* caps,
92 const ProxyParams& p) {
93 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
94 return proxyProvider->createProxy(format,
95 {p.fSize, p.fSize},
96 p.fRenderable,
97 p.fSampleCnt,
98 skgpu::Mipmapped::kNo,
99 p.fFit,
100 p.fBudgeted,
101 GrProtected::kNo,
102 /*label=*/"ResourceAllocatorTest_Deffered");
103 }
104
make_backend(GrDirectContext * dContext,const ProxyParams & p)105 static sk_sp<GrSurfaceProxy> make_backend(GrDirectContext* dContext, const ProxyParams& p) {
106 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
107
108 SkColorType skColorType = GrColorTypeToSkColorType(p.fColorType);
109 SkASSERT(SkColorType::kUnknown_SkColorType != skColorType);
110
111 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
112 dContext, p.fSize, p.fSize, skColorType, skgpu::Mipmapped::kNo, GrRenderable::kNo);
113
114 if (!mbet) {
115 return nullptr;
116 }
117
118 return proxyProvider->wrapBackendTexture(mbet->texture(),
119 kBorrow_GrWrapOwnership,
120 GrWrapCacheable::kNo,
121 kRead_GrIOType,
122 mbet->refCountedCallback());
123 }
124
make_fully_lazy(GrProxyProvider * proxyProvider,const GrCaps * caps,const ProxyParams & p)125 static sk_sp<GrSurfaceProxy> make_fully_lazy(GrProxyProvider* proxyProvider, const GrCaps* caps,
126 const ProxyParams& p) {
127 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
128 auto cb = [p](GrResourceProvider* provider, const GrSurfaceProxy::LazySurfaceDesc& desc) {
129 auto tex = provider->createTexture({p.fSize, p.fSize},
130 desc.fFormat,
131 desc.fTextureType,
132 desc.fRenderable,
133 desc.fSampleCnt,
134 desc.fMipmapped,
135 desc.fBudgeted,
136 desc.fProtected,
137 /*label=*/"ResourceAllocatorTest_FullLazy");
138 return GrSurfaceProxy::LazyCallbackResult(std::move(tex));
139 };
140 return GrProxyProvider::MakeFullyLazyProxy(std::move(cb), format, p.fRenderable, p.fSampleCnt,
141 GrProtected::kNo, *caps,
142 GrSurfaceProxy::UseAllocator::kYes);
143 }
144
make_lazy(GrProxyProvider * proxyProvider,const GrCaps * caps,const ProxyParams & p)145 static sk_sp<GrSurfaceProxy> make_lazy(GrProxyProvider* proxyProvider, const GrCaps* caps,
146 const ProxyParams& p) {
147 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
148 auto cb = [](GrResourceProvider* provider, const GrSurfaceProxy::LazySurfaceDesc& desc) {
149 auto tex = provider->createTexture(desc.fDimensions,
150 desc.fFormat,
151 desc.fTextureType,
152 desc.fRenderable,
153 desc.fSampleCnt,
154 desc.fMipmapped,
155 desc.fBudgeted,
156 desc.fProtected,
157 /*label=*/"ResourceAllocatorTest_Lazy");
158 return GrSurfaceProxy::LazyCallbackResult(std::move(tex));
159 };
160 return proxyProvider->createLazyProxy(std::move(cb),
161 format,
162 {p.fSize, p.fSize},
163 skgpu::Mipmapped::kNo,
164 GrMipmapStatus::kNotAllocated,
165 GrInternalSurfaceFlags::kNone,
166 p.fFit,
167 p.fBudgeted,
168 GrProtected::kNo,
169 GrSurfaceProxy::UseAllocator::kYes,
170 /*label=*/{});
171 }
172
make_proxy(GrDirectContext * dContext,const ProxyParams & p)173 static sk_sp<GrSurfaceProxy> make_proxy(GrDirectContext* dContext, const ProxyParams& p) {
174 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
175 const GrCaps* caps = dContext->priv().caps();
176 sk_sp<GrSurfaceProxy> proxy;
177 switch (p.fKind) {
178 case ProxyParams::kDeferred:
179 proxy = make_deferred(proxyProvider, caps, p);
180 break;
181 case ProxyParams::kBackend:
182 proxy = make_backend(dContext, p);
183 break;
184 case ProxyParams::kFullyLazy:
185 proxy = make_fully_lazy(proxyProvider, caps, p);
186 break;
187 case ProxyParams::kLazy:
188 proxy = make_lazy(proxyProvider, caps, p);
189 break;
190 case ProxyParams::kInstantiated:
191 proxy = make_deferred(proxyProvider, caps, p);
192 if (proxy) {
193 auto surf = proxy->priv().createSurface(dContext->priv().resourceProvider());
194 proxy->priv().assign(std::move(surf));
195 }
196 break;
197 }
198 if (proxy && p.fUniqueKey.isValid()) {
199 SkASSERT(proxy->asTextureProxy());
200 proxyProvider->assignUniqueKeyToProxy(p.fUniqueKey, proxy->asTextureProxy());
201 }
202 return proxy;
203 }
204
205 // Basic test that two proxies with overlapping intervals and compatible descriptors are
206 // assigned different GrSurfaces.
overlap_test(skiatest::Reporter * reporter,GrDirectContext * dContext,const sk_sp<GrSurfaceProxy> & p1,const sk_sp<GrSurfaceProxy> & p2,bool expectedResult)207 static void overlap_test(skiatest::Reporter* reporter, GrDirectContext* dContext,
208 const sk_sp<GrSurfaceProxy>& p1, const sk_sp<GrSurfaceProxy>& p2,
209 bool expectedResult) {
210 GrResourceAllocator alloc(dContext);
211
212 alloc.addInterval(p1.get(), 0, 4, GrResourceAllocator::ActualUse::kYes,
213 GrResourceAllocator::AllowRecycling::kYes);
214 alloc.incOps();
215 alloc.addInterval(p2.get(), 1, 2, GrResourceAllocator::ActualUse::kYes,
216 GrResourceAllocator::AllowRecycling::kYes);
217 alloc.incOps();
218
219 REPORTER_ASSERT(reporter, alloc.planAssignment());
220 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom());
221 REPORTER_ASSERT(reporter, alloc.assign());
222
223 REPORTER_ASSERT(reporter, p1->peekSurface());
224 REPORTER_ASSERT(reporter, p2->peekSurface());
225 bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
226 REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
227 }
228
229 // Test various cases when two proxies do not have overlapping intervals.
230 // This mainly acts as a test of the ResourceAllocator's free pool.
non_overlap_test(skiatest::Reporter * reporter,GrDirectContext * dContext,const sk_sp<GrSurfaceProxy> & p1,const sk_sp<GrSurfaceProxy> & p2,bool expectedResult)231 static void non_overlap_test(skiatest::Reporter* reporter, GrDirectContext* dContext,
232 const sk_sp<GrSurfaceProxy>& p1, const sk_sp<GrSurfaceProxy>& p2,
233 bool expectedResult) {
234 GrResourceAllocator alloc(dContext);
235
236 alloc.incOps();
237 alloc.incOps();
238 alloc.incOps();
239 alloc.incOps();
240 alloc.incOps();
241 alloc.incOps();
242
243 alloc.addInterval(p1.get(), 0, 2, GrResourceAllocator::ActualUse::kYes,
244 GrResourceAllocator::AllowRecycling::kYes);
245 alloc.addInterval(p2.get(), 3, 5, GrResourceAllocator::ActualUse::kYes,
246 GrResourceAllocator::AllowRecycling::kYes);
247
248 REPORTER_ASSERT(reporter, alloc.planAssignment());
249 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom());
250 REPORTER_ASSERT(reporter, alloc.assign());
251
252 REPORTER_ASSERT(reporter, p1->peekSurface());
253 REPORTER_ASSERT(reporter, p2->peekSurface());
254 bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
255 REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
256 }
257
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest,reporter,ctxInfo,CtsEnforcement::kNever)258 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest,
259 reporter,
260 ctxInfo,
261 CtsEnforcement::kNever) {
262 auto dContext = ctxInfo.directContext();
263 const GrCaps* caps = dContext->priv().caps();
264
265 struct TestCase {
266 ProxyParams fP1;
267 ProxyParams fP2;
268 bool fExpectation;
269 };
270
271 constexpr bool kShare = true;
272 constexpr bool kDontShare = false;
273
274 // Non-RT GrSurfaces are never recycled on some platforms.
275 bool kConditionallyShare = caps->reuseScratchTextures();
276
277 static const TestCase overlappingTests[] = {
278 // Two proxies with overlapping intervals and compatible descriptors should never share
279 // RT version
280 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
281 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
282 kDontShare},
283 // non-RT version
284 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
285 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
286 kDontShare},
287 };
288
289 for (size_t i = 0; i < std::size(overlappingTests); i++) {
290 const TestCase& test = overlappingTests[i];
291 sk_sp<GrSurfaceProxy> p1 = make_proxy(dContext, test.fP1);
292 sk_sp<GrSurfaceProxy> p2 = make_proxy(dContext, test.fP2);
293 reporter->push(SkStringPrintf("case %d", SkToInt(i)));
294 overlap_test(reporter, dContext, std::move(p1), std::move(p2), test.fExpectation);
295 reporter->pop();
296 }
297
298 auto beFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, GrRenderable::kYes);
299 int k2 = caps->getRenderTargetSampleCount(2, beFormat);
300 int k4 = caps->getRenderTargetSampleCount(4, beFormat);
301
302 // This cannot be made static as some of the members depend on non static variables like
303 // kConditionallyShare, k2, and k4.
304 const TestCase nonOverlappingTests[] = {
305 // Two non-overlapping intervals w/ compatible proxies should share
306 // both same size & approx
307 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
308 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
309 kShare},
310 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
311 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
312 kConditionallyShare},
313 // diffs sizes but still approx
314 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
315 {50, kRT, kRGBA, kA, 1, kNotB, kDeferred},
316 kShare},
317 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
318 {50, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
319 kConditionallyShare},
320 // sames sizes but exact
321 {{64, kRT, kRGBA, kE, 1, kNotB, kDeferred},
322 {64, kRT, kRGBA, kE, 1, kNotB, kDeferred},
323 kShare},
324 {{64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
325 {64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
326 kConditionallyShare},
327 // Two non-overlapping intervals w/ different exact sizes should not share
328 {{56, kRT, kRGBA, kE, 1, kNotB, kDeferred},
329 {54, kRT, kRGBA, kE, 1, kNotB, kDeferred},
330 kDontShare},
331 // Two non-overlapping intervals w/ _very different_ approx sizes should not share
332 {{255, kRT, kRGBA, kA, 1, kNotB, kDeferred},
333 {127, kRT, kRGBA, kA, 1, kNotB, kDeferred},
334 kDontShare},
335 // Two non-overlapping intervals w/ different MSAA sample counts should not share
336 {{64, kRT, kRGBA, kA, k2, kNotB, kDeferred},
337 {64, kRT, kRGBA, kA, k4, kNotB, kDeferred},
338 k2 == k4},
339 // Two non-overlapping intervals w/ different configs should not share
340 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
341 {64, kRT, kAlpha, kA, 1, kNotB, kDeferred},
342 kDontShare},
343 // Two non-overlapping intervals w/ different RT classifications should never share
344 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
345 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
346 kDontShare},
347 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
348 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
349 kDontShare},
350 // Two non-overlapping intervals w/ different origins should share
351 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
352 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
353 kShare},
354 // Wrapped backend textures should never be reused
355 {{64, kNotRT, kRGBA, kE, 1, kNotB, kBackend},
356 {64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
357 kDontShare}
358 };
359
360 for (size_t i = 0; i < std::size(nonOverlappingTests); i++) {
361 const TestCase& test = nonOverlappingTests[i];
362 sk_sp<GrSurfaceProxy> p1 = make_proxy(dContext, test.fP1);
363 sk_sp<GrSurfaceProxy> p2 = make_proxy(dContext, test.fP2);
364
365 if (!p1 || !p2) {
366 continue; // creation can fail (e.g., for msaa4 on iOS)
367 }
368
369 reporter->push(SkStringPrintf("case %d", SkToInt(i)));
370 non_overlap_test(reporter, dContext, std::move(p1), std::move(p2),
371 test.fExpectation);
372 reporter->pop();
373 }
374 }
375
draw(GrRecordingContext * rContext)376 static void draw(GrRecordingContext* rContext) {
377 SkImageInfo ii = SkImageInfo::Make(1024, 1024, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
378
379 sk_sp<SkSurface> s = SkSurfaces::RenderTarget(
380 rContext, skgpu::Budgeted::kYes, ii, 1, kTopLeft_GrSurfaceOrigin, nullptr);
381
382 SkCanvas* c = s->getCanvas();
383
384 c->clear(SK_ColorBLACK);
385 }
386
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorStressTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)387 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorStressTest,
388 reporter,
389 ctxInfo,
390 CtsEnforcement::kApiLevel_T) {
391 auto context = ctxInfo.directContext();
392
393 size_t maxBytes = context->getResourceCacheLimit();
394
395 context->setResourceCacheLimit(0); // We'll always be overbudget
396
397 draw(context);
398 draw(context);
399 draw(context);
400 draw(context);
401 context->flushAndSubmit();
402
403 context->setResourceCacheLimit(maxBytes);
404 }
405
406 struct Interval {
407 ProxyParams fParams;
408 int fStart;
409 int fEnd;
410 sk_sp<GrSurfaceProxy> fProxy = nullptr;
411 };
412
413 struct TestCase {
414 const char * fName;
415 bool fShouldFit;
416 size_t fBudget;
417 TArray<ProxyParams> fPurgeableResourcesInCache = {};
418 TArray<ProxyParams> fUnpurgeableResourcesInCache = {};
419 TArray<Interval> fIntervals;
420 };
421
memory_budget_test(skiatest::Reporter * reporter,GrDirectContext * dContext,const TestCase & test)422 static void memory_budget_test(skiatest::Reporter* reporter,
423 GrDirectContext* dContext,
424 const TestCase& test) {
425 // Reset cache.
426 auto cache = dContext->priv().getResourceCache();
427 cache->releaseAll();
428 cache->setLimit(test.fBudget);
429
430 // Add purgeable entries.
431 size_t expectedPurgeableBytes = 0;
432 TArray<sk_sp<GrSurface>> purgeableSurfaces;
433 for (auto& params : test.fPurgeableResourcesInCache) {
434 SkASSERT(params.fKind == kInstantiated);
435 sk_sp<GrSurfaceProxy> proxy = make_proxy(dContext, params);
436 REPORTER_ASSERT(reporter, proxy->peekSurface());
437 expectedPurgeableBytes += proxy->gpuMemorySize();
438 purgeableSurfaces.push_back(sk_ref_sp(proxy->peekSurface()));
439 }
440 purgeableSurfaces.clear();
441 REPORTER_ASSERT(reporter, expectedPurgeableBytes == cache->getPurgeableBytes(),
442 "%zu", cache->getPurgeableBytes());
443
444 // Add unpurgeable entries.
445 size_t expectedUnpurgeableBytes = 0;
446 TArray<sk_sp<GrSurface>> unpurgeableSurfaces;
447 for (auto& params : test.fUnpurgeableResourcesInCache) {
448 SkASSERT(params.fKind == kInstantiated);
449 sk_sp<GrSurfaceProxy> proxy = make_proxy(dContext, params);
450 REPORTER_ASSERT(reporter, proxy->peekSurface());
451 expectedUnpurgeableBytes += proxy->gpuMemorySize();
452 unpurgeableSurfaces.push_back(sk_ref_sp(proxy->peekSurface()));
453 }
454
455 auto unpurgeableBytes = cache->getBudgetedResourceBytes() - cache->getPurgeableBytes();
456 REPORTER_ASSERT(reporter, expectedUnpurgeableBytes == unpurgeableBytes,
457 "%zu", unpurgeableBytes);
458
459 // Add intervals and test.
460 GrResourceAllocator alloc(dContext);
461 for (auto& interval : test.fIntervals) {
462 for (int i = interval.fStart; i <= interval.fEnd; i++) {
463 alloc.incOps();
464 }
465 alloc.addInterval(interval.fProxy.get(), interval.fStart, interval.fEnd,
466 GrResourceAllocator::ActualUse::kYes,
467 GrResourceAllocator::AllowRecycling::kYes);
468 }
469 REPORTER_ASSERT(reporter, alloc.planAssignment());
470 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom() == test.fShouldFit);
471 }
472
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorMemoryBudgetTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)473 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorMemoryBudgetTest,
474 reporter,
475 ctxInfo,
476 CtsEnforcement::kApiLevel_T) {
477 auto dContext = ctxInfo.directContext();
478
479 constexpr bool kUnder = true;
480 constexpr bool kOver = false;
481 constexpr size_t kRGBA64Bytes = 4 * 64 * 64;
482 const ProxyParams kProxy64 = {64, kRT, kRGBA, kE, 1, kB, kDeferred};
483 const ProxyParams kProxy64NotBudgeted = {64, kRT, kRGBA, kE, 1, kNotB, kDeferred};
484 const ProxyParams kProxy64Lazy = {64, kRT, kRGBA, kE, 1, kB, kLazy};
485 const ProxyParams kProxy64FullyLazy = {64, kRT, kRGBA, kE, 1, kB, kFullyLazy};
486 const ProxyParams kProxy32Instantiated = {32, kRT, kRGBA, kE, 1, kB, kInstantiated};
487 const ProxyParams kProxy64Instantiated = {64, kRT, kRGBA, kE, 1, kB, kInstantiated};
488
489 TestCase tests[] = {
490 {"empty DAG", kUnder, 0, {}, {}, {}},
491 {"unbudgeted", kUnder, 0, {}, {}, {{kProxy64NotBudgeted, 0, 2}}},
492 {"basic", kUnder, kRGBA64Bytes, {}, {}, {{kProxy64, 0, 2}}},
493 {"basic, over", kOver, kRGBA64Bytes - 1, {}, {}, {{kProxy64, 0, 2}}},
494 {"shared", kUnder, kRGBA64Bytes, {}, {},
495 {
496 {kProxy64, 0, 2},
497 {kProxy64, 3, 5},
498 }},
499 {"retrieved from cache", kUnder, kRGBA64Bytes,
500 /* purgeable */{kProxy64Instantiated},
501 /* unpurgeable */{},
502 {
503 {kProxy64, 0, 2}
504 }},
505 {"purge 4", kUnder, kRGBA64Bytes,
506 /* purgeable */{
507 kProxy32Instantiated,
508 kProxy32Instantiated,
509 kProxy32Instantiated,
510 kProxy32Instantiated
511 },
512 /* unpurgeable */{},
513 {
514 {kProxy64, 0, 2}
515 }},
516 {"dont purge what we've reserved", kOver, kRGBA64Bytes,
517 /* purgeable */{kProxy64Instantiated},
518 /* unpurgeable */{},
519 {
520 {kProxy64, 0, 2},
521 {kProxy64, 1, 3}
522 }},
523 {"unpurgeable", kOver, kRGBA64Bytes,
524 /* purgeable */{},
525 /* unpurgeable */{kProxy64Instantiated},
526 {
527 {kProxy64, 0, 2}
528 }},
529 {"lazy", kUnder, kRGBA64Bytes,
530 /* purgeable */{},
531 /* unpurgeable */{},
532 {
533 {kProxy64Lazy, 0, 2}
534 }},
535 {"lazy, over", kOver, kRGBA64Bytes - 1,
536 /* purgeable */{},
537 /* unpurgeable */{},
538 {
539 {kProxy64Lazy, 0, 2}
540 }},
541 {"fully-lazy", kUnder, kRGBA64Bytes,
542 /* purgeable */{},
543 /* unpurgeable */{},
544 {
545 {kProxy64FullyLazy, 0, 2}
546 }},
547 {"fully-lazy, over", kOver, kRGBA64Bytes - 1,
548 /* purgeable */{},
549 /* unpurgeable */{},
550 {
551 {kProxy64FullyLazy, 0, 2}
552 }},
553 };
554 SkString match("");
555 for (size_t i = 0; i < std::size(tests); i++) {
556 TestCase& test = tests[i];
557 if (match.isEmpty() || match == SkString(test.fName)) {
558 // Create proxies
559 for (Interval& interval : test.fIntervals) {
560 interval.fProxy = make_proxy(dContext, interval.fParams);
561 }
562 reporter->push(SkString(test.fName));
563 memory_budget_test(reporter, dContext, test);
564 reporter->pop();
565 }
566 }
567 }
568