blob: c49f6b8ea07b853b47a185869e4a3451ef86894a [file] [log] [blame]
Robert Phillips1afd4cd2018-01-08 13:40:32 -05001/*
2 * Copyright 2018 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 "GrProxyProvider.h"
9
10#include "GrCaps.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050011#include "GrRenderTarget.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050012#include "GrResourceKey.h"
13#include "GrResourceProvider.h"
14#include "GrSurfaceProxy.h"
15#include "GrSurfaceProxyPriv.h"
16#include "GrTexture.h"
17#include "GrTextureProxyCacheAccess.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050018#include "GrTextureRenderTargetProxy.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050019#include "../private/GrSingleOwner.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050020#include "SkMipMap.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050021
22#define ASSERT_SINGLE_OWNER \
23 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
24
25GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider,
26 GrResourceCache* resourceCache,
27 sk_sp<const GrCaps> caps,
28 GrSingleOwner* owner)
29 : fResourceProvider(resourceProvider)
30 , fResourceCache(resourceCache)
Robert Phillips4d120512018-01-19 13:22:07 -050031 , fAbandoned(false)
Robert Phillips1afd4cd2018-01-08 13:40:32 -050032 , fCaps(caps)
33#ifdef SK_DEBUG
34 , fSingleOwner(owner)
35#endif
36{
37
38}
39
40GrProxyProvider::~GrProxyProvider() {
41 SkASSERT(!fUniquelyKeyedProxies.count());
42}
43
Robert Phillipsadbe1322018-01-17 13:35:46 -050044bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
Robert Phillips1afd4cd2018-01-08 13:40:32 -050045 ASSERT_SINGLE_OWNER
46 SkASSERT(key.isValid());
47 if (this->isAbandoned() || !proxy) {
Robert Phillipsadbe1322018-01-17 13:35:46 -050048 return false;
Robert Phillips1afd4cd2018-01-08 13:40:32 -050049 }
50
51 // If there is already a GrResource with this key then the caller has violated the normal
52 // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing
53 // if it already existed in the cache).
54 SkASSERT(!fResourceCache->findAndRefUniqueResource(key));
55
56 // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
57 // resources are a special case: the unique keys give us a weak ref so that we can reuse the
58 // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
59 // it will always be released - it is never converted to a scratch resource.
60 if (SkBudgeted::kNo == proxy->isBudgeted() &&
61 (!proxy->priv().isInstantiated() ||
62 !proxy->priv().peekSurface()->resourcePriv().refsWrappedObjects())) {
Robert Phillipsadbe1322018-01-17 13:35:46 -050063 return false;
Robert Phillips1afd4cd2018-01-08 13:40:32 -050064 }
65
66 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key
67
68 proxy->cacheAccess().setUniqueKey(this, key);
69 SkASSERT(proxy->getUniqueKey() == key);
70 fUniquelyKeyedProxies.add(proxy);
Robert Phillipsadbe1322018-01-17 13:35:46 -050071 return true;
Robert Phillips1afd4cd2018-01-08 13:40:32 -050072}
73
74void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
75 SkASSERT(surf->getUniqueKey().isValid());
76 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
77 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
78 // multiple proxies can't get the same key
79 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
80 fUniquelyKeyedProxies.add(proxy);
81}
82
83void GrProxyProvider::removeUniqueKeyFromProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
84 ASSERT_SINGLE_OWNER
85 if (this->isAbandoned() || !proxy) {
86 return;
87 }
88 this->processInvalidProxyUniqueKey(key, proxy, true);
89}
90
91sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key,
92 GrSurfaceOrigin origin) {
93 ASSERT_SINGLE_OWNER
94
95 if (this->isAbandoned()) {
96 return nullptr;
97 }
98
99 sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
100 if (result) {
101 SkASSERT(result->origin() == origin);
102 }
103 return result;
104}
105
Robert Phillipsadbe1322018-01-17 13:35:46 -0500106sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) {
107#ifdef SK_DEBUG
108 if (tex->getUniqueKey().isValid()) {
109 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin));
110 }
111#endif
112
113 if (tex->asRenderTarget()) {
114 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin));
115 } else {
116 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin));
117 }
118}
119
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500120sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key,
121 GrSurfaceOrigin origin) {
122 ASSERT_SINGLE_OWNER
123
124 if (this->isAbandoned()) {
125 return nullptr;
126 }
127
128 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin);
129 if (result) {
130 return result;
131 }
132
133 GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key);
134 if (!resource) {
135 return nullptr;
136 }
137
138 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
139 SkASSERT(texture);
140
Robert Phillipsadbe1322018-01-17 13:35:46 -0500141 result = this->createWrapped(std::move(texture), origin);
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500142 SkASSERT(result->getUniqueKey() == key);
Robert Phillipsadbe1322018-01-17 13:35:46 -0500143 // createWrapped should've added this for us
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500144 SkASSERT(fUniquelyKeyedProxies.find(key));
145 return result;
146}
147
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500148sk_sp<GrTextureProxy> GrProxyProvider::createInstantiatedProxy(const GrSurfaceDesc& desc,
149 SkBackingFit fit,
150 SkBudgeted budgeted,
151 uint32_t flags) {
152 sk_sp<GrTexture> tex;
153
154 if (SkBackingFit::kApprox == fit) {
155 tex = fResourceProvider->createApproxTexture(desc, flags);
156 } else {
157 tex = fResourceProvider->createTexture(desc, budgeted, flags);
158 }
159 if (!tex) {
160 return nullptr;
161 }
162
Robert Phillipsadbe1322018-01-17 13:35:46 -0500163 return this->createWrapped(std::move(tex), desc.fOrigin);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500164}
165
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500166sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(const GrSurfaceDesc& desc,
167 SkBudgeted budgeted,
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500168 const void* srcData, size_t rowBytes) {
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500169 ASSERT_SINGLE_OWNER
170
Robert Phillips579f0942018-01-08 14:53:35 -0500171 if (this->isAbandoned()) {
172 return nullptr;
173 }
174
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500175 if (srcData) {
176 GrMipLevel mipLevel = { srcData, rowBytes };
177
178 sk_sp<GrTexture> tex = fResourceProvider->createTexture(desc, budgeted, mipLevel);
179 if (!tex) {
180 return nullptr;
181 }
182
Robert Phillipsadbe1322018-01-17 13:35:46 -0500183 return this->createWrapped(std::move(tex), desc.fOrigin);
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500184 }
185
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500186 return this->createProxy(desc, SkBackingFit::kExact, budgeted);
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500187}
188
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500189sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500190 const GrSurfaceDesc& desc, SkBudgeted budgeted,
191 const GrMipLevel texels[], int mipLevelCount,
192 SkDestinationSurfaceColorMode mipColorMode) {
Robert Phillips579f0942018-01-08 14:53:35 -0500193 ASSERT_SINGLE_OWNER
194
195 if (this->isAbandoned()) {
196 return nullptr;
197 }
198
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500199 if (!mipLevelCount) {
200 if (texels) {
201 return nullptr;
202 }
203 return this->createProxy(desc, SkBackingFit::kExact, budgeted);
204 }
205 if (!texels) {
206 return nullptr;
207 }
208
209 if (1 == mipLevelCount) {
210 return this->createTextureProxy(desc, budgeted, texels[0].fPixels, texels[0].fRowBytes);
211 }
212
213#ifdef SK_DEBUG
214 // There are only three states we want to be in when uploading data to a mipped surface.
215 // 1) We have data to upload to all layers
216 // 2) We are not uploading data to any layers
217 // 3) We are only uploading data to the base layer
218 // We check here to make sure we do not have any other state.
219 bool firstLevelHasData = SkToBool(texels[0].fPixels);
220 bool allOtherLevelsHaveData = true, allOtherLevelsLackData = true;
221 for (int i = 1; i < mipLevelCount; ++i) {
222 if (texels[i].fPixels) {
223 allOtherLevelsLackData = false;
224 } else {
225 allOtherLevelsHaveData = false;
226 }
227 }
228 SkASSERT((firstLevelHasData && allOtherLevelsHaveData) || allOtherLevelsLackData);
229#endif
230
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500231 sk_sp<GrTexture> tex(fResourceProvider->createTexture(desc, budgeted,
232 texels, mipLevelCount,
233 mipColorMode));
234 if (!tex) {
235 return nullptr;
236 }
237
Robert Phillipsadbe1322018-01-17 13:35:46 -0500238 return this->createWrapped(std::move(tex), desc.fOrigin);
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500239}
240
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500241sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrSurfaceDesc& desc,
242 SkBudgeted budgeted) {
243 // SkMipMap doesn't include the base level in the level count so we have to add 1
244 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
245
246 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]);
247
248 // We don't want to upload any texel data
249 for (int i = 0; i < mipCount; i++) {
250 texels[i].fPixels = nullptr;
251 texels[i].fRowBytes = 0;
252 }
253
254 return this->createMipMapProxy(desc, budgeted, texels.get(), mipCount,
255 SkDestinationSurfaceColorMode::kLegacy);
256}
257
258sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc,
259 SkBackingFit fit,
260 SkBudgeted budgeted,
261 uint32_t flags) {
262 SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags);
263
264 const GrCaps* caps = this->caps();
265
266 // TODO: move this logic into GrResourceProvider!
267 // TODO: share this testing code with check_texture_creation_params
268 if (!caps->isConfigTexturable(desc.fConfig)) {
269 return nullptr;
270 }
271
272 bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
273 if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
274 return nullptr;
275 }
276
277 // We currently do not support multisampled textures
278 if (!willBeRT && desc.fSampleCnt > 0) {
279 return nullptr;
280 }
281
282 int maxSize;
283 if (willBeRT) {
284 maxSize = caps->maxRenderTargetSize();
285 } else {
286 maxSize = caps->maxTextureSize();
287 }
288
289 if (desc.fWidth > maxSize || desc.fHeight > maxSize || desc.fWidth <= 0 || desc.fHeight <= 0) {
290 return nullptr;
291 }
292
293 GrSurfaceDesc copyDesc = desc;
294 copyDesc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig);
295
296#ifdef SK_DISABLE_DEFERRED_PROXIES
297 // Temporarily force instantiation for crbug.com/769760 and crbug.com/769898
298 sk_sp<GrTexture> tex;
299
300 if (SkBackingFit::kApprox == fit) {
301 tex = resourceProvider->createApproxTexture(copyDesc, flags);
302 } else {
303 tex = resourceProvider->createTexture(copyDesc, budgeted, flags);
304 }
305
306 if (!tex) {
307 return nullptr;
308 }
309
310 return GrSurfaceProxy::MakeWrapped(std::move(tex), copyDesc.fOrigin);
311#else
312 if (willBeRT) {
313 // We know anything we instantiate later from this deferred path will be
314 // both texturable and renderable
315 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit,
316 budgeted, flags));
317 }
318
319 return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags));
320#endif
321}
322
Robert Phillipsadbe1322018-01-17 13:35:46 -0500323sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(
324 const GrBackendTexture& backendTex,
325 GrSurfaceOrigin origin,
326 GrWrapOwnership ownership,
327 ReleaseProc releaseProc,
328 ReleaseContext releaseCtx) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500329 if (this->isAbandoned()) {
330 return nullptr;
331 }
332
Robert Phillipsadbe1322018-01-17 13:35:46 -0500333 sk_sp<GrTexture> texture(fResourceProvider->wrapBackendTexture(backendTex, ownership));
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500334 if (!texture) {
335 return nullptr;
336 }
Robert Phillipsadbe1322018-01-17 13:35:46 -0500337 if (releaseProc) {
338 texture->setRelease(releaseProc, releaseCtx);
339 }
340
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500341 SkASSERT(!texture->asRenderTarget()); // Strictly a GrTexture
342
Robert Phillipsadbe1322018-01-17 13:35:46 -0500343 return this->createWrapped(std::move(texture), origin);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500344}
345
346sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& tex,
347 GrSurfaceOrigin origin,
348 int sampleCnt) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500349 if (this->isAbandoned()) {
350 return nullptr;
351 }
352
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500353 sk_sp<GrTexture> texture(fResourceProvider->wrapRenderableBackendTexture(tex, sampleCnt));
354 if (!texture) {
355 return nullptr;
356 }
357 SkASSERT(texture->asRenderTarget()); // A GrTextureRenderTarget
358
Robert Phillipsadbe1322018-01-17 13:35:46 -0500359 return this->createWrapped(std::move(texture), origin);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500360}
361
362sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(
363 const GrBackendRenderTarget& backendRT,
364 GrSurfaceOrigin origin) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500365 if (this->isAbandoned()) {
366 return nullptr;
367 }
368
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500369 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendRenderTarget(backendRT));
370 if (!rt) {
371 return nullptr;
372 }
373 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget
374 SkASSERT(!rt->getUniqueKey().isValid());
375
376 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
377}
378
379sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(const GrBackendTexture& tex,
380 GrSurfaceOrigin origin,
381 int sampleCnt) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500382 if (this->isAbandoned()) {
383 return nullptr;
384 }
385
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500386 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendTextureAsRenderTarget(tex, sampleCnt));
387 if (!rt) {
388 return nullptr;
389 }
390 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget
391 SkASSERT(!rt->getUniqueKey().isValid());
392
393 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
394}
395
Robert Phillips777707b2018-01-17 11:40:14 -0500396sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
397 const GrSurfaceDesc& desc,
398 GrMipMapped mipMapped,
399 SkBackingFit fit, SkBudgeted budgeted) {
400 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
401 (desc.fWidth > 0 && desc.fHeight > 0));
402 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag;
403 return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ?
404 new GrTextureRenderTargetProxy(std::move(callback), desc,
405 mipMapped, fit, budgeted, flags) :
406 new GrTextureProxy(std::move(callback), desc, mipMapped, fit,
407 budgeted, flags));
408
409}
410
411sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback,
412 Renderable renderable,
413 GrPixelConfig config) {
414 GrSurfaceDesc desc;
415 if (Renderable::kYes == renderable) {
416 desc.fFlags = kRenderTarget_GrSurfaceFlag;
417 }
418 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
419 desc.fWidth = -1;
420 desc.fHeight = -1;
421 desc.fConfig = config;
422 desc.fSampleCnt = 0;
423
424 return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo,
425 SkBackingFit::kApprox, SkBudgeted::kYes);
426
427}
428
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500429bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
430 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height()));
431}
432
433void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key) {
434 // Note: this method is called for the whole variety of GrGpuResources so often 'key'
435 // will not be in 'fUniquelyKeyedProxies'.
436 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
437 if (proxy) {
438 this->processInvalidProxyUniqueKey(key, proxy, false);
439 }
440}
441
442void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
443 bool invalidateSurface) {
444 SkASSERT(proxy);
445 SkASSERT(proxy->getUniqueKey().isValid());
446 SkASSERT(proxy->getUniqueKey() == key);
447
448 fUniquelyKeyedProxies.remove(key);
449 proxy->cacheAccess().clearUniqueKey();
450
451 if (invalidateSurface && proxy->priv().isInstantiated()) {
452 GrSurface* surface = proxy->priv().peekSurface();
453 if (surface) {
454 surface->resourcePriv().removeUniqueKey();
455 }
456 }
457}
458
459void GrProxyProvider::removeAllUniqueKeys() {
460 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
461 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
462 GrTextureProxy& tmp = *iter;
463
464 this->processInvalidProxyUniqueKey(tmp.getUniqueKey(), &tmp, false);
465 }
466 SkASSERT(!fUniquelyKeyedProxies.count());
467}