1 /* 2 * Copyright 2015 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 "GrResourceProvider.h" 9 10 #include "GrBackendSemaphore.h" 11 #include "GrBuffer.h" 12 #include "GrCaps.h" 13 #include "GrContext.h" 14 #include "GrContextPriv.h" 15 #include "GrGpu.h" 16 #include "GrPath.h" 17 #include "GrPathRendering.h" 18 #include "GrProxyProvider.h" 19 #include "GrRenderTargetPriv.h" 20 #include "GrResourceCache.h" 21 #include "GrResourceKey.h" 22 #include "GrSemaphore.h" 23 #include "GrStencilAttachment.h" 24 #include "GrTexturePriv.h" 25 #include "../private/GrSingleOwner.h" 26 #include "SkGr.h" 27 #include "SkMathPriv.h" 28 29 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); 30 31 const uint32_t GrResourceProvider::kMinScratchTextureSize = 16; 32 33 #ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION 34 static const bool kDefaultExplicitlyAllocateGPUResources = false; 35 #else 36 static const bool kDefaultExplicitlyAllocateGPUResources = true; 37 #endif 38 39 #define ASSERT_SINGLE_OWNER \ 40 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) 41 42 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner, 43 GrContextOptions::Enable explicitlyAllocateGPUResources) 44 : fCache(cache) 45 , fGpu(gpu) 46 #ifdef SK_DEBUG 47 , fSingleOwner(owner) 48 #endif 49 { 50 if (GrContextOptions::Enable::kNo == explicitlyAllocateGPUResources) { 51 fExplicitlyAllocateGPUResources = false; 52 } else if (GrContextOptions::Enable::kYes == explicitlyAllocateGPUResources) { 53 fExplicitlyAllocateGPUResources = true; 54 } else { 55 fExplicitlyAllocateGPUResources = kDefaultExplicitlyAllocateGPUResources; 56 } 57 58 fCaps = sk_ref_sp(fGpu->caps()); 59 60 GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); 61 fQuadIndexBufferKey = gQuadIndexBufferKey; 62 } 63 64 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 65 const GrMipLevel texels[], int mipLevelCount, 66 SkDestinationSurfaceColorMode mipColorMode) { 67 ASSERT_SINGLE_OWNER 68 69 SkASSERT(mipLevelCount > 0); 70 71 if (this->isAbandoned()) { 72 return nullptr; 73 } 74 75 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; 76 if (!fCaps->validateSurfaceDesc(desc, mipMapped)) { 77 return nullptr; 78 } 79 80 sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texels, mipLevelCount)); 81 if (tex) { 82 tex->texturePriv().setMipColorMode(mipColorMode); 83 } 84 85 return tex; 86 } 87 88 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc, 89 SkBudgeted budgeted, uint32_t flags) { 90 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags)); 91 if (tex && SkBudgeted::kNo == budgeted) { 92 tex->resourcePriv().makeUnbudgeted(); 93 } 94 95 return tex; 96 } 97 98 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, 99 SkBudgeted budgeted, 100 SkBackingFit fit, 101 const GrMipLevel& mipLevel) { 102 ASSERT_SINGLE_OWNER 103 104 if (this->isAbandoned()) { 105 return nullptr; 106 } 107 108 if (!mipLevel.fPixels) { 109 return nullptr; 110 } 111 112 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 113 return nullptr; 114 } 115 116 GrContext* context = fGpu->getContext(); 117 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 118 119 SkColorType colorType; 120 if (GrPixelConfigToColorType(desc.fConfig, &colorType)) { 121 // DDL TODO: remove this use of createInstantiatedProxy and convert it to a testing-only 122 // method. 123 sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc, 124 fit, 125 budgeted); 126 if (!proxy) { 127 return nullptr; 128 } 129 // We use an ephemeral surface context to do the write pixels. Here it isn't clear what 130 // color space to tag it with. That's ok because GrSurfaceContext::writePixels doesn't 131 // do any color space conversions. Though, that is likely to change. However, if the 132 // pixel config is sRGB then the passed color space here must have sRGB gamma or 133 // GrSurfaceContext creation fails. 134 sk_sp<SkColorSpace> colorSpace; 135 if (GrPixelConfigIsSRGB(desc.fConfig)) { 136 colorSpace = SkColorSpace::MakeSRGB(); 137 } 138 auto srcInfo = SkImageInfo::Make(desc.fWidth, desc.fHeight, colorType, 139 kUnknown_SkAlphaType, colorSpace); 140 sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext( 141 std::move(proxy), std::move(colorSpace)); 142 if (!sContext) { 143 return nullptr; 144 } 145 SkAssertResult(sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0)); 146 return sk_ref_sp(sContext->asTextureProxy()->priv().peekTexture()); 147 } else { 148 return fGpu->createTexture(desc, budgeted, &mipLevel, 1); 149 } 150 } 151 152 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 153 uint32_t flags) { 154 ASSERT_SINGLE_OWNER 155 if (this->isAbandoned()) { 156 return nullptr; 157 } 158 159 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 160 return nullptr; 161 } 162 163 sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags); 164 if (tex) { 165 return tex; 166 } 167 168 return fGpu->createTexture(desc, budgeted); 169 } 170 171 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, 172 uint32_t flags) { 173 ASSERT_SINGLE_OWNER 174 SkASSERT(0 == flags || kNoPendingIO_Flag == flags); 175 176 if (this->isAbandoned()) { 177 return nullptr; 178 } 179 180 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 181 return nullptr; 182 } 183 184 if (auto tex = this->refScratchTexture(desc, flags)) { 185 return tex; 186 } 187 188 SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc); 189 190 // bin by pow2 with a reasonable min 191 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) && 192 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) { 193 GrSurfaceDesc* wdesc = copyDesc.writable(); 194 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth)); 195 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight)); 196 } 197 198 if (auto tex = this->refScratchTexture(*copyDesc, flags)) { 199 return tex; 200 } 201 202 return fGpu->createTexture(*copyDesc, SkBudgeted::kYes); 203 } 204 205 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc, 206 uint32_t flags) { 207 ASSERT_SINGLE_OWNER 208 SkASSERT(!this->isAbandoned()); 209 SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)); 210 211 // We could make initial clears work with scratch textures but it is a rare case so we just opt 212 // to fall back to making a new texture. 213 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) && 214 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) { 215 216 GrScratchKey key; 217 GrTexturePriv::ComputeScratchKey(desc, &key); 218 uint32_t scratchFlags = 0; 219 if (kNoPendingIO_Flag & flags) { 220 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; 221 } else if (!(desc.fFlags & kRenderTarget_GrSurfaceFlag)) { 222 // If it is not a render target then it will most likely be populated by 223 // writePixels() which will trigger a flush if the texture has pending IO. 224 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; 225 } 226 GrGpuResource* resource = fCache->findAndRefScratchResource(key, 227 GrSurface::WorstCaseSize(desc), 228 scratchFlags); 229 if (resource) { 230 GrSurface* surface = static_cast<GrSurface*>(resource); 231 return sk_sp<GrTexture>(surface->asTexture()); 232 } 233 } 234 235 return nullptr; 236 } 237 238 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex, 239 GrWrapOwnership ownership) { 240 ASSERT_SINGLE_OWNER 241 if (this->isAbandoned()) { 242 return nullptr; 243 } 244 return fGpu->wrapBackendTexture(tex, ownership); 245 } 246 247 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex, 248 int sampleCnt, 249 GrWrapOwnership ownership) { 250 ASSERT_SINGLE_OWNER 251 if (this->isAbandoned()) { 252 return nullptr; 253 } 254 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership); 255 } 256 257 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget( 258 const GrBackendRenderTarget& backendRT) 259 { 260 ASSERT_SINGLE_OWNER 261 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT); 262 } 263 264 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key, 265 GrGpuResource* resource) { 266 ASSERT_SINGLE_OWNER 267 if (this->isAbandoned() || !resource) { 268 return; 269 } 270 resource->resourcePriv().setUniqueKey(key); 271 } 272 273 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) { 274 ASSERT_SINGLE_OWNER 275 return this->isAbandoned() ? nullptr 276 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key)); 277 } 278 279 sk_sp<const GrBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrBufferType intendedType, 280 size_t size, 281 const void* data, 282 const GrUniqueKey& key) { 283 if (auto buffer = this->findByUniqueKey<GrBuffer>(key)) { 284 return buffer; 285 } 286 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, 0, 287 data)) { 288 // We shouldn't bin and/or cachestatic buffers. 289 SkASSERT(buffer->sizeInBytes() == size); 290 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid()); 291 SkASSERT(!buffer->resourcePriv().hasPendingIO_debugOnly()); 292 buffer->resourcePriv().setUniqueKey(key); 293 return sk_sp<const GrBuffer>(buffer); 294 } 295 return nullptr; 296 } 297 298 sk_sp<const GrBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern, 299 int patternSize, 300 int reps, 301 int vertCount, 302 const GrUniqueKey& key) { 303 size_t bufferSize = patternSize * reps * sizeof(uint16_t); 304 305 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO. 306 sk_sp<GrBuffer> buffer(this->createBuffer(bufferSize, kIndex_GrBufferType, 307 kStatic_GrAccessPattern, kNoPendingIO_Flag)); 308 if (!buffer) { 309 return nullptr; 310 } 311 uint16_t* data = (uint16_t*) buffer->map(); 312 SkAutoTArray<uint16_t> temp; 313 if (!data) { 314 temp.reset(reps * patternSize); 315 data = temp.get(); 316 } 317 for (int i = 0; i < reps; ++i) { 318 int baseIdx = i * patternSize; 319 uint16_t baseVert = (uint16_t)(i * vertCount); 320 for (int j = 0; j < patternSize; ++j) { 321 data[baseIdx+j] = baseVert + pattern[j]; 322 } 323 } 324 if (temp.get()) { 325 if (!buffer->updateData(data, bufferSize)) { 326 return nullptr; 327 } 328 } else { 329 buffer->unmap(); 330 } 331 this->assignUniqueKeyToResource(key, buffer.get()); 332 return std::move(buffer); 333 } 334 335 static constexpr int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1; 336 337 sk_sp<const GrBuffer> GrResourceProvider::createQuadIndexBuffer() { 338 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535); 339 static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 }; 340 return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey); 341 } 342 343 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; } 344 345 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) { 346 if (this->isAbandoned()) { 347 return nullptr; 348 } 349 350 SkASSERT(this->gpu()->pathRendering()); 351 return this->gpu()->pathRendering()->createPath(path, style); 352 } 353 354 sk_sp<GrPathRange> GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen, 355 const GrStyle& style) { 356 if (this->isAbandoned()) { 357 return nullptr; 358 } 359 360 SkASSERT(this->gpu()->pathRendering()); 361 return this->gpu()->pathRendering()->createPathRange(gen, style); 362 } 363 364 sk_sp<GrPathRange> GrResourceProvider::createGlyphs(const SkTypeface* tf, 365 const SkScalerContextEffects& effects, 366 const SkDescriptor* desc, 367 const GrStyle& style) { 368 369 SkASSERT(this->gpu()->pathRendering()); 370 return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style); 371 } 372 373 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType, 374 GrAccessPattern accessPattern, uint32_t flags, 375 const void* data) { 376 if (this->isAbandoned()) { 377 return nullptr; 378 } 379 if (kDynamic_GrAccessPattern != accessPattern) { 380 return this->gpu()->createBuffer(size, intendedType, accessPattern, data); 381 } 382 if (!(flags & kRequireGpuMemory_Flag) && 383 this->gpu()->caps()->preferClientSideDynamicBuffers() && 384 GrBufferTypeIsVertexOrIndex(intendedType) && 385 kDynamic_GrAccessPattern == accessPattern) { 386 return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data); 387 } 388 389 // bin by pow2 with a reasonable min 390 static const size_t MIN_SIZE = 1 << 12; 391 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size)); 392 393 GrScratchKey key; 394 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key); 395 uint32_t scratchFlags = 0; 396 if (flags & kNoPendingIO_Flag) { 397 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; 398 } else { 399 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; 400 } 401 GrBuffer* buffer = static_cast<GrBuffer*>( 402 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags)); 403 if (!buffer) { 404 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern); 405 if (!buffer) { 406 return nullptr; 407 } 408 } 409 if (data) { 410 buffer->updateData(data, size); 411 } 412 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs. 413 return buffer; 414 } 415 416 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) { 417 SkASSERT(rt); 418 if (rt->renderTargetPriv().getStencilAttachment()) { 419 return true; 420 } 421 422 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) { 423 GrUniqueKey sbKey; 424 425 int width = rt->width(); 426 int height = rt->height(); 427 #if 0 428 if (this->caps()->oversizedStencilSupport()) { 429 width = SkNextPow2(width); 430 height = SkNextPow2(height); 431 } 432 #endif 433 SkDEBUGCODE(bool newStencil = false;) 434 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, 435 rt->numStencilSamples(), &sbKey); 436 auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey); 437 if (!stencil) { 438 // Need to try and create a new stencil 439 stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height)); 440 if (stencil) { 441 this->assignUniqueKeyToResource(sbKey, stencil.get()); 442 SkDEBUGCODE(newStencil = true;) 443 } 444 } 445 if (rt->renderTargetPriv().attachStencilAttachment(std::move(stencil))) { 446 #ifdef SK_DEBUG 447 // Fill the SB with an inappropriate value. opLists that use the 448 // SB should clear it properly. 449 if (newStencil) { 450 SkASSERT(rt->renderTargetPriv().getStencilAttachment()->isDirty()); 451 this->gpu()->clearStencil(rt, 0xFFFF); 452 SkASSERT(rt->renderTargetPriv().getStencilAttachment()->isDirty()); 453 } 454 #endif 455 } 456 } 457 return SkToBool(rt->renderTargetPriv().getStencilAttachment()); 458 } 459 460 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget( 461 const GrBackendTexture& tex, int sampleCnt) 462 { 463 if (this->isAbandoned()) { 464 return nullptr; 465 } 466 return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt); 467 } 468 469 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) { 470 return fGpu->makeSemaphore(isOwned); 471 } 472 473 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, 474 SemaphoreWrapType wrapType, 475 GrWrapOwnership ownership) { 476 ASSERT_SINGLE_OWNER 477 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, 478 wrapType, 479 ownership); 480 } 481 482 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) { 483 semaphore->resetGpu(fGpu); 484 } 485 486 void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) { 487 semaphore->resetGpu(nullptr); 488 } 489