• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkTypes.h"
9 
10 #include "tests/Test.h"
11 
12 #include "include/gpu/GrTexture.h"
13 #include "src/gpu/GrContextPriv.h"
14 #include "src/gpu/GrDeinstantiateProxyTracker.h"
15 #include "src/gpu/GrGpu.h"
16 #include "src/gpu/GrProxyProvider.h"
17 #include "src/gpu/GrResourceAllocator.h"
18 #include "src/gpu/GrResourceProvider.h"
19 #include "src/gpu/GrSurfaceProxyPriv.h"
20 #include "src/gpu/GrTextureProxy.h"
21 
22 #include "include/core/SkSurface.h"
23 
24 struct ProxyParams {
25     int             fSize;
26     GrRenderable    fRenderable;
27     GrColorType     fColorType;
28     SkBackingFit    fFit;
29     int             fSampleCnt;
30     GrSurfaceOrigin fOrigin;
31     SkBudgeted      fBudgeted;
32     // TODO: do we care about mipmapping
33 };
34 
make_deferred(GrProxyProvider * proxyProvider,const GrCaps * caps,const ProxyParams & p)35 static sk_sp<GrSurfaceProxy> make_deferred(GrProxyProvider* proxyProvider, const GrCaps* caps,
36                                            const ProxyParams& p) {
37     GrPixelConfig config = GrColorTypeToPixelConfig(p.fColorType);
38 
39     GrSurfaceDesc desc;
40     desc.fWidth  = p.fSize;
41     desc.fHeight = p.fSize;
42     desc.fConfig = config;
43 
44     const GrBackendFormat format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
45 
46     return proxyProvider->createProxy(format, desc, p.fRenderable, p.fSampleCnt, p.fOrigin, p.fFit,
47                                       p.fBudgeted, GrProtected::kNo);
48 }
49 
make_backend(GrContext * context,const ProxyParams & p,GrBackendTexture * backendTex)50 static sk_sp<GrSurfaceProxy> make_backend(GrContext* context, const ProxyParams& p,
51                                           GrBackendTexture* backendTex) {
52     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
53 
54     SkColorType skColorType = GrColorTypeToSkColorType(p.fColorType);
55     SkASSERT(SkColorType::kUnknown_SkColorType != skColorType);
56 
57     *backendTex = context->createBackendTexture(p.fSize, p.fSize, skColorType,
58                                                 SkColors::kTransparent,
59                                                 GrMipMapped::kNo, GrRenderable::kNo,
60                                                 GrProtected::kNo);
61     if (!backendTex->isValid()) {
62         return nullptr;
63     }
64 
65     return proxyProvider->wrapBackendTexture(*backendTex, p.fColorType, p.fOrigin,
66                                              kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
67                                              kRead_GrIOType);
68 }
69 
cleanup_backend(GrContext * context,const GrBackendTexture & backendTex)70 static void cleanup_backend(GrContext* context, const GrBackendTexture& backendTex) {
71     context->deleteBackendTexture(backendTex);
72 }
73 
74 // Basic test that two proxies with overlapping intervals and compatible descriptors are
75 // assigned different GrSurfaces.
overlap_test(skiatest::Reporter * reporter,GrResourceProvider * resourceProvider,sk_sp<GrSurfaceProxy> p1,sk_sp<GrSurfaceProxy> p2,bool expectedResult)76 static void overlap_test(skiatest::Reporter* reporter, GrResourceProvider* resourceProvider,
77                          sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
78                          bool expectedResult) {
79     GrDeinstantiateProxyTracker deinstantiateTracker;
80     GrResourceAllocator alloc(resourceProvider, &deinstantiateTracker SkDEBUGCODE(, 1));
81 
82     alloc.addInterval(p1.get(), 0, 4, GrResourceAllocator::ActualUse::kYes);
83     alloc.incOps();
84     alloc.addInterval(p2.get(), 1, 2, GrResourceAllocator::ActualUse::kYes);
85     alloc.incOps();
86     alloc.markEndOfOpList(0);
87 
88     alloc.determineRecyclability();
89 
90     int startIndex, stopIndex;
91     GrResourceAllocator::AssignError error;
92     alloc.assign(&startIndex, &stopIndex, &error);
93     REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
94 
95     REPORTER_ASSERT(reporter, p1->peekSurface());
96     REPORTER_ASSERT(reporter, p2->peekSurface());
97     bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
98     REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
99 }
100 
101 // Test various cases when two proxies do not have overlapping intervals.
102 // This mainly acts as a test of the ResourceAllocator's free pool.
non_overlap_test(skiatest::Reporter * reporter,GrResourceProvider * resourceProvider,sk_sp<GrSurfaceProxy> p1,sk_sp<GrSurfaceProxy> p2,bool expectedResult)103 static void non_overlap_test(skiatest::Reporter* reporter, GrResourceProvider* resourceProvider,
104                              sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
105                              bool expectedResult) {
106     GrDeinstantiateProxyTracker deinstantiateTracker;
107     GrResourceAllocator alloc(resourceProvider, &deinstantiateTracker SkDEBUGCODE(, 1));
108 
109     alloc.incOps();
110     alloc.incOps();
111     alloc.incOps();
112     alloc.incOps();
113     alloc.incOps();
114     alloc.incOps();
115 
116     alloc.addInterval(p1.get(), 0, 2, GrResourceAllocator::ActualUse::kYes);
117     alloc.addInterval(p2.get(), 3, 5, GrResourceAllocator::ActualUse::kYes);
118     alloc.markEndOfOpList(0);
119 
120     alloc.determineRecyclability();
121 
122     int startIndex, stopIndex;
123     GrResourceAllocator::AssignError error;
124     alloc.assign(&startIndex, &stopIndex, &error);
125     REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
126 
127     REPORTER_ASSERT(reporter, p1->peekSurface());
128     REPORTER_ASSERT(reporter, p2->peekSurface());
129     bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
130     REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
131 }
132 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest,reporter,ctxInfo)133 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest, reporter, ctxInfo) {
134     const GrCaps* caps = ctxInfo.grContext()->priv().caps();
135     GrProxyProvider* proxyProvider = ctxInfo.grContext()->priv().proxyProvider();
136     GrResourceProvider* resourceProvider = ctxInfo.grContext()->priv().resourceProvider();
137 
138     struct TestCase {
139         ProxyParams   fP1;
140         ProxyParams   fP2;
141         bool          fExpectation;
142     };
143 
144     constexpr GrRenderable kRT = GrRenderable::kYes;
145     constexpr GrRenderable kNotRT = GrRenderable::kNo;
146 
147     constexpr bool kShare = true;
148     constexpr bool kDontShare = false;
149     // Non-RT GrSurfaces are never recycled on some platforms.
150     bool kConditionallyShare = resourceProvider->caps()->reuseScratchTextures();
151 
152     const GrColorType kRGBA = GrColorType::kRGBA_8888;
153     const GrColorType kBGRA = GrColorType::kBGRA_8888;
154 
155     const SkBackingFit kE = SkBackingFit::kExact;
156     const SkBackingFit kA = SkBackingFit::kApprox;
157 
158     const GrSurfaceOrigin kTL = kTopLeft_GrSurfaceOrigin;
159     const GrSurfaceOrigin kBL = kBottomLeft_GrSurfaceOrigin;
160 
161     const SkBudgeted kNotB = SkBudgeted::kNo;
162 
163     //--------------------------------------------------------------------------------------------
164     TestCase gOverlappingTests[] = {
165         //----------------------------------------------------------------------------------------
166         // Two proxies with overlapping intervals and compatible descriptors should never share
167         // RT version
168         { { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, kDontShare },
169         // non-RT version
170         { { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, kDontShare },
171     };
172 
173     for (auto test : gOverlappingTests) {
174         sk_sp<GrSurfaceProxy> p1 = make_deferred(proxyProvider, caps, test.fP1);
175         sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, caps, test.fP2);
176         overlap_test(reporter, resourceProvider, std::move(p1), std::move(p2), test.fExpectation);
177     }
178 
179     auto beFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, GrRenderable::kYes);
180     int k2 = ctxInfo.grContext()->priv().caps()->getRenderTargetSampleCount(2, beFormat);
181     int k4 = ctxInfo.grContext()->priv().caps()->getRenderTargetSampleCount(4, beFormat);
182 
183     //--------------------------------------------------------------------------------------------
184     TestCase gNonOverlappingTests[] = {
185         //----------------------------------------------------------------------------------------
186         // Two non-overlapping intervals w/ compatible proxies should share
187         // both same size & approx
188         { { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, kShare },
189         { { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, kConditionallyShare },
190         // diffs sizes but still approx
191         { { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, { 50,    kRT, kRGBA, kA, 1, kTL, kNotB }, kShare },
192         { { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, { 50, kNotRT, kRGBA, kA, 1, kTL, kNotB }, kConditionallyShare },
193         // sames sizes but exact
194         { { 64,    kRT, kRGBA, kE, 1, kTL, kNotB }, { 64,    kRT, kRGBA, kE, 1, kTL, kNotB }, kShare },
195         { { 64, kNotRT, kRGBA, kE, 1, kTL, kNotB }, { 64, kNotRT, kRGBA, kE, 1, kTL, kNotB }, kConditionallyShare },
196         //----------------------------------------------------------------------------------------
197         // Two non-overlapping intervals w/ different exact sizes should not share
198         { { 56,    kRT, kRGBA, kE, 1, kTL, kNotB }, { 54,    kRT, kRGBA, kE, 1, kTL, kNotB }, kDontShare },
199         // Two non-overlapping intervals w/ _very different_ approx sizes should not share
200         { { 255,   kRT, kRGBA, kA, 1, kTL, kNotB }, { 127,   kRT, kRGBA, kA, 1, kTL, kNotB }, kDontShare },
201         // Two non-overlapping intervals w/ different MSAA sample counts should not share
202         { { 64,    kRT, kRGBA, kA, k2, kTL, kNotB },{ 64,    kRT, kRGBA, kA, k4,kTL, kNotB}, k2 == k4 },
203         // Two non-overlapping intervals w/ different configs should not share
204         { { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, { 64,    kRT, kBGRA, kA, 1, kTL, kNotB }, kDontShare },
205         // Two non-overlapping intervals w/ different RT classifications should never share
206         { { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, kDontShare },
207         { { 64, kNotRT, kRGBA, kA, 1, kTL, kNotB }, { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, kDontShare },
208         // Two non-overlapping intervals w/ different origins should share
209         { { 64,    kRT, kRGBA, kA, 1, kTL, kNotB }, { 64,    kRT, kRGBA, kA, 1, kBL, kNotB }, kShare },
210     };
211 
212     for (auto test : gNonOverlappingTests) {
213         sk_sp<GrSurfaceProxy> p1 = make_deferred(proxyProvider, caps, test.fP1);
214         sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, caps, test.fP2);
215 
216         if (!p1 || !p2) {
217             continue; // creation can fail (i.e., for msaa4 on iOS)
218         }
219 
220         non_overlap_test(reporter, resourceProvider, std::move(p1), std::move(p2),
221                          test.fExpectation);
222     }
223 
224     {
225         // Wrapped backend textures should never be reused
226         TestCase t[1] = {
227             { { 64, kNotRT, kRGBA, kE, 1, kTL, kNotB }, { 64, kNotRT, kRGBA, kE, 1, kTL, kNotB }, kDontShare }
228         };
229 
230         GrBackendTexture backEndTex;
231         sk_sp<GrSurfaceProxy> p1 = make_backend(ctxInfo.grContext(), t[0].fP1, &backEndTex);
232         sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, caps, t[0].fP2);
233 
234         non_overlap_test(reporter, resourceProvider, std::move(p1), std::move(p2),
235                          t[0].fExpectation);
236 
237         cleanup_backend(ctxInfo.grContext(), backEndTex);
238     }
239 }
240 
draw(GrContext * context)241 static void draw(GrContext* context) {
242     SkImageInfo ii = SkImageInfo::Make(1024, 1024, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
243 
244     sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes,
245                                                      ii, 1, kTopLeft_GrSurfaceOrigin, nullptr);
246 
247     SkCanvas* c = s->getCanvas();
248 
249     c->clear(SK_ColorBLACK);
250 }
251 
252 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorStressTest,reporter,ctxInfo)253 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorStressTest, reporter, ctxInfo) {
254     GrContext* context = ctxInfo.grContext();
255 
256     int maxNum;
257     size_t maxBytes;
258     context->getResourceCacheLimits(&maxNum, &maxBytes);
259 
260     context->setResourceCacheLimits(0, 0); // We'll always be overbudget
261 
262     draw(context);
263     draw(context);
264     draw(context);
265     draw(context);
266     context->flush();
267 
268     context->setResourceCacheLimits(maxNum, maxBytes);
269 }
270 
make_lazy(GrProxyProvider * proxyProvider,const GrCaps * caps,const ProxyParams & p,bool deinstantiate)271 sk_sp<GrSurfaceProxy> make_lazy(GrProxyProvider* proxyProvider, const GrCaps* caps,
272                                 const ProxyParams& p, bool deinstantiate) {
273     GrPixelConfig config = GrColorTypeToPixelConfig(p.fColorType);
274     const auto format = caps->getDefaultBackendFormat(p.fColorType, p.fRenderable);
275 
276     GrSurfaceDesc desc;
277     desc.fWidth = p.fSize;
278     desc.fHeight = p.fSize;
279     desc.fConfig = config;
280 
281     SkBackingFit fit = p.fFit;
282     auto callback = [fit, desc, format, p](GrResourceProvider* resourceProvider) {
283         sk_sp<GrTexture> texture;
284         if (fit == SkBackingFit::kApprox) {
285             texture = resourceProvider->createApproxTexture(
286                     desc, format, p.fRenderable, p.fSampleCnt, GrProtected::kNo,
287                     GrResourceProvider::Flags::kNoPendingIO);
288         } else {
289             texture = resourceProvider->createTexture(desc, format, p.fRenderable, p.fSampleCnt,
290                                                       SkBudgeted::kNo, GrProtected::kNo,
291                                                       GrResourceProvider::Flags::kNoPendingIO);
292         }
293         return GrSurfaceProxy::LazyInstantiationResult(std::move(texture));
294     };
295     auto lazyType = deinstantiate ? GrSurfaceProxy::LazyInstantiationType ::kDeinstantiate
296                                   : GrSurfaceProxy::LazyInstantiationType ::kSingleUse;
297     GrInternalSurfaceFlags flags = GrInternalSurfaceFlags::kNone;
298     return proxyProvider->createLazyProxy(
299             callback, format, desc, p.fRenderable, p.fSampleCnt, p.fOrigin, GrMipMapped::kNo,
300             GrMipMapsStatus::kNotAllocated, flags, p.fFit, p.fBudgeted, GrProtected::kNo, lazyType);
301 }
302 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(LazyDeinstantiation,reporter,ctxInfo)303 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(LazyDeinstantiation, reporter, ctxInfo) {
304     GrContext* context = ctxInfo.grContext();
305     GrResourceProvider* resourceProvider = ctxInfo.grContext()->priv().resourceProvider();
306     ProxyParams texParams;
307     texParams.fFit = SkBackingFit::kExact;
308     texParams.fOrigin = kTopLeft_GrSurfaceOrigin;
309     texParams.fColorType = GrColorType::kRGBA_8888;
310     texParams.fRenderable = GrRenderable::kNo;
311     texParams.fSampleCnt = 1;
312     texParams.fSize = 100;
313     texParams.fBudgeted = SkBudgeted::kNo;
314     auto proxyProvider = context->priv().proxyProvider();
315     auto caps = context->priv().caps();
316     auto p0 = make_lazy(proxyProvider, caps, texParams, true);
317     auto p1 = make_lazy(proxyProvider, caps, texParams, false);
318     ProxyParams rtParams = texParams;
319     rtParams.fRenderable = GrRenderable::kYes;
320     rtParams.fFit = SkBackingFit::kApprox;
321     auto p2 = make_lazy(proxyProvider, caps, rtParams, true);
322     auto p3 = make_lazy(proxyProvider, caps, rtParams, false);
323 
324     GrDeinstantiateProxyTracker deinstantiateTracker;
325     {
326         GrResourceAllocator alloc(resourceProvider, &deinstantiateTracker SkDEBUGCODE(, 1));
327         alloc.addInterval(p0.get(), 0, 1, GrResourceAllocator::ActualUse::kNo);
328         alloc.addInterval(p1.get(), 0, 1, GrResourceAllocator::ActualUse::kNo);
329         alloc.addInterval(p2.get(), 0, 1, GrResourceAllocator::ActualUse::kNo);
330         alloc.addInterval(p3.get(), 0, 1, GrResourceAllocator::ActualUse::kNo);
331         alloc.incOps();
332         alloc.markEndOfOpList(0);
333 
334         alloc.determineRecyclability();
335 
336         int startIndex, stopIndex;
337         GrResourceAllocator::AssignError error;
338         alloc.assign(&startIndex, &stopIndex, &error);
339     }
340     deinstantiateTracker.deinstantiateAllProxies();
341     REPORTER_ASSERT(reporter, !p0->isInstantiated());
342     REPORTER_ASSERT(reporter, p1->isInstantiated());
343     REPORTER_ASSERT(reporter, !p2->isInstantiated());
344     REPORTER_ASSERT(reporter, p3->isInstantiated());
345 }
346 
347 // Set up so there are two opLists that need to be flushed but the resource allocator thinks
348 // it is over budget. The two opLists should be flushed separately and the opList indices
349 // returned from assign should be correct.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorOverBudgetTest,reporter,ctxInfo)350 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorOverBudgetTest, reporter, ctxInfo) {
351     GrContext* context = ctxInfo.grContext();
352     const GrCaps* caps = context->priv().caps();
353     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
354     GrResourceProvider* resourceProvider = context->priv().resourceProvider();
355 
356     int origMaxNum;
357     size_t origMaxBytes;
358     context->getResourceCacheLimits(&origMaxNum, &origMaxBytes);
359 
360     // Force the resource allocator to always believe it is over budget
361     context->setResourceCacheLimits(0, 0);
362 
363     const ProxyParams params  = { 64, GrRenderable::kNo, GrColorType::kRGBA_8888,
364                                   SkBackingFit::kExact, 1, kTopLeft_GrSurfaceOrigin,
365                                   SkBudgeted::kYes };
366 
367     {
368         sk_sp<GrSurfaceProxy> p1 = make_deferred(proxyProvider, caps, params);
369         sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, caps, params);
370         sk_sp<GrSurfaceProxy> p3 = make_deferred(proxyProvider, caps, params);
371         sk_sp<GrSurfaceProxy> p4 = make_deferred(proxyProvider, caps, params);
372 
373         GrDeinstantiateProxyTracker deinstantiateTracker;
374         GrResourceAllocator alloc(resourceProvider, &deinstantiateTracker SkDEBUGCODE(, 2));
375 
376         alloc.addInterval(p1.get(), 0, 0, GrResourceAllocator::ActualUse::kYes);
377         alloc.incOps();
378         alloc.addInterval(p2.get(), 1, 1, GrResourceAllocator::ActualUse::kYes);
379         alloc.incOps();
380         alloc.markEndOfOpList(0);
381 
382         alloc.addInterval(p3.get(), 2, 2, GrResourceAllocator::ActualUse::kYes);
383         alloc.incOps();
384         alloc.addInterval(p4.get(), 3, 3, GrResourceAllocator::ActualUse::kYes);
385         alloc.incOps();
386         alloc.markEndOfOpList(1);
387 
388         int startIndex, stopIndex;
389         GrResourceAllocator::AssignError error;
390 
391         alloc.determineRecyclability();
392 
393         alloc.assign(&startIndex, &stopIndex, &error);
394         REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
395         REPORTER_ASSERT(reporter, 0 == startIndex && 1 == stopIndex);
396 
397         alloc.assign(&startIndex, &stopIndex, &error);
398         REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
399         REPORTER_ASSERT(reporter, 1 == startIndex && 2 == stopIndex);
400     }
401 
402     context->setResourceCacheLimits(origMaxNum, origMaxBytes);
403 }
404