1/* 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" 11#include "GrRenderTarget.h" 12#include "GrResourceKey.h" 13#include "GrResourceProvider.h" 14#include "GrSurfaceProxy.h" 15#include "GrSurfaceProxyPriv.h" 16#include "GrTexture.h" 17#include "GrTextureProxyCacheAccess.h" 18#include "GrTextureRenderTargetProxy.h" 19#include "../private/GrSingleOwner.h" 20#include "SkGr.h" 21#include "SkImage.h" 22#include "SkImage_Base.h" 23#include "SkMipMap.h" 24 25#define ASSERT_SINGLE_OWNER \ 26 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) 27 28GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider, 29 GrResourceCache* resourceCache, 30 sk_sp<const GrCaps> caps, 31 GrSingleOwner* owner) 32 : fResourceProvider(resourceProvider) 33 , fResourceCache(resourceCache) 34 , fAbandoned(false) 35 , fCaps(caps) 36#ifdef SK_DEBUG 37 , fSingleOwner(owner) 38#endif 39{ 40 41} 42 43GrProxyProvider::~GrProxyProvider() { 44 SkASSERT(!fUniquelyKeyedProxies.count()); 45} 46 47bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { 48 ASSERT_SINGLE_OWNER 49 SkASSERT(key.isValid()); 50 if (this->isAbandoned() || !proxy) { 51 return false; 52 } 53 54 // If there is already a GrResource with this key then the caller has violated the normal 55 // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing 56 // if it already existed in the cache). 57 SkASSERT(!fResourceCache || !fResourceCache->findAndRefUniqueResource(key)); 58 59 // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped 60 // resources are a special case: the unique keys give us a weak ref so that we can reuse the 61 // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced, 62 // it will always be released - it is never converted to a scratch resource. 63 if (SkBudgeted::kNo == proxy->isBudgeted() && 64 (!proxy->priv().isInstantiated() || 65 !proxy->priv().peekSurface()->resourcePriv().refsWrappedObjects())) { 66 return false; 67 } 68 69 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key 70 71 proxy->cacheAccess().setUniqueKey(this, key); 72 SkASSERT(proxy->getUniqueKey() == key); 73 fUniquelyKeyedProxies.add(proxy); 74 return true; 75} 76 77void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) { 78 SkASSERT(surf->getUniqueKey().isValid()); 79 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey()); 80 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey()); 81 // multiple proxies can't get the same key 82 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey())); 83 fUniquelyKeyedProxies.add(proxy); 84} 85 86void GrProxyProvider::removeUniqueKeyFromProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { 87 ASSERT_SINGLE_OWNER 88 if (this->isAbandoned() || !proxy) { 89 return; 90 } 91 this->processInvalidProxyUniqueKey(key, proxy, true); 92} 93 94sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key, 95 GrSurfaceOrigin origin) { 96 ASSERT_SINGLE_OWNER 97 98 if (this->isAbandoned()) { 99 return nullptr; 100 } 101 102 sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key)); 103 if (result) { 104 SkASSERT(result->origin() == origin); 105 } 106 return result; 107} 108 109sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) { 110#ifdef SK_DEBUG 111 if (tex->getUniqueKey().isValid()) { 112 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin)); 113 } 114#endif 115 116 if (tex->asRenderTarget()) { 117 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin)); 118 } else { 119 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin)); 120 } 121} 122 123sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key, 124 GrSurfaceOrigin origin) { 125 ASSERT_SINGLE_OWNER 126 127 if (this->isAbandoned()) { 128 return nullptr; 129 } 130 131 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin); 132 if (result) { 133 return result; 134 } 135 136 if (!fResourceCache) { 137 return nullptr; 138 } 139 140 GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key); 141 if (!resource) { 142 return nullptr; 143 } 144 145 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture()); 146 SkASSERT(texture); 147 148 result = this->createWrapped(std::move(texture), origin); 149 SkASSERT(result->getUniqueKey() == key); 150 // createWrapped should've added this for us 151 SkASSERT(fUniquelyKeyedProxies.find(key)); 152 return result; 153} 154 155sk_sp<GrTextureProxy> GrProxyProvider::createInstantiatedProxy(const GrSurfaceDesc& desc, 156 SkBackingFit fit, 157 SkBudgeted budgeted, 158 uint32_t flags) { 159 sk_sp<GrTexture> tex; 160 161 if (SkBackingFit::kApprox == fit) { 162 tex = fResourceProvider->createApproxTexture(desc, flags); 163 } else { 164 tex = fResourceProvider->createTexture(desc, budgeted, flags); 165 } 166 if (!tex) { 167 return nullptr; 168 } 169 170 return this->createWrapped(std::move(tex), desc.fOrigin); 171} 172 173sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(const GrSurfaceDesc& desc, 174 SkBudgeted budgeted, 175 const void* srcData, size_t rowBytes) { 176 ASSERT_SINGLE_OWNER 177 178 if (this->isAbandoned()) { 179 return nullptr; 180 } 181 182 if (srcData) { 183 GrMipLevel mipLevel = { srcData, rowBytes }; 184 185 sk_sp<GrTexture> tex = fResourceProvider->createTexture(desc, budgeted, mipLevel); 186 if (!tex) { 187 return nullptr; 188 } 189 190 return this->createWrapped(std::move(tex), desc.fOrigin); 191 } 192 193 return this->createProxy(desc, SkBackingFit::kExact, budgeted); 194} 195 196sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage, 197 GrSurfaceFlags flags, 198 GrSurfaceOrigin origin, 199 int sampleCnt, 200 SkBudgeted budgeted) { 201 ASSERT_SINGLE_OWNER 202 SkASSERT(srcImage); 203 204 if (this->isAbandoned()) { 205 return nullptr; 206 } 207 208 GrSurfaceDesc desc; 209 desc.fWidth = srcImage->width(); 210 desc.fHeight = srcImage->height(); 211 desc.fFlags = flags; 212 desc.fOrigin = origin; 213 desc.fSampleCnt = sampleCnt; 214 desc.fConfig = SkImageInfo2GrPixelConfig(as_IB(srcImage)->onImageInfo(), *this->caps()); 215 216 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 217 [desc, budgeted, srcImage] 218 (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) { 219 if (!resourceProvider) { 220 // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref 221 // on srcImage will be released. 222 return sk_sp<GrTexture>(); 223 } 224 SkPixmap pixMap; 225 SkAssertResult(srcImage->peekPixels(&pixMap)); 226 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() }; 227 228 return resourceProvider->createTexture(desc, budgeted, mipLevel); 229 }, desc, GrMipMapped::kNo, SkBackingFit::kExact, budgeted); 230 231 if (fResourceProvider) { 232 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 233 // we're better off instantiating the proxy immediately here. 234 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 235 return nullptr; 236 } 237 } 238 return proxy; 239} 240 241sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy( 242 const GrSurfaceDesc& desc, SkBudgeted budgeted, 243 const GrMipLevel texels[], int mipLevelCount, 244 SkDestinationSurfaceColorMode mipColorMode) { 245 ASSERT_SINGLE_OWNER 246 247 if (this->isAbandoned()) { 248 return nullptr; 249 } 250 251 if (!mipLevelCount) { 252 if (texels) { 253 return nullptr; 254 } 255 return this->createProxy(desc, SkBackingFit::kExact, budgeted); 256 } 257 if (!texels) { 258 return nullptr; 259 } 260 261 if (1 == mipLevelCount) { 262 return this->createTextureProxy(desc, budgeted, texels[0].fPixels, texels[0].fRowBytes); 263 } 264 265#ifdef SK_DEBUG 266 // There are only three states we want to be in when uploading data to a mipped surface. 267 // 1) We have data to upload to all layers 268 // 2) We are not uploading data to any layers 269 // 3) We are only uploading data to the base layer 270 // We check here to make sure we do not have any other state. 271 bool firstLevelHasData = SkToBool(texels[0].fPixels); 272 bool allOtherLevelsHaveData = true, allOtherLevelsLackData = true; 273 for (int i = 1; i < mipLevelCount; ++i) { 274 if (texels[i].fPixels) { 275 allOtherLevelsLackData = false; 276 } else { 277 allOtherLevelsHaveData = false; 278 } 279 } 280 SkASSERT((firstLevelHasData && allOtherLevelsHaveData) || allOtherLevelsLackData); 281#endif 282 283 sk_sp<GrTexture> tex(fResourceProvider->createTexture(desc, budgeted, 284 texels, mipLevelCount, 285 mipColorMode)); 286 if (!tex) { 287 return nullptr; 288 } 289 290 return this->createWrapped(std::move(tex), desc.fOrigin); 291} 292 293sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrSurfaceDesc& desc, 294 SkBudgeted budgeted) { 295 // SkMipMap doesn't include the base level in the level count so we have to add 1 296 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1; 297 298 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]); 299 300 // We don't want to upload any texel data 301 for (int i = 0; i < mipCount; i++) { 302 texels[i].fPixels = nullptr; 303 texels[i].fRowBytes = 0; 304 } 305 306 return this->createMipMapProxy(desc, budgeted, texels.get(), mipCount, 307 SkDestinationSurfaceColorMode::kLegacy); 308} 309 310sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc, 311 SkBackingFit fit, 312 SkBudgeted budgeted, 313 uint32_t flags) { 314 SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags); 315 316 const GrCaps* caps = this->caps(); 317 318 // TODO: move this logic into GrResourceProvider! 319 // TODO: share this testing code with check_texture_creation_params 320 if (!caps->isConfigTexturable(desc.fConfig)) { 321 return nullptr; 322 } 323 324 bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); 325 if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 1)) { 326 return nullptr; 327 } 328 329 // We currently do not support multisampled textures 330 if (!willBeRT && desc.fSampleCnt > 1) { 331 return nullptr; 332 } 333 334 if (willBeRT && !caps->getSampleCount(desc.fSampleCnt, desc.fConfig)) { 335 return nullptr; 336 } 337 338 int maxSize; 339 if (willBeRT) { 340 maxSize = caps->maxRenderTargetSize(); 341 } else { 342 maxSize = caps->maxTextureSize(); 343 } 344 345 if (desc.fWidth > maxSize || desc.fHeight > maxSize || desc.fWidth <= 0 || desc.fHeight <= 0) { 346 return nullptr; 347 } 348 349 GrSurfaceDesc copyDesc = desc; 350 copyDesc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig); 351 352#ifdef SK_DISABLE_DEFERRED_PROXIES 353 // Temporarily force instantiation for crbug.com/769760 and crbug.com/769898 354 sk_sp<GrTexture> tex; 355 356 if (SkBackingFit::kApprox == fit) { 357 tex = resourceProvider->createApproxTexture(copyDesc, flags); 358 } else { 359 tex = resourceProvider->createTexture(copyDesc, budgeted, flags); 360 } 361 362 if (!tex) { 363 return nullptr; 364 } 365 366 return GrSurfaceProxy::MakeWrapped(std::move(tex), copyDesc.fOrigin); 367#else 368 if (willBeRT) { 369 // We know anything we instantiate later from this deferred path will be 370 // both texturable and renderable 371 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit, 372 budgeted, flags)); 373 } 374 375 return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags)); 376#endif 377} 378 379sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy( 380 const GrBackendTexture& backendTex, 381 GrSurfaceOrigin origin, 382 GrWrapOwnership ownership, 383 ReleaseProc releaseProc, 384 ReleaseContext releaseCtx) { 385 if (this->isAbandoned()) { 386 return nullptr; 387 } 388 389 GrSurfaceDesc desc; 390 desc.fOrigin = origin; 391 desc.fWidth = backendTex.width(); 392 desc.fHeight = backendTex.height(); 393 desc.fConfig = backendTex.config(); 394 GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo; 395 396 sk_sp<GrReleaseProcHelper> releaseHelper; 397 if (releaseProc) { 398 releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx)); 399 } 400 401 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 402 [backendTex, ownership, releaseHelper] 403 (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) { 404 if (!resourceProvider) { 405 // If this had a releaseHelper it will get unrefed when we delete this lambda 406 // and will call the release proc so that the client knows they can free the 407 // underlying backend object. 408 return sk_sp<GrTexture>(); 409 } 410 411 sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex, 412 ownership); 413 if (!tex) { 414 return sk_sp<GrTexture>(); 415 } 416 if (releaseHelper) { 417 // This gives the texture a ref on the releaseHelper 418 tex->setRelease(releaseHelper); 419 } 420 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture 421 // Make sure we match how we created the proxy with SkBudgeted::kNo 422 SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted()); 423 424 return tex; 425 }, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo); 426 427 if (fResourceProvider) { 428 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however, 429 // we're better off instantiating the proxy immediately here. 430 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 431 return nullptr; 432 } 433 } 434 return proxy; 435} 436 437sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& tex, 438 GrSurfaceOrigin origin, 439 int sampleCnt) { 440 if (this->isAbandoned()) { 441 return nullptr; 442 } 443 444 sk_sp<GrTexture> texture(fResourceProvider->wrapRenderableBackendTexture(tex, sampleCnt)); 445 if (!texture) { 446 return nullptr; 447 } 448 SkASSERT(texture->asRenderTarget()); // A GrTextureRenderTarget 449 450 return this->createWrapped(std::move(texture), origin); 451} 452 453sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy( 454 const GrBackendRenderTarget& backendRT, 455 GrSurfaceOrigin origin) { 456 if (this->isAbandoned()) { 457 return nullptr; 458 } 459 460 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendRenderTarget(backendRT)); 461 if (!rt) { 462 return nullptr; 463 } 464 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget 465 SkASSERT(!rt->getUniqueKey().isValid()); 466 467 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin)); 468} 469 470sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(const GrBackendTexture& tex, 471 GrSurfaceOrigin origin, 472 int sampleCnt) { 473 if (this->isAbandoned()) { 474 return nullptr; 475 } 476 477 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendTextureAsRenderTarget(tex, sampleCnt)); 478 if (!rt) { 479 return nullptr; 480 } 481 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget 482 SkASSERT(!rt->getUniqueKey().isValid()); 483 484 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin)); 485} 486 487sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, 488 const GrSurfaceDesc& desc, 489 GrMipMapped mipMapped, 490 SkBackingFit fit, SkBudgeted budgeted) { 491 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || 492 (desc.fWidth > 0 && desc.fHeight > 0)); 493 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag; 494 return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ? 495 new GrTextureRenderTargetProxy(std::move(callback), desc, 496 mipMapped, fit, budgeted, flags) : 497 new GrTextureProxy(std::move(callback), desc, mipMapped, fit, 498 budgeted, flags)); 499} 500 501sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback, 502 Renderable renderable, 503 GrPixelConfig config) { 504 GrSurfaceDesc desc; 505 if (Renderable::kYes == renderable) { 506 desc.fFlags = kRenderTarget_GrSurfaceFlag; 507 } 508 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 509 desc.fWidth = -1; 510 desc.fHeight = -1; 511 desc.fConfig = config; 512 desc.fSampleCnt = 1; 513 514 return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo, 515 SkBackingFit::kApprox, SkBudgeted::kYes); 516 517} 518 519bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) { 520 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())); 521} 522 523void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key) { 524 // Note: this method is called for the whole variety of GrGpuResources so often 'key' 525 // will not be in 'fUniquelyKeyedProxies'. 526 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key); 527 if (proxy) { 528 this->processInvalidProxyUniqueKey(key, proxy, false); 529 } 530} 531 532void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy, 533 bool invalidateSurface) { 534 SkASSERT(proxy); 535 SkASSERT(proxy->getUniqueKey().isValid()); 536 SkASSERT(proxy->getUniqueKey() == key); 537 538 fUniquelyKeyedProxies.remove(key); 539 proxy->cacheAccess().clearUniqueKey(); 540 541 if (invalidateSurface && proxy->priv().isInstantiated()) { 542 GrSurface* surface = proxy->priv().peekSurface(); 543 if (surface) { 544 surface->resourcePriv().removeUniqueKey(); 545 } 546 } 547} 548 549void GrProxyProvider::removeAllUniqueKeys() { 550 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); 551 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) { 552 GrTextureProxy& tmp = *iter; 553 554 this->processInvalidProxyUniqueKey(tmp.getUniqueKey(), &tmp, false); 555 } 556 SkASSERT(!fUniquelyKeyedProxies.count()); 557} 558