blob: 7e9c251d33ae6e7c5ed79d3b7d25c95eb3ba32b9 [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
Greg Danielf2336e42018-01-23 16:38:14 -0500333 GrSurfaceDesc desc;
334 desc.fOrigin = origin;
335 desc.fWidth = backendTex.width();
336 desc.fHeight = backendTex.height();
337 desc.fConfig = backendTex.config();
338 GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo;
Robert Phillipsadbe1322018-01-17 13:35:46 -0500339
Greg Danielf2336e42018-01-23 16:38:14 -0500340 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
341 [backendTex, ownership, releaseProc, releaseCtx]
342 (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) {
343 if (!resourceProvider) {
344 // This lazy proxy was never initialized. If it has a releaseProc we must call
345 // it now so that the client knows they can free the underlying backend object.
346 if (releaseProc) {
347 releaseProc(releaseCtx);
348 }
349 return sk_sp<GrTexture>();
350 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500351
Greg Danielf2336e42018-01-23 16:38:14 -0500352 sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex,
353 ownership);
354 if (!tex) {
355 return sk_sp<GrTexture>();
356 }
357 if (releaseProc) {
358 tex->setRelease(releaseProc, releaseCtx);
359 }
360 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
361 // Make sure we match how we created the proxy with SkBudgeted::kNo
362 SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted());
363
364 return tex;
365 }, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo);
366
367 if (fResourceProvider) {
368 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however,
369 // we're better off instantiating the proxy immediately here.
Greg Danielbddcc952018-01-24 13:22:24 -0500370 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
371 return nullptr;
372 }
Greg Danielf2336e42018-01-23 16:38:14 -0500373 }
374 return proxy;
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500375}
376
377sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& tex,
378 GrSurfaceOrigin origin,
379 int sampleCnt) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500380 if (this->isAbandoned()) {
381 return nullptr;
382 }
383
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500384 sk_sp<GrTexture> texture(fResourceProvider->wrapRenderableBackendTexture(tex, sampleCnt));
385 if (!texture) {
386 return nullptr;
387 }
388 SkASSERT(texture->asRenderTarget()); // A GrTextureRenderTarget
389
Robert Phillipsadbe1322018-01-17 13:35:46 -0500390 return this->createWrapped(std::move(texture), origin);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500391}
392
393sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(
394 const GrBackendRenderTarget& backendRT,
395 GrSurfaceOrigin origin) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500396 if (this->isAbandoned()) {
397 return nullptr;
398 }
399
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500400 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendRenderTarget(backendRT));
401 if (!rt) {
402 return nullptr;
403 }
404 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget
405 SkASSERT(!rt->getUniqueKey().isValid());
406
407 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
408}
409
410sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(const GrBackendTexture& tex,
411 GrSurfaceOrigin origin,
412 int sampleCnt) {
Robert Phillipsf9bec202018-01-16 09:21:01 -0500413 if (this->isAbandoned()) {
414 return nullptr;
415 }
416
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500417 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendTextureAsRenderTarget(tex, sampleCnt));
418 if (!rt) {
419 return nullptr;
420 }
421 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget
422 SkASSERT(!rt->getUniqueKey().isValid());
423
424 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
425}
426
Robert Phillips777707b2018-01-17 11:40:14 -0500427sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
428 const GrSurfaceDesc& desc,
429 GrMipMapped mipMapped,
430 SkBackingFit fit, SkBudgeted budgeted) {
431 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
432 (desc.fWidth > 0 && desc.fHeight > 0));
433 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag;
434 return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ?
435 new GrTextureRenderTargetProxy(std::move(callback), desc,
436 mipMapped, fit, budgeted, flags) :
437 new GrTextureProxy(std::move(callback), desc, mipMapped, fit,
438 budgeted, flags));
439
440}
441
442sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback,
443 Renderable renderable,
444 GrPixelConfig config) {
445 GrSurfaceDesc desc;
446 if (Renderable::kYes == renderable) {
447 desc.fFlags = kRenderTarget_GrSurfaceFlag;
448 }
449 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
450 desc.fWidth = -1;
451 desc.fHeight = -1;
452 desc.fConfig = config;
453 desc.fSampleCnt = 0;
454
455 return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo,
456 SkBackingFit::kApprox, SkBudgeted::kYes);
457
458}
459
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500460bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
461 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height()));
462}
463
464void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key) {
465 // Note: this method is called for the whole variety of GrGpuResources so often 'key'
466 // will not be in 'fUniquelyKeyedProxies'.
467 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
468 if (proxy) {
469 this->processInvalidProxyUniqueKey(key, proxy, false);
470 }
471}
472
473void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
474 bool invalidateSurface) {
475 SkASSERT(proxy);
476 SkASSERT(proxy->getUniqueKey().isValid());
477 SkASSERT(proxy->getUniqueKey() == key);
478
479 fUniquelyKeyedProxies.remove(key);
480 proxy->cacheAccess().clearUniqueKey();
481
482 if (invalidateSurface && proxy->priv().isInstantiated()) {
483 GrSurface* surface = proxy->priv().peekSurface();
484 if (surface) {
485 surface->resourcePriv().removeUniqueKey();
486 }
487 }
488}
489
490void GrProxyProvider::removeAllUniqueKeys() {
491 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
492 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
493 GrTextureProxy& tmp = *iter;
494
495 this->processInvalidProxyUniqueKey(tmp.getUniqueKey(), &tmp, false);
496 }
497 SkASSERT(!fUniquelyKeyedProxies.count());
498}