blob: 8b4aae24d4a4aa1a3f84e94cde85e247ac68d93a [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,
94 desc.fRenderable, desc.fSampleCnt,
95 desc.fMipmapped, desc.fBudgeted,
96 desc.fProtected);
97 return GrSurfaceProxy::LazyCallbackResult(std::move(tex));
98 };
99 return GrProxyProvider::MakeFullyLazyProxy(std::move(cb), format, p.fRenderable, p.fSampleCnt,
100 GrProtected::kNo, *caps,
101 GrSurfaceProxy::UseAllocator::kYes);
102}
103
104static sk_sp<GrSurfaceProxy> make_lazy(GrProxyProvider* proxyProvider, const GrCaps* caps,
105 const ProxyParams& p) {
106 const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
107 auto cb = [](GrResourceProvider* provider, const GrSurfaceProxy::LazySurfaceDesc& desc) {
108 auto tex = provider->createTexture(desc.fDimensions, desc.fFormat,
109 desc.fRenderable, desc.fSampleCnt,
110 desc.fMipmapped, desc.fBudgeted,
111 desc.fProtected);
112 return GrSurfaceProxy::LazyCallbackResult(std::move(tex));
113 };
114 return proxyProvider->createLazyProxy(std::move(cb), format, {p.fSize, p.fSize},
115 GrMipmapped::kNo, GrMipmapStatus::kNotAllocated,
116 GrInternalSurfaceFlags::kNone,
117 p.fFit, p.fBudgeted, GrProtected::kNo,
118 GrSurfaceProxy::UseAllocator::kYes);
119}
120
121static sk_sp<GrSurfaceProxy> make_proxy(GrDirectContext* dContext, const ProxyParams& p) {
122 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
123 const GrCaps* caps = dContext->priv().caps();
124 sk_sp<GrSurfaceProxy> proxy;
125 switch (p.fKind) {
126 case ProxyParams::kDeferred:
127 proxy = make_deferred(proxyProvider, caps, p);
128 break;
129 case ProxyParams::kBackend:
130 proxy = make_backend(dContext, p);
131 break;
132 case ProxyParams::kFullyLazy:
133 proxy = make_fully_lazy(proxyProvider, caps, p);
134 break;
135 case ProxyParams::kLazy:
136 proxy = make_lazy(proxyProvider, caps, p);
137 break;
138 case ProxyParams::kInstantiated:
139 proxy = make_deferred(proxyProvider, caps, p);
140 if (proxy) {
141 auto surf = proxy->priv().createSurface(dContext->priv().resourceProvider());
142 proxy->priv().assign(std::move(surf));
143 }
144 break;
145 }
146 if (proxy && p.fUniqueKey.isValid()) {
147 SkASSERT(proxy->asTextureProxy());
148 proxyProvider->assignUniqueKeyToProxy(p.fUniqueKey, proxy->asTextureProxy());
149 }
150 return proxy;
151}
152
Robert Phillips5af44de2017-07-18 14:49:38 -0400153// Basic test that two proxies with overlapping intervals and compatible descriptors are
154// assigned different GrSurfaces.
Adlai Hollerca1137b2021-04-08 11:39:55 -0400155static void overlap_test(skiatest::Reporter* reporter, GrDirectContext* dContext,
Robert Phillips3d4cac52019-06-11 08:08:08 -0400156 sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
Brian Salomon2c791fc2019-04-02 11:52:03 -0400157 bool expectedResult) {
Adlai Hollerb51dd572021-04-15 11:01:46 -0400158 GrResourceAllocator alloc(dContext);
Robert Phillips5af44de2017-07-18 14:49:38 -0400159
Adlai Holler7f7a5df2021-02-09 17:41:10 +0000160 alloc.addInterval(p1.get(), 0, 4, GrResourceAllocator::ActualUse::kYes);
Robert Phillipsc476e5d2019-03-26 14:50:08 -0400161 alloc.incOps();
Adlai Holler7f7a5df2021-02-09 17:41:10 +0000162 alloc.addInterval(p2.get(), 1, 2, GrResourceAllocator::ActualUse::kYes);
Robert Phillipsc476e5d2019-03-26 14:50:08 -0400163 alloc.incOps();
Robert Phillips5af44de2017-07-18 14:49:38 -0400164
Adlai Holleree2837b2021-04-09 16:52:48 -0400165 REPORTER_ASSERT(reporter, alloc.planAssignment());
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400166 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom());
Adlai Holler19fd5142021-03-08 10:19:30 -0700167 REPORTER_ASSERT(reporter, alloc.assign());
Robert Phillips5af44de2017-07-18 14:49:38 -0400168
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400169 REPORTER_ASSERT(reporter, p1->peekSurface());
170 REPORTER_ASSERT(reporter, p2->peekSurface());
Robert Phillips57aa3672017-07-21 11:38:13 -0400171 bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
172 REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
Robert Phillips5af44de2017-07-18 14:49:38 -0400173}
174
Robert Phillips57aa3672017-07-21 11:38:13 -0400175// Test various cases when two proxies do not have overlapping intervals.
176// This mainly acts as a test of the ResourceAllocator's free pool.
Adlai Hollerca1137b2021-04-08 11:39:55 -0400177static void non_overlap_test(skiatest::Reporter* reporter, GrDirectContext* dContext,
Robert Phillips3d4cac52019-06-11 08:08:08 -0400178 sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
Robert Phillips57aa3672017-07-21 11:38:13 -0400179 bool expectedResult) {
Adlai Hollerb51dd572021-04-15 11:01:46 -0400180 GrResourceAllocator alloc(dContext);
Robert Phillipsc476e5d2019-03-26 14:50:08 -0400181
182 alloc.incOps();
183 alloc.incOps();
184 alloc.incOps();
185 alloc.incOps();
186 alloc.incOps();
187 alloc.incOps();
Robert Phillips57aa3672017-07-21 11:38:13 -0400188
Adlai Holler7f7a5df2021-02-09 17:41:10 +0000189 alloc.addInterval(p1.get(), 0, 2, GrResourceAllocator::ActualUse::kYes);
190 alloc.addInterval(p2.get(), 3, 5, GrResourceAllocator::ActualUse::kYes);
Robert Phillips57aa3672017-07-21 11:38:13 -0400191
Adlai Holleree2837b2021-04-09 16:52:48 -0400192 REPORTER_ASSERT(reporter, alloc.planAssignment());
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400193 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom());
Adlai Holler19fd5142021-03-08 10:19:30 -0700194 REPORTER_ASSERT(reporter, alloc.assign());
Robert Phillips57aa3672017-07-21 11:38:13 -0400195
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400196 REPORTER_ASSERT(reporter, p1->peekSurface());
197 REPORTER_ASSERT(reporter, p2->peekSurface());
Robert Phillips57aa3672017-07-21 11:38:13 -0400198 bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
199 REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
200}
201
202DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest, reporter, ctxInfo) {
Adlai Hollerca1137b2021-04-08 11:39:55 -0400203 auto dContext = ctxInfo.directContext();
204 const GrCaps* caps = dContext->priv().caps();
Robert Phillips5af44de2017-07-18 14:49:38 -0400205
Robert Phillips57aa3672017-07-21 11:38:13 -0400206 struct TestCase {
207 ProxyParams fP1;
208 ProxyParams fP2;
209 bool fExpectation;
210 };
211
Robert Phillips57aa3672017-07-21 11:38:13 -0400212 constexpr bool kShare = true;
213 constexpr bool kDontShare = false;
Adlai Holler3cffe812021-04-09 13:43:32 -0400214
Robert Phillips57aa3672017-07-21 11:38:13 -0400215 // Non-RT GrSurfaces are never recycled on some platforms.
Adlai Holler3cffe812021-04-09 13:43:32 -0400216 bool kConditionallyShare = caps->reuseScratchTextures();
Robert Phillips57aa3672017-07-21 11:38:13 -0400217
Adlai Holler3cffe812021-04-09 13:43:32 -0400218 static const TestCase overlappingTests[] = {
219 // Two proxies with overlapping intervals and compatible descriptors should never share
220 // RT version
221 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
222 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
223 kDontShare},
224 // non-RT version
225 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
226 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
227 kDontShare},
Robert Phillips57aa3672017-07-21 11:38:13 -0400228 };
229
Adlai Holler3cffe812021-04-09 13:43:32 -0400230 for (size_t i = 0; i < SK_ARRAY_COUNT(overlappingTests); i++) {
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400231 const TestCase& test = overlappingTests[i];
Adlai Holler3cffe812021-04-09 13:43:32 -0400232 sk_sp<GrSurfaceProxy> p1 = make_proxy(dContext, test.fP1);
233 sk_sp<GrSurfaceProxy> p2 = make_proxy(dContext, test.fP2);
Adlai Holler7df8d222021-03-19 12:27:49 -0400234 reporter->push(SkStringPrintf("case %d", SkToInt(i)));
Adlai Hollerca1137b2021-04-08 11:39:55 -0400235 overlap_test(reporter, dContext, std::move(p1), std::move(p2), test.fExpectation);
Adlai Holler7df8d222021-03-19 12:27:49 -0400236 reporter->pop();
Robert Phillips57aa3672017-07-21 11:38:13 -0400237 }
238
Greg Daniel6fa62e22019-08-07 15:52:37 -0400239 auto beFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, GrRenderable::kYes);
Adlai Hollerca1137b2021-04-08 11:39:55 -0400240 int k2 = caps->getRenderTargetSampleCount(2, beFormat);
241 int k4 = caps->getRenderTargetSampleCount(4, beFormat);
Robert Phillips57aa3672017-07-21 11:38:13 -0400242
Adlai Holler3cffe812021-04-09 13:43:32 -0400243 static const TestCase nonOverlappingTests[] = {
244 // Two non-overlapping intervals w/ compatible proxies should share
245 // both same size & approx
246 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
247 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
248 kShare},
249 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
250 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
251 kConditionallyShare},
252 // diffs sizes but still approx
253 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
254 {50, kRT, kRGBA, kA, 1, kNotB, kDeferred},
255 kShare},
256 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
257 {50, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
258 kConditionallyShare},
259 // sames sizes but exact
260 {{64, kRT, kRGBA, kE, 1, kNotB, kDeferred},
261 {64, kRT, kRGBA, kE, 1, kNotB, kDeferred},
262 kShare},
263 {{64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
264 {64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
265 kConditionallyShare},
266 // Two non-overlapping intervals w/ different exact sizes should not share
267 {{56, kRT, kRGBA, kE, 1, kNotB, kDeferred},
268 {54, kRT, kRGBA, kE, 1, kNotB, kDeferred},
269 kDontShare},
270 // Two non-overlapping intervals w/ _very different_ approx sizes should not share
271 {{255, kRT, kRGBA, kA, 1, kNotB, kDeferred},
272 {127, kRT, kRGBA, kA, 1, kNotB, kDeferred},
273 kDontShare},
274 // Two non-overlapping intervals w/ different MSAA sample counts should not share
275 {{64, kRT, kRGBA, kA, k2, kNotB, kDeferred},
276 {64, kRT, kRGBA, kA, k4, kNotB, kDeferred},
277 k2 == k4},
278 // Two non-overlapping intervals w/ different configs should not share
279 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
280 {64, kRT, kAlpha, kA, 1, kNotB, kDeferred},
281 kDontShare},
282 // Two non-overlapping intervals w/ different RT classifications should never share
283 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
284 {64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
285 kDontShare},
286 {{64, kNotRT, kRGBA, kA, 1, kNotB, kDeferred},
287 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
288 kDontShare},
289 // Two non-overlapping intervals w/ different origins should share
290 {{64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
291 {64, kRT, kRGBA, kA, 1, kNotB, kDeferred},
292 kShare},
293 // Wrapped backend textures should never be reused
294 {{64, kNotRT, kRGBA, kE, 1, kNotB, kBackend},
295 {64, kNotRT, kRGBA, kE, 1, kNotB, kDeferred},
296 kDontShare}
Robert Phillips57aa3672017-07-21 11:38:13 -0400297 };
298
Adlai Holler3cffe812021-04-09 13:43:32 -0400299 for (size_t i = 0; i < SK_ARRAY_COUNT(nonOverlappingTests); i++) {
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400300 const TestCase& test = nonOverlappingTests[i];
Adlai Holler3cffe812021-04-09 13:43:32 -0400301 sk_sp<GrSurfaceProxy> p1 = make_proxy(dContext, test.fP1);
302 sk_sp<GrSurfaceProxy> p2 = make_proxy(dContext, test.fP2);
Robert Phillips715d08c2018-07-18 13:56:48 -0400303
Robert Phillips57aa3672017-07-21 11:38:13 -0400304 if (!p1 || !p2) {
Adlai Holler3cffe812021-04-09 13:43:32 -0400305 continue; // creation can fail (e.g., for msaa4 on iOS)
Robert Phillips57aa3672017-07-21 11:38:13 -0400306 }
Robert Phillips715d08c2018-07-18 13:56:48 -0400307
Adlai Holler7df8d222021-03-19 12:27:49 -0400308 reporter->push(SkStringPrintf("case %d", SkToInt(i)));
Adlai Hollerca1137b2021-04-08 11:39:55 -0400309 non_overlap_test(reporter, dContext, std::move(p1), std::move(p2),
Robert Phillipse5f73282019-06-18 17:15:04 -0400310 test.fExpectation);
Adlai Holler7df8d222021-03-19 12:27:49 -0400311 reporter->pop();
Robert Phillips57aa3672017-07-21 11:38:13 -0400312 }
Robert Phillips5af44de2017-07-18 14:49:38 -0400313}
Robert Phillips1734dd32018-08-21 13:52:09 -0400314
Robert Phillipseffd13f2020-07-20 15:00:36 -0400315static void draw(GrRecordingContext* rContext) {
Robert Phillips1734dd32018-08-21 13:52:09 -0400316 SkImageInfo ii = SkImageInfo::Make(1024, 1024, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
317
Robert Phillipseffd13f2020-07-20 15:00:36 -0400318 sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(rContext, SkBudgeted::kYes,
Robert Phillips1734dd32018-08-21 13:52:09 -0400319 ii, 1, kTopLeft_GrSurfaceOrigin, nullptr);
320
321 SkCanvas* c = s->getCanvas();
322
323 c->clear(SK_ColorBLACK);
324}
325
326
327DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorStressTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400328 auto context = ctxInfo.directContext();
Robert Phillips1734dd32018-08-21 13:52:09 -0400329
Robert Phillipscf39f372019-09-03 10:29:20 -0400330 size_t maxBytes = context->getResourceCacheLimit();
Robert Phillips1734dd32018-08-21 13:52:09 -0400331
Robert Phillipscf39f372019-09-03 10:29:20 -0400332 context->setResourceCacheLimit(0); // We'll always be overbudget
Robert Phillips1734dd32018-08-21 13:52:09 -0400333
334 draw(context);
335 draw(context);
336 draw(context);
337 draw(context);
Greg Daniel0a2464f2020-05-14 15:45:44 -0400338 context->flushAndSubmit();
Robert Phillips1734dd32018-08-21 13:52:09 -0400339
Robert Phillipscf39f372019-09-03 10:29:20 -0400340 context->setResourceCacheLimit(maxBytes);
Robert Phillips1734dd32018-08-21 13:52:09 -0400341}
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400342
343struct Interval {
344 ProxyParams fParams;
345 int fStart;
346 int fEnd;
347 sk_sp<GrSurfaceProxy> fProxy = nullptr;
348};
349
350struct TestCase {
351 const char * fName;
352 bool fShouldFit;
353 size_t fBudget;
354 SkTArray<ProxyParams> fPurgeableResourcesInCache = {};
355 SkTArray<ProxyParams> fUnpurgeableResourcesInCache = {};
356 SkTArray<Interval> fIntervals;
357};
358
359static void memory_budget_test(skiatest::Reporter* reporter,
360 GrDirectContext* dContext,
361 const TestCase& test) {
362 // Reset cache.
363 auto cache = dContext->priv().getResourceCache();
364 cache->releaseAll();
365 cache->setLimit(test.fBudget);
366
367 // Add purgeable entries.
368 size_t expectedPurgeableBytes = 0;
369 SkTArray<sk_sp<GrSurface>> purgeableSurfaces;
370 for (auto& params : test.fPurgeableResourcesInCache) {
371 SkASSERT(params.fKind == kInstantiated);
372 sk_sp<GrSurfaceProxy> proxy = make_proxy(dContext, params);
373 REPORTER_ASSERT(reporter, proxy->peekSurface());
374 expectedPurgeableBytes += proxy->gpuMemorySize();
375 purgeableSurfaces.push_back(sk_ref_sp(proxy->peekSurface()));
376 }
377 purgeableSurfaces.reset();
378 REPORTER_ASSERT(reporter, expectedPurgeableBytes == cache->getPurgeableBytes(),
379 "%zu", cache->getPurgeableBytes());
380
381 // Add unpurgeable entries.
382 size_t expectedUnpurgeableBytes = 0;
383 SkTArray<sk_sp<GrSurface>> unpurgeableSurfaces;
384 for (auto& params : test.fUnpurgeableResourcesInCache) {
385 SkASSERT(params.fKind == kInstantiated);
386 sk_sp<GrSurfaceProxy> proxy = make_proxy(dContext, params);
387 REPORTER_ASSERT(reporter, proxy->peekSurface());
388 expectedUnpurgeableBytes += proxy->gpuMemorySize();
389 unpurgeableSurfaces.push_back(sk_ref_sp(proxy->peekSurface()));
390 }
391
392 auto unpurgeableBytes = cache->getBudgetedResourceBytes() - cache->getPurgeableBytes();
393 REPORTER_ASSERT(reporter, expectedUnpurgeableBytes == unpurgeableBytes,
394 "%zu", unpurgeableBytes);
395
396 // Add intervals and test.
Adlai Hollerb51dd572021-04-15 11:01:46 -0400397 GrResourceAllocator alloc(dContext);
Adlai Hollercd2f96d2021-04-09 17:58:14 -0400398 for (auto& interval : test.fIntervals) {
399 for (int i = interval.fStart; i <= interval.fEnd; i++) {
400 alloc.incOps();
401 }
402 alloc.addInterval(interval.fProxy.get(), interval.fStart, interval.fEnd,
403 GrResourceAllocator::ActualUse::kYes);
404 }
405 REPORTER_ASSERT(reporter, alloc.planAssignment());
406 REPORTER_ASSERT(reporter, alloc.makeBudgetHeadroom() == test.fShouldFit);
407}
408
409DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorMemoryBudgetTest, reporter, ctxInfo) {
410 auto dContext = ctxInfo.directContext();
411
412 constexpr bool kUnder = true;
413 constexpr bool kOver = false;
414 constexpr size_t kRGBA64Bytes = 4 * 64 * 64;
415 const ProxyParams kProxy64 = {64, kRT, kRGBA, kE, 1, kB, kDeferred};
416 const ProxyParams kProxy64NotBudgeted = {64, kRT, kRGBA, kE, 1, kNotB, kDeferred};
417 const ProxyParams kProxy64Lazy = {64, kRT, kRGBA, kE, 1, kB, kLazy};
418 const ProxyParams kProxy64FullyLazy = {64, kRT, kRGBA, kE, 1, kB, kFullyLazy};
419 const ProxyParams kProxy32Instantiated = {32, kRT, kRGBA, kE, 1, kB, kInstantiated};
420 const ProxyParams kProxy64Instantiated = {64, kRT, kRGBA, kE, 1, kB, kInstantiated};
421
422 TestCase tests[] = {
423 {"empty DAG", kUnder, 0, {}, {}, {}},
424 {"unbudgeted", kUnder, 0, {}, {}, {{kProxy64NotBudgeted, 0, 2}}},
425 {"basic", kUnder, kRGBA64Bytes, {}, {}, {{kProxy64, 0, 2}}},
426 {"basic, over", kOver, kRGBA64Bytes - 1, {}, {}, {{kProxy64, 0, 2}}},
427 {"shared", kUnder, kRGBA64Bytes, {}, {},
428 {
429 {kProxy64, 0, 2},
430 {kProxy64, 3, 5},
431 }},
432 {"retrieved from cache", kUnder, kRGBA64Bytes,
433 /* purgeable */{kProxy64Instantiated},
434 /* unpurgeable */{},
435 {
436 {kProxy64, 0, 2}
437 }},
438 {"purge 4", kUnder, kRGBA64Bytes,
439 /* purgeable */{
440 kProxy32Instantiated,
441 kProxy32Instantiated,
442 kProxy32Instantiated,
443 kProxy32Instantiated
444 },
445 /* unpurgeable */{},
446 {
447 {kProxy64, 0, 2}
448 }},
449 {"dont purge what we've reserved", kOver, kRGBA64Bytes,
450 /* purgeable */{kProxy64Instantiated},
451 /* unpurgeable */{},
452 {
453 {kProxy64, 0, 2},
454 {kProxy64, 1, 3}
455 }},
456 {"unpurgeable", kOver, kRGBA64Bytes,
457 /* purgeable */{},
458 /* unpurgeable */{kProxy64Instantiated},
459 {
460 {kProxy64, 0, 2}
461 }},
462 {"lazy", kUnder, kRGBA64Bytes,
463 /* purgeable */{},
464 /* unpurgeable */{},
465 {
466 {kProxy64Lazy, 0, 2}
467 }},
468 {"lazy, over", kOver, kRGBA64Bytes - 1,
469 /* purgeable */{},
470 /* unpurgeable */{},
471 {
472 {kProxy64Lazy, 0, 2}
473 }},
474 {"fully-lazy", kUnder, kRGBA64Bytes,
475 /* purgeable */{},
476 /* unpurgeable */{},
477 {
478 {kProxy64FullyLazy, 0, 2}
479 }},
480 {"fully-lazy, over", kOver, kRGBA64Bytes - 1,
481 /* purgeable */{},
482 /* unpurgeable */{},
483 {
484 {kProxy64FullyLazy, 0, 2}
485 }},
486 };
487 SkString match("");
488 for (size_t i = 0; i < SK_ARRAY_COUNT(tests); i++) {
489 TestCase& test = tests[i];
490 if (match.isEmpty() || match == SkString(test.fName)) {
491 // Create proxies
492 for (Interval& interval : test.fIntervals) {
493 interval.fProxy = make_proxy(dContext, interval.fParams);
494 }
495 reporter->push(SkString(test.fName));
496 memory_budget_test(reporter, dContext, test);
497 reporter->pop();
498 }
499 }
500}
501