• 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 // This is a GPU-backend specific test.
9 
10 #include "tests/Test.h"
11 
12 #include "include/gpu/GrBackendSurface.h"
13 #include "include/gpu/GrTexture.h"
14 #include "src/gpu/GrContextPriv.h"
15 #include "src/gpu/GrProxyProvider.h"
16 #include "src/gpu/GrResourceCache.h"
17 #include "src/gpu/GrResourceProvider.h"
18 #include "src/gpu/GrTextureProxy.h"
19 
20 #include "include/core/SkImage.h"
21 #include "src/gpu/SkGr.h"
22 
numUniqueKeyProxies_TestOnly() const23 int GrProxyProvider::numUniqueKeyProxies_TestOnly() const {
24     return fUniquelyKeyedProxies.count();
25 }
26 
27 static constexpr auto kColorType = GrColorType::kRGBA_8888;
28 static constexpr auto kSize = SkISize::Make(64, 64);
make_desc()29 static GrSurfaceDesc make_desc() {
30     GrSurfaceDesc desc;
31     desc.fWidth = kSize.width();
32     desc.fHeight = kSize.height();
33     desc.fConfig = GrColorTypeToPixelConfig(kColorType);
34     return desc;
35 }
36 
37 ///////////////////////////////////////////////////////////////////////////////////////////////////
38 // Basic test
39 
deferred_tex(skiatest::Reporter * reporter,GrContext * ctx,GrProxyProvider * proxyProvider,SkBackingFit fit)40 static sk_sp<GrTextureProxy> deferred_tex(skiatest::Reporter* reporter, GrContext* ctx,
41                                           GrProxyProvider* proxyProvider, SkBackingFit fit) {
42     const GrCaps* caps = ctx->priv().caps();
43 
44     const GrSurfaceDesc desc = make_desc();
45     GrBackendFormat format = caps->getDefaultBackendFormat(kColorType, GrRenderable::kNo);
46 
47     sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(format, desc, GrRenderable::kNo, 1,
48                                                              kBottomLeft_GrSurfaceOrigin, fit,
49                                                              SkBudgeted::kYes, GrProtected::kNo);
50     // Only budgeted & wrapped external proxies get to carry uniqueKeys
51     REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid());
52     return proxy;
53 }
54 
deferred_texRT(skiatest::Reporter * reporter,GrContext * ctx,GrProxyProvider * proxyProvider,SkBackingFit fit)55 static sk_sp<GrTextureProxy> deferred_texRT(skiatest::Reporter* reporter, GrContext* ctx,
56                                             GrProxyProvider* proxyProvider, SkBackingFit fit) {
57     const GrCaps* caps = ctx->priv().caps();
58 
59     const GrSurfaceDesc desc = make_desc();
60 
61     GrBackendFormat format = caps->getDefaultBackendFormat(kColorType, GrRenderable::kYes);
62 
63     sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(format, desc, GrRenderable::kYes, 1,
64                                                              kBottomLeft_GrSurfaceOrigin, fit,
65                                                              SkBudgeted::kYes, GrProtected::kNo);
66     // Only budgeted & wrapped external proxies get to carry uniqueKeys
67     REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid());
68     return proxy;
69 }
70 
wrapped(skiatest::Reporter * reporter,GrContext * ctx,GrProxyProvider * proxyProvider,SkBackingFit fit)71 static sk_sp<GrTextureProxy> wrapped(skiatest::Reporter* reporter, GrContext* ctx,
72                                      GrProxyProvider* proxyProvider, SkBackingFit fit) {
73     sk_sp<GrTextureProxy> proxy = proxyProvider->testingOnly_createInstantiatedProxy(
74             kSize, kColorType, GrRenderable::kNo, 1, kBottomLeft_GrSurfaceOrigin, fit,
75             SkBudgeted::kYes, GrProtected::kNo);
76     // Only budgeted & wrapped external proxies get to carry uniqueKeys
77     REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid());
78     return proxy;
79 }
80 
wrapped_with_key(skiatest::Reporter * reporter,GrContext * ctx,GrProxyProvider * proxyProvider,SkBackingFit fit)81 static sk_sp<GrTextureProxy> wrapped_with_key(skiatest::Reporter* reporter, GrContext* ctx,
82                                               GrProxyProvider* proxyProvider, SkBackingFit fit) {
83     static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
84     static int kUniqueKeyData = 0;
85 
86     GrUniqueKey key;
87 
88     GrUniqueKey::Builder builder(&key, d, 1, nullptr);
89     builder[0] = kUniqueKeyData++;
90     builder.finish();
91 
92     // Only budgeted & wrapped external proxies get to carry uniqueKeys
93     sk_sp<GrTextureProxy> proxy = proxyProvider->testingOnly_createInstantiatedProxy(
94             kSize, kColorType, GrRenderable::kNo, 1, kBottomLeft_GrSurfaceOrigin, fit,
95             SkBudgeted::kYes, GrProtected::kNo);
96     SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get()));
97     REPORTER_ASSERT(reporter, proxy->getUniqueKey().isValid());
98     return proxy;
99 }
100 
create_wrapped_backend(GrContext * context,SkBackingFit fit,sk_sp<GrTexture> * backingSurface)101 static sk_sp<GrTextureProxy> create_wrapped_backend(GrContext* context, SkBackingFit fit,
102                                                     sk_sp<GrTexture>* backingSurface) {
103     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
104     GrResourceProvider* resourceProvider = context->priv().resourceProvider();
105 
106     const GrSurfaceDesc desc = make_desc();
107     GrBackendFormat format =
108             proxyProvider->caps()->getDefaultBackendFormat(kColorType, GrRenderable::kYes);
109 
110     *backingSurface = resourceProvider->createTexture(desc, format, GrRenderable::kNo, 1,
111                                                       SkBudgeted::kNo, GrProtected::kNo,
112                                                       GrResourceProvider::Flags::kNoPendingIO);
113     if (!(*backingSurface)) {
114         return nullptr;
115     }
116 
117     GrBackendTexture backendTex = (*backingSurface)->getBackendTexture();
118 
119     return proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
120                                              kBottomLeft_GrSurfaceOrigin, kBorrow_GrWrapOwnership,
121                                              GrWrapCacheable::kYes, kRead_GrIOType);
122 }
123 
124 
125 // This tests the basic capabilities of the uniquely keyed texture proxies. Does assigning
126 // and looking them up work, etc.
basic_test(GrContext * context,skiatest::Reporter * reporter,sk_sp<GrTextureProxy> proxy)127 static void basic_test(GrContext* context,
128                        skiatest::Reporter* reporter,
129                        sk_sp<GrTextureProxy> proxy) {
130     static int id = 1;
131 
132     GrResourceProvider* resourceProvider = context->priv().resourceProvider();
133     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
134     GrResourceCache* cache = context->priv().getResourceCache();
135 
136     int startCacheCount = cache->getResourceCount();
137 
138     GrUniqueKey key;
139     if (proxy->getUniqueKey().isValid()) {
140         key = proxy->getUniqueKey();
141     } else {
142         GrMakeKeyFromImageID(&key, id, SkIRect::MakeWH(64, 64));
143         ++id;
144 
145         // Assigning the uniqueKey adds the proxy to the hash but doesn't force instantiation
146         REPORTER_ASSERT(reporter, !proxyProvider->numUniqueKeyProxies_TestOnly());
147         SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get()));
148     }
149 
150     REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly());
151     REPORTER_ASSERT(reporter, startCacheCount == cache->getResourceCount());
152 
153     // setUniqueKey had better stick
154     REPORTER_ASSERT(reporter, key == proxy->getUniqueKey());
155 
156     // We just added it, surely we can find it
157     REPORTER_ASSERT(reporter, proxyProvider->findOrCreateProxyByUniqueKey(
158                                       key, kColorType, kBottomLeft_GrSurfaceOrigin));
159     REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly());
160 
161     int expectedCacheCount = startCacheCount + (proxy->isInstantiated() ? 0 : 1);
162 
163     // Once instantiated, the backing resource should have the same key
164     SkAssertResult(proxy->instantiate(resourceProvider));
165     const GrUniqueKey texKey = proxy->peekSurface()->getUniqueKey();
166     REPORTER_ASSERT(reporter, texKey.isValid());
167     REPORTER_ASSERT(reporter, key == texKey);
168 
169     // An Unbudgeted-cacheable resource will not get purged when a proxy with the same key is
170     // deleted.
171     bool expectResourceToOutliveProxy = proxy->peekSurface()->resourcePriv().budgetedType() ==
172                                         GrBudgetedType::kUnbudgetedCacheable;
173 
174     // An Unbudgeted-uncacheable resource is never kept alive if it's ref cnt reaches zero even if
175     // it has a key.
176     bool expectDeletingProxyToDeleteResource =
177             proxy->peekSurface()->resourcePriv().budgetedType() ==
178             GrBudgetedType::kUnbudgetedUncacheable;
179 
180     // deleting the proxy should delete it from the hash but not the cache
181     proxy = nullptr;
182     if (expectDeletingProxyToDeleteResource) {
183         expectedCacheCount -= 1;
184     }
185     REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly());
186     REPORTER_ASSERT(reporter, expectedCacheCount == cache->getResourceCount());
187 
188     // If the proxy was cached refinding it should bring it back to life
189     proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kColorType,
190                                                         kBottomLeft_GrSurfaceOrigin);
191     REPORTER_ASSERT(reporter, proxy);
192     REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly());
193     REPORTER_ASSERT(reporter, expectedCacheCount == cache->getResourceCount());
194 
195     // Mega-purging it should remove it from both the hash and the cache
196     proxy = nullptr;
197     cache->purgeAllUnlocked();
198     if (!expectResourceToOutliveProxy) {
199         expectedCacheCount--;
200     }
201     REPORTER_ASSERT(reporter, expectedCacheCount == cache->getResourceCount());
202 
203     // If the texture was deleted then the proxy should no longer be findable. Otherwise, it should
204     // be.
205     proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kColorType,
206                                                         kBottomLeft_GrSurfaceOrigin);
207     REPORTER_ASSERT(reporter, expectResourceToOutliveProxy ? (bool)proxy : !proxy);
208     REPORTER_ASSERT(reporter, expectedCacheCount == cache->getResourceCount());
209 
210     if (expectResourceToOutliveProxy) {
211         proxy.reset();
212         GrUniqueKeyInvalidatedMessage msg(texKey, context->priv().contextID());
213         SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(msg);
214         cache->purgeAsNeeded();
215         expectedCacheCount--;
216         proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kColorType,
217                                                             kBottomLeft_GrSurfaceOrigin);
218         REPORTER_ASSERT(reporter, !proxy);
219         REPORTER_ASSERT(reporter, expectedCacheCount == cache->getResourceCount());
220     }
221 }
222 
223 ///////////////////////////////////////////////////////////////////////////////////////////////////
224 // Invalidation test
225 
226 // Test if invalidating unique ids operates as expected for texture proxies.
invalidation_test(GrContext * context,skiatest::Reporter * reporter)227 static void invalidation_test(GrContext* context, skiatest::Reporter* reporter) {
228 
229     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
230     GrResourceCache* cache = context->priv().getResourceCache();
231     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
232 
233     sk_sp<SkImage> rasterImg;
234 
235     {
236         SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
237 
238         SkBitmap bm;
239         bm.allocPixels(ii);
240 
241         rasterImg = SkImage::MakeFromBitmap(bm);
242         REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly());
243         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
244     }
245 
246     sk_sp<SkImage> textureImg = rasterImg->makeTextureImage(context);
247     REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly());
248     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
249 
250     rasterImg = nullptr;        // this invalidates the uniqueKey
251 
252     // this forces the cache to respond to the inval msg
253     int maxNum;
254     size_t maxBytes;
255     context->getResourceCacheLimits(&maxNum, &maxBytes);
256     context->setResourceCacheLimits(maxNum-1, maxBytes);
257 
258     REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly());
259     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
260 
261     textureImg = nullptr;
262     context->priv().testingOnly_purgeAllUnlockedResources();
263 
264     REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly());
265     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
266 }
267 
268 // Test if invalidating unique ids prior to instantiating operates as expected
invalidation_and_instantiation_test(GrContext * context,skiatest::Reporter * reporter)269 static void invalidation_and_instantiation_test(GrContext* context, skiatest::Reporter* reporter) {
270     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
271     GrResourceProvider* resourceProvider = context->priv().resourceProvider();
272     GrResourceCache* cache = context->priv().getResourceCache();
273     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
274 
275     static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
276     GrUniqueKey key;
277     GrUniqueKey::Builder builder(&key, d, 1, nullptr);
278     builder[0] = 0;
279     builder.finish();
280 
281     // Create proxy, assign unique key
282     sk_sp<GrTextureProxy> proxy = deferred_tex(reporter, context, proxyProvider,
283                                                SkBackingFit::kExact);
284     SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get()));
285 
286     // Send an invalidation message, which will be sitting in the cache's inbox
287     SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(
288             GrUniqueKeyInvalidatedMessage(key, context->priv().contextID()));
289 
290     REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly());
291     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
292 
293     // Instantiate the proxy. This will trigger the message to be processed, so the resulting
294     // texture should *not* have the unique key on it!
295     SkAssertResult(proxy->instantiate(resourceProvider));
296 
297     REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid());
298     REPORTER_ASSERT(reporter, !proxy->peekTexture()->getUniqueKey().isValid());
299     REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly());
300     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
301 
302     proxy = nullptr;
303     context->priv().testingOnly_purgeAllUnlockedResources();
304 
305     REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly());
306     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
307 }
308 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureProxyTest,reporter,ctxInfo)309 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureProxyTest, reporter, ctxInfo) {
310     GrContext* context = ctxInfo.grContext();
311     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
312     GrResourceCache* cache = context->priv().getResourceCache();
313 
314     REPORTER_ASSERT(reporter, !proxyProvider->numUniqueKeyProxies_TestOnly());
315     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
316 
317     for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) {
318         for (auto create : { deferred_tex, deferred_texRT, wrapped, wrapped_with_key }) {
319             REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
320             basic_test(context, reporter, create(reporter, context, proxyProvider, fit));
321         }
322 
323         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
324         sk_sp<GrTexture> backingTex;
325         sk_sp<GrTextureProxy> proxy = create_wrapped_backend(context, fit, &backingTex);
326         basic_test(context, reporter, std::move(proxy));
327 
328         backingTex = nullptr;
329         cache->purgeAllUnlocked();
330     }
331 
332     invalidation_test(context, reporter);
333     invalidation_and_instantiation_test(context, reporter);
334 }
335