1 /* 2 * Copyright 2016 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 "GrSurfaceProxy.h" 9 #include "GrSurfaceProxyPriv.h" 10 11 #include "GrCaps.h" 12 #include "GrContext.h" 13 #include "GrContextPriv.h" 14 #include "GrGpuResourcePriv.h" 15 #include "GrOpList.h" 16 #include "GrProxyProvider.h" 17 #include "GrSurfaceContext.h" 18 #include "GrSurfacePriv.h" 19 #include "GrTexturePriv.h" 20 #include "GrTextureRenderTargetProxy.h" 21 22 #include "SkMathPriv.h" 23 #include "SkMipMap.h" 24 25 #ifdef SK_DEBUG 26 #include "GrRenderTarget.h" 27 #include "GrRenderTargetPriv.h" 28 29 static bool is_valid_fully_lazy(const GrSurfaceDesc& desc, SkBackingFit fit) { 30 return desc.fWidth <= 0 && 31 desc.fHeight <= 0 && 32 desc.fConfig != kUnknown_GrPixelConfig && 33 desc.fSampleCnt == 1 && 34 SkBackingFit::kApprox == fit; 35 } 36 37 static bool is_valid_partially_lazy(const GrSurfaceDesc& desc) { 38 return ((desc.fWidth > 0 && desc.fHeight > 0) || 39 (desc.fWidth <= 0 && desc.fHeight <= 0)) && 40 desc.fConfig != kUnknown_GrPixelConfig; 41 } 42 43 static bool is_valid_non_lazy(const GrSurfaceDesc& desc) { 44 return desc.fWidth > 0 && 45 desc.fHeight > 0 && 46 desc.fConfig != kUnknown_GrPixelConfig; 47 } 48 #endif 49 50 // Lazy-callback version 51 GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, LazyInstantiationType lazyType, 52 const GrBackendFormat& format, const GrSurfaceDesc& desc, 53 GrSurfaceOrigin origin, SkBackingFit fit, 54 SkBudgeted budgeted, GrInternalSurfaceFlags surfaceFlags) 55 : fSurfaceFlags(surfaceFlags) 56 , fFormat(format) 57 , fConfig(desc.fConfig) 58 , fWidth(desc.fWidth) 59 , fHeight(desc.fHeight) 60 , fOrigin(origin) 61 , fFit(fit) 62 , fBudgeted(budgeted) 63 , fLazyInstantiateCallback(std::move(callback)) 64 , fLazyInstantiationType(lazyType) 65 , fNeedsClear(SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) 66 , fGpuMemorySize(kInvalidGpuMemorySize) 67 , fLastOpList(nullptr) { 68 SkASSERT(fFormat.isValid()); 69 // NOTE: the default fUniqueID ctor pulls a value from the same pool as the GrGpuResources. 70 if (fLazyInstantiateCallback) { 71 SkASSERT(is_valid_fully_lazy(desc, fit) || is_valid_partially_lazy(desc)); 72 } else { 73 SkASSERT(is_valid_non_lazy(desc)); 74 } 75 76 if (GrPixelConfigIsCompressed(desc.fConfig)) { 77 SkASSERT(!SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag)); 78 fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly; 79 } 80 } 81 82 // Wrapped version 83 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin, SkBackingFit fit) 84 : INHERITED(std::move(surface)) 85 , fSurfaceFlags(fTarget->surfacePriv().flags()) 86 , fFormat(fTarget->backendFormat()) 87 , fConfig(fTarget->config()) 88 , fWidth(fTarget->width()) 89 , fHeight(fTarget->height()) 90 , fOrigin(origin) 91 , fFit(fit) 92 , fBudgeted(fTarget->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted 93 ? SkBudgeted::kYes 94 : SkBudgeted::kNo) 95 , fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID! 96 , fNeedsClear(false) 97 , fGpuMemorySize(kInvalidGpuMemorySize) 98 , fLastOpList(nullptr) { 99 SkASSERT(fFormat.isValid()); 100 } 101 102 GrSurfaceProxy::~GrSurfaceProxy() { 103 if (fLazyInstantiateCallback) { 104 // We call the callback with a null GrResourceProvider to signal that the lambda should 105 // clean itself up if it is holding onto any captured objects. 106 this->fLazyInstantiateCallback(nullptr); 107 } 108 // For this to be deleted the opList that held a ref on it (if there was one) must have been 109 // deleted. Which would have cleared out this back pointer. 110 SkASSERT(!fLastOpList); 111 } 112 113 bool GrSurfaceProxyPriv::AttachStencilIfNeeded(GrResourceProvider* resourceProvider, 114 GrSurface* surface, bool needsStencil) { 115 if (needsStencil) { 116 GrRenderTarget* rt = surface->asRenderTarget(); 117 if (!rt) { 118 SkASSERT(0); 119 return false; 120 } 121 122 if (!resourceProvider->attachStencilAttachment(rt)) { 123 return false; 124 } 125 } 126 127 return true; 128 } 129 130 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider, 131 int sampleCnt, bool needsStencil, 132 GrSurfaceDescFlags descFlags, 133 GrMipMapped mipMapped) const { 134 SkASSERT(GrSurfaceProxy::LazyState::kNot == this->lazyInstantiationState()); 135 SkASSERT(!fTarget); 136 GrSurfaceDesc desc; 137 desc.fFlags = descFlags; 138 if (fNeedsClear) { 139 desc.fFlags |= kPerformInitialClear_GrSurfaceFlag; 140 } 141 desc.fWidth = fWidth; 142 desc.fHeight = fHeight; 143 desc.fConfig = fConfig; 144 desc.fSampleCnt = sampleCnt; 145 146 GrResourceProvider::Flags resourceProviderFlags = GrResourceProvider::Flags::kNone; 147 if ((fSurfaceFlags & GrInternalSurfaceFlags::kNoPendingIO) || 148 resourceProvider->explicitlyAllocateGPUResources()) { 149 // The explicit resource allocator requires that any resources it pulls out of the 150 // cache have no pending IO. 151 resourceProviderFlags = GrResourceProvider::Flags::kNoPendingIO; 152 } 153 154 sk_sp<GrSurface> surface; 155 if (GrMipMapped::kYes == mipMapped) { 156 SkASSERT(SkBackingFit::kExact == fFit); 157 158 // SkMipMap doesn't include the base level in the level count so we have to add 1 159 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1; 160 // We should have caught the case where mipCount == 1 when making the proxy and instead 161 // created a non-mipmapped proxy. 162 SkASSERT(mipCount > 1); 163 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]); 164 165 // We don't want to upload any texel data 166 for (int i = 0; i < mipCount; i++) { 167 texels[i].fPixels = nullptr; 168 texels[i].fRowBytes = 0; 169 } 170 171 surface = resourceProvider->createTexture(desc, fBudgeted, texels.get(), mipCount); 172 if (surface) { 173 SkASSERT(surface->asTexture()); 174 SkASSERT(GrMipMapped::kYes == surface->asTexture()->texturePriv().mipMapped()); 175 } 176 } else { 177 if (SkBackingFit::kApprox == fFit) { 178 surface = resourceProvider->createApproxTexture(desc, resourceProviderFlags); 179 } else { 180 surface = resourceProvider->createTexture(desc, fBudgeted, resourceProviderFlags); 181 } 182 } 183 if (!surface) { 184 return nullptr; 185 } 186 187 if (!GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, surface.get(), needsStencil)) { 188 return nullptr; 189 } 190 191 return surface; 192 } 193 194 bool GrSurfaceProxy::canSkipResourceAllocator() const { 195 auto peek = this->peekSurface(); 196 if (!peek) { 197 return false; 198 } 199 // If this resource is already allocated and not recyclable then the resource allocator does 200 // not need to do anything with it. 201 return !peek->resourcePriv().getScratchKey().isValid(); 202 } 203 204 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) { 205 SkASSERT(!fTarget && surface); 206 207 SkDEBUGCODE(this->validateSurface(surface.get());) 208 209 fTarget = surface.release(); 210 211 this->INHERITED::transferRefs(); 212 213 #ifdef SK_DEBUG 214 if (this->asRenderTargetProxy()) { 215 SkASSERT(fTarget->asRenderTarget()); 216 if (this->asRenderTargetProxy()->needsStencil()) { 217 SkASSERT(fTarget->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 218 } 219 } 220 221 if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) { 222 SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly()); 223 } 224 #endif 225 } 226 227 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, 228 bool needsStencil, GrSurfaceDescFlags descFlags, 229 GrMipMapped mipMapped, const GrUniqueKey* uniqueKey) { 230 SkASSERT(LazyState::kNot == this->lazyInstantiationState()); 231 if (fTarget) { 232 if (uniqueKey && uniqueKey->isValid()) { 233 SkASSERT(fTarget->getUniqueKey().isValid() && fTarget->getUniqueKey() == *uniqueKey); 234 } 235 return GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, fTarget, needsStencil); 236 } 237 238 sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, needsStencil, 239 descFlags, mipMapped); 240 if (!surface) { 241 return false; 242 } 243 244 // If there was an invalidation message pending for this key, we might have just processed it, 245 // causing the key (stored on this proxy) to become invalid. 246 if (uniqueKey && uniqueKey->isValid()) { 247 resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get()); 248 } 249 250 this->assign(std::move(surface)); 251 252 return true; 253 } 254 255 void GrSurfaceProxy::deinstantiate() { 256 SkASSERT(this->isInstantiated()); 257 258 this->release(); 259 } 260 261 void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const { 262 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 263 const GrRenderTargetProxy* rtp = this->asRenderTargetProxy(); 264 int sampleCount = 1; 265 if (rtp) { 266 sampleCount = rtp->numStencilSamples(); 267 } 268 269 const GrTextureProxy* tp = this->asTextureProxy(); 270 GrMipMapped mipMapped = GrMipMapped::kNo; 271 if (tp) { 272 mipMapped = tp->mipMapped(); 273 } 274 275 int width = this->worstCaseWidth(); 276 int height = this->worstCaseHeight(); 277 278 GrTexturePriv::ComputeScratchKey(this->config(), width, height, SkToBool(rtp), sampleCount, 279 mipMapped, key); 280 } 281 282 void GrSurfaceProxy::setLastOpList(GrOpList* opList) { 283 #ifdef SK_DEBUG 284 if (fLastOpList) { 285 SkASSERT(fLastOpList->isClosed()); 286 } 287 #endif 288 289 // Un-reffed 290 fLastOpList = opList; 291 } 292 293 GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() { 294 return fLastOpList ? fLastOpList->asRenderTargetOpList() : nullptr; 295 } 296 297 GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() { 298 return fLastOpList ? fLastOpList->asTextureOpList() : nullptr; 299 } 300 301 int GrSurfaceProxy::worstCaseWidth() const { 302 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 303 if (fTarget) { 304 return fTarget->width(); 305 } 306 307 if (SkBackingFit::kExact == fFit) { 308 return fWidth; 309 } 310 return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fWidth)); 311 } 312 313 int GrSurfaceProxy::worstCaseHeight() const { 314 SkASSERT(LazyState::kFully != this->lazyInstantiationState()); 315 if (fTarget) { 316 return fTarget->height(); 317 } 318 319 if (SkBackingFit::kExact == fFit) { 320 return fHeight; 321 } 322 return SkTMax(GrResourceProvider::kMinScratchTextureSize, GrNextPow2(fHeight)); 323 } 324 325 #ifdef SK_DEBUG 326 void GrSurfaceProxy::validate(GrContext* context) const { 327 if (fTarget) { 328 SkASSERT(fTarget->getContext() == context); 329 } 330 331 INHERITED::validate(); 332 } 333 #endif 334 335 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, 336 GrSurfaceProxy* src, 337 GrMipMapped mipMapped, 338 SkIRect srcRect, 339 SkBackingFit fit, 340 SkBudgeted budgeted) { 341 SkASSERT(LazyState::kFully != src->lazyInstantiationState()); 342 if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) { 343 return nullptr; 344 } 345 346 GrSurfaceDesc dstDesc; 347 dstDesc.fWidth = srcRect.width(); 348 dstDesc.fHeight = srcRect.height(); 349 dstDesc.fConfig = src->config(); 350 351 GrBackendFormat format = src->backendFormat().makeTexture2D(); 352 if (!format.isValid()) { 353 return nullptr; 354 } 355 356 sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext( 357 format, dstDesc, src->origin(), mipMapped, fit, budgeted)); 358 if (!dstContext) { 359 return nullptr; 360 } 361 362 if (!dstContext->copy(src, srcRect, SkIPoint::Make(0, 0))) { 363 return nullptr; 364 } 365 366 return dstContext->asTextureProxyRef(); 367 } 368 369 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src, 370 GrMipMapped mipMapped, SkBackingFit fit, 371 SkBudgeted budgeted) { 372 SkASSERT(LazyState::kFully != src->lazyInstantiationState()); 373 return Copy(context, src, mipMapped, SkIRect::MakeWH(src->width(), src->height()), fit, 374 budgeted); 375 } 376 377 sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc, 378 GrSurfaceOrigin origin, GrSurfaceProxy* srcProxy) { 379 SkASSERT(LazyState::kFully != srcProxy->lazyInstantiationState()); 380 381 GrBackendFormat format = srcProxy->backendFormat().makeTexture2D(); 382 if (!format.isValid()) { 383 return nullptr; 384 } 385 386 sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext( 387 format, dstDesc, origin, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kYes)); 388 if (!dstContext) { 389 return nullptr; 390 } 391 392 if (!dstContext->copy(srcProxy)) { 393 return nullptr; 394 } 395 396 return dstContext; 397 } 398 399 void GrSurfaceProxyPriv::exactify() { 400 SkASSERT(GrSurfaceProxy::LazyState::kFully != fProxy->lazyInstantiationState()); 401 if (this->isExact()) { 402 return; 403 } 404 405 SkASSERT(SkBackingFit::kApprox == fProxy->fFit); 406 407 if (fProxy->fTarget) { 408 // The kApprox but already instantiated case. Setting the proxy's width & height to 409 // the instantiated width & height could have side-effects going forward, since we're 410 // obliterating the area of interest information. This call (exactify) only used 411 // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be 412 // used for additional draws. 413 fProxy->fWidth = fProxy->fTarget->width(); 414 fProxy->fHeight = fProxy->fTarget->height(); 415 return; 416 } 417 418 // The kApprox uninstantiated case. Making this proxy be exact should be okay. 419 // It could mess things up if prior decisions were based on the approximate size. 420 fProxy->fFit = SkBackingFit::kExact; 421 // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has 422 // already been computed we want to leave it alone so that amount will be removed when 423 // the special image goes away. If it hasn't been computed yet it might as well compute the 424 // exact amount. 425 } 426 427 bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) { 428 SkASSERT(GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()); 429 430 sk_sp<GrSurface> surface; 431 if (fProxy->asTextureProxy() && fProxy->asTextureProxy()->getUniqueKey().isValid()) { 432 // First try to reattach to a cached version if the proxy is uniquely keyed 433 surface = resourceProvider->findByUniqueKey<GrSurface>( 434 fProxy->asTextureProxy()->getUniqueKey()); 435 } 436 437 if (!surface) { 438 surface = fProxy->fLazyInstantiateCallback(resourceProvider); 439 } 440 if (GrSurfaceProxy::LazyInstantiationType::kSingleUse == fProxy->fLazyInstantiationType) { 441 fProxy->fLazyInstantiateCallback(nullptr); 442 fProxy->fLazyInstantiateCallback = nullptr; 443 } 444 if (!surface) { 445 fProxy->fWidth = 0; 446 fProxy->fHeight = 0; 447 return false; 448 } 449 450 if (fProxy->fWidth <= 0 || fProxy->fHeight <= 0) { 451 // This was a fully lazy proxy. We need to fill in the width & height. For partially 452 // lazy proxies we must preserve the original width & height since that indicates 453 // the content area. 454 SkASSERT(fProxy->fWidth <= 0 && fProxy->fHeight <= 0); 455 fProxy->fWidth = surface->width(); 456 fProxy->fHeight = surface->height(); 457 } 458 459 bool needsStencil = fProxy->asRenderTargetProxy() 460 ? fProxy->asRenderTargetProxy()->needsStencil() 461 : false; 462 463 if (!GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, surface.get(), needsStencil)) { 464 return false; 465 } 466 467 if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) { 468 const GrUniqueKey& key = texProxy->getUniqueKey(); 469 if (key.isValid()) { 470 if (!surface->asTexture()->getUniqueKey().isValid()) { 471 // If 'surface' is newly created, attach the unique key 472 resourceProvider->assignUniqueKeyToResource(key, surface.get()); 473 } else { 474 // otherwise we had better have reattached to a cached version 475 SkASSERT(surface->asTexture()->getUniqueKey() == key); 476 } 477 } 478 } 479 480 this->assign(std::move(surface)); 481 return true; 482 } 483 484 #ifdef SK_DEBUG 485 void GrSurfaceProxy::validateSurface(const GrSurface* surface) { 486 SkASSERT(surface->config() == fConfig); 487 488 // Assert the flags are the same except for kNoPendingIO which is not passed onto the GrSurface. 489 GrInternalSurfaceFlags proxyFlags = fSurfaceFlags & ~GrInternalSurfaceFlags::kNoPendingIO; 490 GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags(); 491 SkASSERT((proxyFlags & GrInternalSurfaceFlags::kSurfaceMask) == 492 (surfaceFlags & GrInternalSurfaceFlags::kSurfaceMask)); 493 this->onValidateSurface(surface); 494 } 495 #endif 496