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