blob: 5e4349d5989bc791305303488188ba916dd54f7b [file] [log] [blame]
Robert Phillips5af44de2017-07-18 14:49:38 -04001/*
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
Robert Phillipse19babf2020-04-06 13:57:30 -04008#include "include/core/SkCanvas.h"
Brian Osmana5842bc2021-05-11 13:41:46 -04009#include "include/core/SkSpan.h"
Robert Phillipse19babf2020-04-06 13:57:30 -040010#include "include/core/SkSurface.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040011#include "include/gpu/GrDirectContext.h"
Adlai Hollera0693042020-10-14 11:23:11 -040012#include "src/gpu/GrDirectContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrGpu.h"
14#include "src/gpu/GrProxyProvider.h"
15#include "src/gpu/GrResourceAllocator.h"
Adlai Hollercd2f96d2021-04-09 17:58:14 -040016#include "src/gpu/GrResourceProviderPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrSurfaceProxyPriv.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000018#include "src/gpu/GrTexture.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040019#include "src/gpu/GrTextureProxy.h"
Robert Phillipse19babf2020-04-06 13:57:30 -040020#include "tests/Test.h"
Brian Salomon72050802020-10-12 20:45:06 -040021#include "tools/gpu/ManagedBackendTexture.h"
Robert Phillips1734dd32018-08-21 13:52:09 -040022
Adlai Holler3cffe812021-04-09 13:43:32 -040023namespace {
Robert Phillips57aa3672017-07-21 11:38:13 -040024struct ProxyParams {
25 int fSize;
Brian Salomonf2c2ba92019-07-17 09:59:59 -040026 GrRenderable fRenderable;
Robert Phillipsc80b0e92019-07-23 10:27:09 -040027 GrColorType fColorType;
Robert Phillips57aa3672017-07-21 11:38:13 -040028 SkBackingFit fFit;
29 int fSampleCnt;
Robert Phillipsc476e5d2019-03-26 14:50:08 -040030 SkBudgeted fBudgeted;
Adlai Holler3cffe812021-04-09 13:43:32 -040031 enum Kind {
32 kDeferred,
33 kBackend,
34 kFullyLazy,
35 kLazy,
36 kInstantiated
37 };
38 Kind fKind;
39 GrUniqueKey fUniqueKey = GrUniqueKey();
Robert Phillips57aa3672017-07-21 11:38:13 -040040 // TODO: do we care about mipmapping
41};
42
Adlai Holler3cffe812021-04-09 13:43:32 -040043constexpr GrRenderable kRT = GrRenderable::kYes;
44constexpr GrRenderable kNotRT = GrRenderable::kNo;
45
46constexpr GrColorType kRGBA = GrColorType::kRGBA_8888;
47constexpr GrColorType kAlpha = GrColorType::kAlpha_8;
48
49constexpr SkBackingFit kE = SkBackingFit::kExact;
50constexpr SkBackingFit kA = SkBackingFit::kApprox;
51
52constexpr SkBudgeted kNotB = SkBudgeted::kNo;
Adlai Hollercd2f96d2021-04-09 17:58:14 -040053constexpr SkBudgeted kB = SkBudgeted::kYes;
Adlai Holler3cffe812021-04-09 13:43:32 -040054
55constexpr ProxyParams::Kind kDeferred = ProxyParams::Kind::kDeferred;
56constexpr ProxyParams::Kind kBackend = ProxyParams::Kind::kBackend;
Adlai Hollercd2f96d2021-04-09 17:58:14 -040057constexpr ProxyParams::Kind kInstantiated = ProxyParams::Kind::kInstantiated;
58constexpr ProxyParams::Kind kLazy = ProxyParams::Kind::kLazy;
59constexpr ProxyParams::Kind kFullyLazy = ProxyParams::Kind::kFullyLazy;
Adlai Holler3cffe812021-04-09 13:43:32 -040060};
61
Robert Phillips3d4cac52019-06-11 08:08:08 -040062static sk_sp<GrSurfaceProxy> make_deferred(GrProxyProvider* proxyProvider, const GrCaps* caps,
63 const ProxyParams& p) {
Robert Phillips0a15cc62019-07-30 12:49:10 -040064 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
Brian Salomondf1bd6d2020-03-26 20:37:01 -040065 return proxyProvider->createProxy(format, {p.fSize, p.fSize}, p.fRenderable, p.fSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -040066 GrMipmapped::kNo, p.fFit, p.fBudgeted, GrProtected::kNo);
Robert Phillips57aa3672017-07-21 11:38:13 -040067}
68
Brian Salomon72050802020-10-12 20:45:06 -040069static sk_sp<GrSurfaceProxy> make_backend(GrDirectContext* dContext, const ProxyParams& p) {
Robert Phillipseffd13f2020-07-20 15:00:36 -040070 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
Robert Phillips0bd24dc2018-01-16 08:06:32 -050071
Robert Phillipsc80b0e92019-07-23 10:27:09 -040072 SkColorType skColorType = GrColorTypeToSkColorType(p.fColorType);
73 SkASSERT(SkColorType::kUnknown_SkColorType != skColorType);
74
Brian Salomon72050802020-10-12 20:45:06 -040075 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
76 dContext, p.fSize, p.fSize, skColorType, GrMipmapped::kNo, GrRenderable::kNo);
Greg Danielc1ad77c2020-05-06 11:40:03 -040077
Brian Salomon72050802020-10-12 20:45:06 -040078 if (!mbet) {
Robert Phillips646f6372018-09-25 09:31:10 -040079 return nullptr;
80 }
Robert Phillips57aa3672017-07-21 11:38:13 -040081
Brian Salomon72050802020-10-12 20:45:06 -040082 return proxyProvider->wrapBackendTexture(mbet->texture(),
83 kBorrow_GrWrapOwnership,
84 GrWrapCacheable::kNo,
85 kRead_GrIOType,
86 mbet->refCountedCallback());
Robert Phillips57aa3672017-07-21 11:38:13 -040087}
88
Adlai Holler3cffe812021-04-09 13:43:32 -040089static sk_sp<GrSurfaceProxy> make_fully_lazy(GrProxyProvider* proxyProvider, const GrCaps* caps,
90 const ProxyParams& p) {
91 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
92 auto cb = [p](GrResourceProvider* provider, const GrSurfaceProxy::LazySurfaceDesc& desc) {
93 auto tex = provider->createTexture({p.fSize, p.fSize}, desc.fFormat,
Greg Daniele56d31f2021-08-16 09:29:56 -040094 desc.fTextureType,
Adlai Holler3cffe812021-04-09 13:43:32 -040095 desc.fRenderable, desc.fSampleCnt,
96 desc.fMipmapped, desc.fBudgeted,
97 desc.fProtected);
98 return GrSurfaceProxy::LazyCallbackResult(std::move(tex));
99 };
100 return GrProxyProvider::MakeFullyLazyProxy(std::move(cb), format, p.fRenderable, p.fSampleCnt,
101 GrProtected::kNo, *caps,
102 GrSurfaceProxy::UseAllocator::kYes);
103}
104
105static sk_sp<GrSurfaceProxy> make_lazy(GrProxyProvider* proxyProvider, const GrCaps* caps,
106 const ProxyParams& p) {
107 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
108 auto cb = [](GrResourceProvider* provider, const GrSurfaceProxy::LazySurfaceDesc& desc) {
109 auto tex = provider->createTexture(desc.fDimensions, desc.fFormat,
Greg Daniele56d31f2021-08-16 09:29:56 -0400110 desc.fTextureType,
Adlai Holler3cffe812021-04-09 13:43:32 -0400111 desc.fRenderable, desc.fSampleCnt,
112 desc.fMipmapped, desc.fBudgeted,
113 desc.fProtected);
114 return GrSurfaceProxy::LazyCallbackResult(std::move(tex));
115 };
116 return proxyProvider->createLazyProxy(std::move(cb), format, {p.fSize, p.fSize},
117 GrMipmapped::kNo, GrMipmapStatus::kNotAllocated,
118 GrInternalSurfaceFlags::kNone,
119 p.fFit, p.fBudgeted, GrProtected::kNo,
120 GrSurfaceProxy::UseAllocator::kYes);
121}
122
123static sk_sp<GrSurfaceProxy> make_proxy(GrDirectContext* dContext, const ProxyParams& p) {
124 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
125 const GrCaps* caps = dContext->priv().caps();
126 sk_sp<GrSurfaceProxy> proxy;
127 switch (p.fKind) {
128 case ProxyParams::kDeferred:
129 proxy = make_deferred(proxyProvider, caps, p);
130 break;
131 case ProxyParams::kBackend:
132 proxy = make_backend(dContext, p);
133 break;
134 case ProxyParams::kFullyLazy:
135 proxy = make_fully_lazy(proxyProvider, caps, p);
136 break;
137 case ProxyParams::kLazy:
138 proxy = make_lazy(proxyProvider, caps, p);
139 break;
140 case ProxyParams::kInstantiated:
141 proxy = make_deferred(proxyProvider, caps, p);
142 if (proxy) {
143 auto surf = proxy->priv().createSurface(dContext->priv().resourceProvider());
144 proxy->priv().assign(std::move(surf));
145 }
146 break;
147 }
148 if (proxy && p.fUniqueKey.isValid()) {
149 SkASSERT(proxy->asTextureProxy());
150 proxyProvider->assignUniqueKeyToProxy(p.fUniqueKey, proxy->asTextureProxy());
151 }
152 return proxy;
153}
154
Robert Phillips5af44de2017-07-18 14:49:38 -0400155// Basic test that two proxies with overlapping intervals and compatible descriptors are
156// assigned different GrSurfaces.
Adlai Hollerca1137b2021-04-08 11:39:55 -0400157static void overlap_test(skiatest::Reporter* reporter, GrDirectContext* dContext,
Robert Phillips3d4cac52019-06-11 08:08:08 -0400158 sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
Brian Salomon2c791fc2019-04-02 11:52:03 -0400159 bool expectedResult) {
Adlai Hollerb51dd572021-04-15 11:01:46 -0400160 GrResourceAllocator alloc(dContext);
Robert Phillips5af44de2017-07-18 14:49:38 -0400161
Adlai Holler7f7a5df2021-02-09 17:41:10 +0000162 alloc.addInterval(p1.get(), 0, 4, GrResourceAllocator::ActualUse::kYes);
Robert Phillipsc476e5d2019-03-26 14:50:08 -0400163 alloc.incOps();
Adlai Holler7f7a5df2021-02-09 17:41:10 +0000164 alloc.addInterval(p2.get(), 1, 2, GrResourceAllocator::ActualUse::kYes);
Robert Phillipsc476e5d2019-03-26 14:50:08 -0400165 alloc.incOps();
Robert Phillips5af44de2017-07-18 14:49:38 -0400166
Adlai Holleree2837b2021-04-09 16:52:48 -0400167 REPORTER_ASSERT(reporter, alloc.planAssignment());
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400168 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom());
Adlai Holler19fd5142021-03-08 10:19:30 -0700169 REPORTER_ASSERT(reporter, alloc.assign());
Robert Phillips5af44de2017-07-18 14:49:38 -0400170
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400171 REPORTER_ASSERT(reporter, p1->peekSurface());
172 REPORTER_ASSERT(reporter, p2->peekSurface());
Robert Phillips57aa3672017-07-21 11:38:13 -0400173 bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
174 REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
Robert Phillips5af44de2017-07-18 14:49:38 -0400175}
176
Robert Phillips57aa3672017-07-21 11:38:13 -0400177// Test various cases when two proxies do not have overlapping intervals.
178// This mainly acts as a test of the ResourceAllocator's free pool.
Adlai Hollerca1137b2021-04-08 11:39:55 -0400179static void non_overlap_test(skiatest::Reporter* reporter, GrDirectContext* dContext,
Robert Phillips3d4cac52019-06-11 08:08:08 -0400180 sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
Robert Phillips57aa3672017-07-21 11:38:13 -0400181 bool expectedResult) {
Adlai Hollerb51dd572021-04-15 11:01:46 -0400182 GrResourceAllocator alloc(dContext);
Robert Phillipsc476e5d2019-03-26 14:50:08 -0400183
184 alloc.incOps();
185 alloc.incOps();
186 alloc.incOps();
187 alloc.incOps();
188 alloc.incOps();
189 alloc.incOps();
Robert Phillips57aa3672017-07-21 11:38:13 -0400190
Adlai Holler7f7a5df2021-02-09 17:41:10 +0000191 alloc.addInterval(p1.get(), 0, 2, GrResourceAllocator::ActualUse::kYes);
192 alloc.addInterval(p2.get(), 3, 5, GrResourceAllocator::ActualUse::kYes);
Robert Phillips57aa3672017-07-21 11:38:13 -0400193
Adlai Holleree2837b2021-04-09 16:52:48 -0400194 REPORTER_ASSERT(reporter, alloc.planAssignment());
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400195 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom());
Adlai Holler19fd5142021-03-08 10:19:30 -0700196 REPORTER_ASSERT(reporter, alloc.assign());
Robert Phillips57aa3672017-07-21 11:38:13 -0400197
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400198 REPORTER_ASSERT(reporter, p1->peekSurface());
199 REPORTER_ASSERT(reporter, p2->peekSurface());
Robert Phillips57aa3672017-07-21 11:38:13 -0400200 bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
201 REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
202}
203
204DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest, reporter, ctxInfo) {
Adlai Hollerca1137b2021-04-08 11:39:55 -0400205 auto dContext = ctxInfo.directContext();
206 const GrCaps* caps = dContext->priv().caps();
Robert Phillips5af44de2017-07-18 14:49:38 -0400207
Robert Phillips57aa3672017-07-21 11:38:13 -0400208 struct TestCase {
209 ProxyParams fP1;
210 ProxyParams fP2;
211 bool fExpectation;
212 };
213
Robert Phillips57aa3672017-07-21 11:38:13 -0400214 constexpr bool kShare = true;
215 constexpr bool kDontShare = false;
Adlai Holler3cffe812021-04-09 13:43:32 -0400216
Robert Phillips57aa3672017-07-21 11:38:13 -0400217 // Non-RT GrSurfaces are never recycled on some platforms.
Adlai Holler3cffe812021-04-09 13:43:32 -0400218 bool kConditionallyShare = caps->reuseScratchTextures();
Robert Phillips57aa3672017-07-21 11:38:13 -0400219
Adlai Holler3cffe812021-04-09 13:43:32 -0400220 static const TestCase overlappingTests[] = {
221 // Two proxies with overlapping intervals and compatible descriptors should never share
222 // RT version
223 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
224 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
225 kDontShare},
226 // non-RT version
227 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
228 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
229 kDontShare},
Robert Phillips57aa3672017-07-21 11:38:13 -0400230 };
231
Adlai Holler3cffe812021-04-09 13:43:32 -0400232 for (size_t i = 0; i < SK_ARRAY_COUNT(overlappingTests); i++) {
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400233 const TestCase& test = overlappingTests[i];
Adlai Holler3cffe812021-04-09 13:43:32 -0400234 sk_sp<GrSurfaceProxy> p1 = make_proxy(dContext, test.fP1);
235 sk_sp<GrSurfaceProxy> p2 = make_proxy(dContext, test.fP2);
Adlai Holler7df8d222021-03-19 12:27:49 -0400236 reporter->push(SkStringPrintf("case %d", SkToInt(i)));
Adlai Hollerca1137b2021-04-08 11:39:55 -0400237 overlap_test(reporter, dContext, std::move(p1), std::move(p2), test.fExpectation);
Adlai Holler7df8d222021-03-19 12:27:49 -0400238 reporter->pop();
Robert Phillips57aa3672017-07-21 11:38:13 -0400239 }
240
Greg Daniel6fa62e22019-08-07 15:52:37 -0400241 auto beFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, GrRenderable::kYes);
Adlai Hollerca1137b2021-04-08 11:39:55 -0400242 int k2 = caps->getRenderTargetSampleCount(2, beFormat);
243 int k4 = caps->getRenderTargetSampleCount(4, beFormat);
Robert Phillips57aa3672017-07-21 11:38:13 -0400244
Adlai Holler3cffe812021-04-09 13:43:32 -0400245 static const TestCase nonOverlappingTests[] = {
246 // Two non-overlapping intervals w/ compatible proxies should share
247 // both same size & approx
248 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
249 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
250 kShare},
251 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
252 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
253 kConditionallyShare},
254 // diffs sizes but still approx
255 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
256 {50, kRT, kRGBA, kA, 1, kNotB, kDeferred},
257 kShare},
258 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
259 {50, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
260 kConditionallyShare},
261 // sames sizes but exact
262 {{64, kRT, kRGBA, kE, 1, kNotB, kDeferred},
263 {64, kRT, kRGBA, kE, 1, kNotB, kDeferred},
264 kShare},
265 {{64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
266 {64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
267 kConditionallyShare},
268 // Two non-overlapping intervals w/ different exact sizes should not share
269 {{56, kRT, kRGBA, kE, 1, kNotB, kDeferred},
270 {54, kRT, kRGBA, kE, 1, kNotB, kDeferred},
271 kDontShare},
272 // Two non-overlapping intervals w/ _very different_ approx sizes should not share
273 {{255, kRT, kRGBA, kA, 1, kNotB, kDeferred},
274 {127, kRT, kRGBA, kA, 1, kNotB, kDeferred},
275 kDontShare},
276 // Two non-overlapping intervals w/ different MSAA sample counts should not share
277 {{64, kRT, kRGBA, kA, k2, kNotB, kDeferred},
278 {64, kRT, kRGBA, kA, k4, kNotB, kDeferred},
279 k2 == k4},
280 // Two non-overlapping intervals w/ different configs should not share
281 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
282 {64, kRT, kAlpha, kA, 1, kNotB, kDeferred},
283 kDontShare},
284 // Two non-overlapping intervals w/ different RT classifications should never share
285 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
286 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
287 kDontShare},
288 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
289 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
290 kDontShare},
291 // Two non-overlapping intervals w/ different origins should share
292 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
293 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
294 kShare},
295 // Wrapped backend textures should never be reused
296 {{64, kNotRT, kRGBA, kE, 1, kNotB, kBackend},
297 {64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
298 kDontShare}
Robert Phillips57aa3672017-07-21 11:38:13 -0400299 };
300
Adlai Holler3cffe812021-04-09 13:43:32 -0400301 for (size_t i = 0; i < SK_ARRAY_COUNT(nonOverlappingTests); i++) {
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400302 const TestCase& test = nonOverlappingTests[i];
Adlai Holler3cffe812021-04-09 13:43:32 -0400303 sk_sp<GrSurfaceProxy> p1 = make_proxy(dContext, test.fP1);
304 sk_sp<GrSurfaceProxy> p2 = make_proxy(dContext, test.fP2);
Robert Phillips715d08c2018-07-18 13:56:48 -0400305
Robert Phillips57aa3672017-07-21 11:38:13 -0400306 if (!p1 || !p2) {
Adlai Holler3cffe812021-04-09 13:43:32 -0400307 continue; // creation can fail (e.g., for msaa4 on iOS)
Robert Phillips57aa3672017-07-21 11:38:13 -0400308 }
Robert Phillips715d08c2018-07-18 13:56:48 -0400309
Adlai Holler7df8d222021-03-19 12:27:49 -0400310 reporter->push(SkStringPrintf("case %d", SkToInt(i)));
Adlai Hollerca1137b2021-04-08 11:39:55 -0400311 non_overlap_test(reporter, dContext, std::move(p1), std::move(p2),
Robert Phillipse5f73282019-06-18 17:15:04 -0400312 test.fExpectation);
Adlai Holler7df8d222021-03-19 12:27:49 -0400313 reporter->pop();
Robert Phillips57aa3672017-07-21 11:38:13 -0400314 }
Robert Phillips5af44de2017-07-18 14:49:38 -0400315}
Robert Phillips1734dd32018-08-21 13:52:09 -0400316
Robert Phillipseffd13f2020-07-20 15:00:36 -0400317static void draw(GrRecordingContext* rContext) {
Robert Phillips1734dd32018-08-21 13:52:09 -0400318 SkImageInfo ii = SkImageInfo::Make(1024, 1024, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
319
Robert Phillipseffd13f2020-07-20 15:00:36 -0400320 sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(rContext, SkBudgeted::kYes,
Robert Phillips1734dd32018-08-21 13:52:09 -0400321 ii, 1, kTopLeft_GrSurfaceOrigin, nullptr);
322
323 SkCanvas* c = s->getCanvas();
324
325 c->clear(SK_ColorBLACK);
326}
327
328
329DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorStressTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400330 auto context = ctxInfo.directContext();
Robert Phillips1734dd32018-08-21 13:52:09 -0400331
Robert Phillipscf39f372019-09-03 10:29:20 -0400332 size_t maxBytes = context->getResourceCacheLimit();
Robert Phillips1734dd32018-08-21 13:52:09 -0400333
Robert Phillipscf39f372019-09-03 10:29:20 -0400334 context->setResourceCacheLimit(0); // We'll always be overbudget
Robert Phillips1734dd32018-08-21 13:52:09 -0400335
336 draw(context);
337 draw(context);
338 draw(context);
339 draw(context);
Greg Daniel0a2464f2020-05-14 15:45:44 -0400340 context->flushAndSubmit();
Robert Phillips1734dd32018-08-21 13:52:09 -0400341
Robert Phillipscf39f372019-09-03 10:29:20 -0400342 context->setResourceCacheLimit(maxBytes);
Robert Phillips1734dd32018-08-21 13:52:09 -0400343}
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400344
345struct Interval {
346 ProxyParams fParams;
347 int fStart;
348 int fEnd;
349 sk_sp<GrSurfaceProxy> fProxy = nullptr;
350};
351
352struct TestCase {
353 const char * fName;
354 bool fShouldFit;
355 size_t fBudget;
356 SkTArray<ProxyParams> fPurgeableResourcesInCache = {};
357 SkTArray<ProxyParams> fUnpurgeableResourcesInCache = {};
358 SkTArray<Interval> fIntervals;
359};
360
361static void memory_budget_test(skiatest::Reporter* reporter,
362 GrDirectContext* dContext,
363 const TestCase& test) {
364 // Reset cache.
365 auto cache = dContext->priv().getResourceCache();
366 cache->releaseAll();
367 cache->setLimit(test.fBudget);
368
369 // Add purgeable entries.
370 size_t expectedPurgeableBytes = 0;
371 SkTArray<sk_sp<GrSurface>> purgeableSurfaces;
372 for (auto& params : test.fPurgeableResourcesInCache) {
373 SkASSERT(params.fKind == kInstantiated);
374 sk_sp<GrSurfaceProxy> proxy = make_proxy(dContext, params);
375 REPORTER_ASSERT(reporter, proxy->peekSurface());
376 expectedPurgeableBytes += proxy->gpuMemorySize();
377 purgeableSurfaces.push_back(sk_ref_sp(proxy->peekSurface()));
378 }
379 purgeableSurfaces.reset();
380 REPORTER_ASSERT(reporter, expectedPurgeableBytes == cache->getPurgeableBytes(),
381 "%zu", cache->getPurgeableBytes());
382
383 // Add unpurgeable entries.
384 size_t expectedUnpurgeableBytes = 0;
385 SkTArray<sk_sp<GrSurface>> unpurgeableSurfaces;
386 for (auto& params : test.fUnpurgeableResourcesInCache) {
387 SkASSERT(params.fKind == kInstantiated);
388 sk_sp<GrSurfaceProxy> proxy = make_proxy(dContext, params);
389 REPORTER_ASSERT(reporter, proxy->peekSurface());
390 expectedUnpurgeableBytes += proxy->gpuMemorySize();
391 unpurgeableSurfaces.push_back(sk_ref_sp(proxy->peekSurface()));
392 }
393
394 auto unpurgeableBytes = cache->getBudgetedResourceBytes() - cache->getPurgeableBytes();
395 REPORTER_ASSERT(reporter, expectedUnpurgeableBytes == unpurgeableBytes,
396 "%zu", unpurgeableBytes);
397
398 // Add intervals and test.
Adlai Hollerb51dd572021-04-15 11:01:46 -0400399 GrResourceAllocator alloc(dContext);
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400400 for (auto& interval : test.fIntervals) {
401 for (int i = interval.fStart; i <= interval.fEnd; i++) {
402 alloc.incOps();
403 }
404 alloc.addInterval(interval.fProxy.get(), interval.fStart, interval.fEnd,
405 GrResourceAllocator::ActualUse::kYes);
406 }
407 REPORTER_ASSERT(reporter, alloc.planAssignment());
408 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom() == test.fShouldFit);
409}
410
411DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorMemoryBudgetTest, reporter, ctxInfo) {
412 auto dContext = ctxInfo.directContext();
413
414 constexpr bool kUnder = true;
415 constexpr bool kOver = false;
416 constexpr size_t kRGBA64Bytes = 4 * 64 * 64;
417 const ProxyParams kProxy64 = {64, kRT, kRGBA, kE, 1, kB, kDeferred};
418 const ProxyParams kProxy64NotBudgeted = {64, kRT, kRGBA, kE, 1, kNotB, kDeferred};
419 const ProxyParams kProxy64Lazy = {64, kRT, kRGBA, kE, 1, kB, kLazy};
420 const ProxyParams kProxy64FullyLazy = {64, kRT, kRGBA, kE, 1, kB, kFullyLazy};
421 const ProxyParams kProxy32Instantiated = {32, kRT, kRGBA, kE, 1, kB, kInstantiated};
422 const ProxyParams kProxy64Instantiated = {64, kRT, kRGBA, kE, 1, kB, kInstantiated};
423
424 TestCase tests[] = {
425 {"empty DAG", kUnder, 0, {}, {}, {}},
426 {"unbudgeted", kUnder, 0, {}, {}, {{kProxy64NotBudgeted, 0, 2}}},
427 {"basic", kUnder, kRGBA64Bytes, {}, {}, {{kProxy64, 0, 2}}},
428 {"basic, over", kOver, kRGBA64Bytes - 1, {}, {}, {{kProxy64, 0, 2}}},
429 {"shared", kUnder, kRGBA64Bytes, {}, {},
430 {
431 {kProxy64, 0, 2},
432 {kProxy64, 3, 5},
433 }},
434 {"retrieved from cache", kUnder, kRGBA64Bytes,
435 /* purgeable */{kProxy64Instantiated},
436 /* unpurgeable */{},
437 {
438 {kProxy64, 0, 2}
439 }},
440 {"purge 4", kUnder, kRGBA64Bytes,
441 /* purgeable */{
442 kProxy32Instantiated,
443 kProxy32Instantiated,
444 kProxy32Instantiated,
445 kProxy32Instantiated
446 },
447 /* unpurgeable */{},
448 {
449 {kProxy64, 0, 2}
450 }},
451 {"dont purge what we've reserved", kOver, kRGBA64Bytes,
452 /* purgeable */{kProxy64Instantiated},
453 /* unpurgeable */{},
454 {
455 {kProxy64, 0, 2},
456 {kProxy64, 1, 3}
457 }},
458 {"unpurgeable", kOver, kRGBA64Bytes,
459 /* purgeable */{},
460 /* unpurgeable */{kProxy64Instantiated},
461 {
462 {kProxy64, 0, 2}
463 }},
464 {"lazy", kUnder, kRGBA64Bytes,
465 /* purgeable */{},
466 /* unpurgeable */{},
467 {
468 {kProxy64Lazy, 0, 2}
469 }},
470 {"lazy, over", kOver, kRGBA64Bytes - 1,
471 /* purgeable */{},
472 /* unpurgeable */{},
473 {
474 {kProxy64Lazy, 0, 2}
475 }},
476 {"fully-lazy", kUnder, kRGBA64Bytes,
477 /* purgeable */{},
478 /* unpurgeable */{},
479 {
480 {kProxy64FullyLazy, 0, 2}
481 }},
482 {"fully-lazy, over", kOver, kRGBA64Bytes - 1,
483 /* purgeable */{},
484 /* unpurgeable */{},
485 {
486 {kProxy64FullyLazy, 0, 2}
487 }},
488 };
489 SkString match("");
490 for (size_t i = 0; i < SK_ARRAY_COUNT(tests); i++) {
491 TestCase& test = tests[i];
492 if (match.isEmpty() || match == SkString(test.fName)) {
493 // Create proxies
494 for (Interval& interval : test.fIntervals) {
495 interval.fProxy = make_proxy(dContext, interval.fParams);
496 }
497 reporter->push(SkString(test.fName));
498 memory_budget_test(reporter, dContext, test);
499 reporter->pop();
500 }
501 }
502}
503