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 ASSERT_SINGLE_OWNER 67 68 SkASSERT(mipLevelCount > 0); 69 70 if (this->isAbandoned()) { 71 return nullptr; 72 } 73 74 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; 75 if (!fCaps->validateSurfaceDesc(desc, mipMapped)) { 76 return nullptr; 77 } 78 79 return fGpu->createTexture(desc, budgeted, texels, mipLevelCount); 80 } 81 82 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc, 83 SkBudgeted budgeted, Flags flags) { 84 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags)); 85 if (tex && SkBudgeted::kNo == budgeted) { 86 tex->resourcePriv().makeUnbudgeted(); 87 } 88 89 return tex; 90 } 91 92 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, 93 SkBudgeted budgeted, 94 SkBackingFit fit, 95 const GrMipLevel& mipLevel, 96 Flags flags) { 97 ASSERT_SINGLE_OWNER 98 99 if (this->isAbandoned()) { 100 return nullptr; 101 } 102 103 if (!mipLevel.fPixels) { 104 return nullptr; 105 } 106 107 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 108 return nullptr; 109 } 110 111 GrContext* context = fGpu->getContext(); 112 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 113 114 SkColorType colorType; 115 if (GrPixelConfigToColorType(desc.fConfig, &colorType)) { 116 sk_sp<GrTexture> tex = (SkBackingFit::kApprox == fit) 117 ? this->createApproxTexture(desc, flags) 118 : this->createTexture(desc, budgeted, flags); 119 if (!tex) { 120 return nullptr; 121 } 122 123 sk_sp<GrTextureProxy> proxy = proxyProvider->createWrapped(std::move(tex), 124 kTopLeft_GrSurfaceOrigin); 125 if (!proxy) { 126 return nullptr; 127 } 128 auto srcInfo = SkImageInfo::Make(desc.fWidth, desc.fHeight, colorType, 129 kUnknown_SkAlphaType); 130 sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext( 131 std::move(proxy)); 132 if (!sContext) { 133 return nullptr; 134 } 135 SkAssertResult(sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0)); 136 return sk_ref_sp(sContext->asTextureProxy()->peekTexture()); 137 } else { 138 return fGpu->createTexture(desc, budgeted, &mipLevel, 1); 139 } 140 } 141 142 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 143 Flags flags) { 144 ASSERT_SINGLE_OWNER 145 if (this->isAbandoned()) { 146 return nullptr; 147 } 148 149 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 150 return nullptr; 151 } 152 153 // Compressed textures are read-only so they don't support re-use for scratch. 154 if (!GrPixelConfigIsCompressed(desc.fConfig)) { 155 sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags); 156 if (tex) { 157 return tex; 158 } 159 } 160 161 return fGpu->createTexture(desc, budgeted); 162 } 163 164 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, 165 Flags flags) { 166 ASSERT_SINGLE_OWNER 167 SkASSERT(Flags::kNone == flags || Flags::kNoPendingIO == flags); 168 169 if (this->isAbandoned()) { 170 return nullptr; 171 } 172 173 // Currently we don't recycle compressed textures as scratch. 174 if (GrPixelConfigIsCompressed(desc.fConfig)) { 175 return nullptr; 176 } 177 178 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 179 return nullptr; 180 } 181 182 if (auto tex = this->refScratchTexture(desc, flags)) { 183 return tex; 184 } 185 186 SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc); 187 188 // bin by pow2 with a reasonable min 189 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) && 190 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) { 191 GrSurfaceDesc* wdesc = copyDesc.writable(); 192 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth)); 193 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight)); 194 } 195 196 if (auto tex = this->refScratchTexture(*copyDesc, flags)) { 197 return tex; 198 } 199 200 return fGpu->createTexture(*copyDesc, SkBudgeted::kYes); 201 } 202 203 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc, Flags flags) { 204 ASSERT_SINGLE_OWNER 205 SkASSERT(!this->isAbandoned()); 206 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); 207 SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)); 208 209 // We could make initial clears work with scratch textures but it is a rare case so we just opt 210 // to fall back to making a new texture. 211 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) && 212 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) { 213 214 GrScratchKey key; 215 GrTexturePriv::ComputeScratchKey(desc, &key); 216 auto scratchFlags = GrResourceCache::ScratchFlags::kNone; 217 if (Flags::kNoPendingIO & flags) { 218 scratchFlags |= GrResourceCache::ScratchFlags::kRequireNoPendingIO; 219 } else if (!(desc.fFlags & kRenderTarget_GrSurfaceFlag)) { 220 // If it is not a render target then it will most likely be populated by 221 // writePixels() which will trigger a flush if the texture has pending IO. 222 scratchFlags |= GrResourceCache::ScratchFlags::kPreferNoPendingIO; 223 } 224 GrGpuResource* resource = fCache->findAndRefScratchResource(key, 225 GrSurface::WorstCaseSize(desc), 226 scratchFlags); 227 if (resource) { 228 GrSurface* surface = static_cast<GrSurface*>(resource); 229 return sk_sp<GrTexture>(surface->asTexture()); 230 } 231 } 232 233 return nullptr; 234 } 235 236 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex, 237 GrWrapOwnership ownership, 238 GrWrapCacheable cacheable, 239 GrIOType ioType) { 240 ASSERT_SINGLE_OWNER 241 if (this->isAbandoned()) { 242 return nullptr; 243 } 244 return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType); 245 } 246 247 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex, 248 int sampleCnt, 249 GrWrapOwnership ownership, 250 GrWrapCacheable cacheable) { 251 ASSERT_SINGLE_OWNER 252 if (this->isAbandoned()) { 253 return nullptr; 254 } 255 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable); 256 } 257 258 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget( 259 const GrBackendRenderTarget& backendRT) 260 { 261 ASSERT_SINGLE_OWNER 262 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT); 263 } 264 265 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget( 266 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) { 267 ASSERT_SINGLE_OWNER 268 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, 269 vkInfo); 270 271 } 272 273 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key, 274 GrGpuResource* resource) { 275 ASSERT_SINGLE_OWNER 276 if (this->isAbandoned() || !resource) { 277 return; 278 } 279 resource->resourcePriv().setUniqueKey(key); 280 } 281 282 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) { 283 ASSERT_SINGLE_OWNER 284 return this->isAbandoned() ? nullptr 285 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key)); 286 } 287 288 sk_sp<const GrBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrBufferType intendedType, 289 size_t size, 290 const void* data, 291 const GrUniqueKey& key) { 292 if (auto buffer = this->findByUniqueKey<GrBuffer>(key)) { 293 return std::move(buffer); 294 } 295 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, Flags::kNone, 296 data)) { 297 // We shouldn't bin and/or cache static buffers. 298 SkASSERT(buffer->sizeInBytes() == size); 299 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid()); 300 SkASSERT(!buffer->resourcePriv().hasPendingIO_debugOnly()); 301 buffer->resourcePriv().setUniqueKey(key); 302 return sk_sp<const GrBuffer>(buffer); 303 } 304 return nullptr; 305 } 306 307 sk_sp<const GrBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern, 308 int patternSize, 309 int reps, 310 int vertCount, 311 const GrUniqueKey& key) { 312 size_t bufferSize = patternSize * reps * sizeof(uint16_t); 313 314 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO. 315 sk_sp<GrBuffer> buffer(this->createBuffer(bufferSize, kIndex_GrBufferType, 316 kStatic_GrAccessPattern, Flags::kNone)); 317 if (!buffer) { 318 return nullptr; 319 } 320 uint16_t* data = (uint16_t*) buffer->map(); 321 SkAutoTArray<uint16_t> temp; 322 if (!data) { 323 temp.reset(reps * patternSize); 324 data = temp.get(); 325 } 326 for (int i = 0; i < reps; ++i) { 327 int baseIdx = i * patternSize; 328 uint16_t baseVert = (uint16_t)(i * vertCount); 329 for (int j = 0; j < patternSize; ++j) { 330 data[baseIdx+j] = baseVert + pattern[j]; 331 } 332 } 333 if (temp.get()) { 334 if (!buffer->updateData(data, bufferSize)) { 335 return nullptr; 336 } 337 } else { 338 buffer->unmap(); 339 } 340 this->assignUniqueKeyToResource(key, buffer.get()); 341 return std::move(buffer); 342 } 343 344 static constexpr int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1; 345 346 sk_sp<const GrBuffer> GrResourceProvider::createQuadIndexBuffer() { 347 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535); 348 static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 }; 349 return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey); 350 } 351 352 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; } 353 354 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) { 355 if (this->isAbandoned()) { 356 return nullptr; 357 } 358 359 SkASSERT(this->gpu()->pathRendering()); 360 return this->gpu()->pathRendering()->createPath(path, style); 361 } 362 363 sk_sp<GrBuffer> GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType, 364 GrAccessPattern accessPattern, Flags flags, 365 const void* data) { 366 if (this->isAbandoned()) { 367 return nullptr; 368 } 369 if (kDynamic_GrAccessPattern != accessPattern) { 370 return this->gpu()->createBuffer(size, intendedType, accessPattern, data); 371 } 372 if (!(flags & Flags::kRequireGpuMemory) && 373 this->gpu()->caps()->preferClientSideDynamicBuffers() && 374 GrBufferTypeIsVertexOrIndex(intendedType) && 375 kDynamic_GrAccessPattern == accessPattern) { 376 return GrBuffer::MakeCPUBacked(this->gpu(), size, intendedType, data); 377 } 378 379 // bin by pow2 with a reasonable min 380 static const size_t MIN_SIZE = 1 << 12; 381 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size)); 382 383 GrScratchKey key; 384 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key); 385 auto scratchFlags = GrResourceCache::ScratchFlags::kNone; 386 if (flags & Flags::kNoPendingIO) { 387 scratchFlags = GrResourceCache::ScratchFlags::kRequireNoPendingIO; 388 } else { 389 scratchFlags = GrResourceCache::ScratchFlags::kPreferNoPendingIO; 390 } 391 auto buffer = sk_sp<GrBuffer>(static_cast<GrBuffer*>( 392 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags))); 393 if (!buffer) { 394 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern); 395 if (!buffer) { 396 return nullptr; 397 } 398 } 399 if (data) { 400 buffer->updateData(data, size); 401 } 402 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs. 403 return buffer; 404 } 405 406 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) { 407 SkASSERT(rt); 408 if (rt->renderTargetPriv().getStencilAttachment()) { 409 return true; 410 } 411 412 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) { 413 GrUniqueKey sbKey; 414 415 int width = rt->width(); 416 int height = rt->height(); 417 #if 0 418 if (this->caps()->oversizedStencilSupport()) { 419 width = SkNextPow2(width); 420 height = SkNextPow2(height); 421 } 422 #endif 423 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, 424 rt->numStencilSamples(), &sbKey); 425 auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey); 426 if (!stencil) { 427 // Need to try and create a new stencil 428 stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height)); 429 if (!stencil) { 430 return false; 431 } 432 this->assignUniqueKeyToResource(sbKey, stencil.get()); 433 } 434 rt->renderTargetPriv().attachStencilAttachment(std::move(stencil)); 435 } 436 return SkToBool(rt->renderTargetPriv().getStencilAttachment()); 437 } 438 439 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget( 440 const GrBackendTexture& tex, int sampleCnt) 441 { 442 if (this->isAbandoned()) { 443 return nullptr; 444 } 445 return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt); 446 } 447 448 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) { 449 return fGpu->makeSemaphore(isOwned); 450 } 451 452 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, 453 SemaphoreWrapType wrapType, 454 GrWrapOwnership ownership) { 455 ASSERT_SINGLE_OWNER 456 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, 457 wrapType, 458 ownership); 459 } 460