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 "GrRenderTarget.h" 19 #include "GrRenderTargetPriv.h" 20 #include "GrResourceCache.h" 21 #include "GrResourceKey.h" 22 #include "GrSemaphore.h" 23 #include "GrStencilAttachment.h" 24 #include "GrSurfaceProxyPriv.h" 25 #include "GrTexturePriv.h" 26 #include "../private/GrSingleOwner.h" 27 #include "SkGr.h" 28 #include "SkMathPriv.h" 29 30 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); 31 32 const uint32_t GrResourceProvider::kMinScratchTextureSize = 16; 33 34 #define ASSERT_SINGLE_OWNER \ 35 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) 36 37 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner) 38 : fCache(cache) 39 , fGpu(gpu) 40 #ifdef SK_DEBUG 41 , fSingleOwner(owner) 42 #endif 43 { 44 fCaps = sk_ref_sp(fGpu->caps()); 45 46 GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); 47 fQuadIndexBufferKey = gQuadIndexBufferKey; 48 } 49 50 bool GrResourceProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) { 51 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())); 52 } 53 54 bool validate_desc(const GrSurfaceDesc& desc, const GrCaps& caps, int levelCount = 0) { 55 if (desc.fWidth <= 0 || desc.fHeight <= 0) { 56 return false; 57 } 58 if (!caps.isConfigTexturable(desc.fConfig)) { 59 return false; 60 } 61 if (desc.fFlags & kRenderTarget_GrSurfaceFlag) { 62 if (!caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 63 return false; 64 } 65 } else { 66 if (desc.fSampleCnt) { 67 return false; 68 } 69 } 70 if (levelCount > 1 && (GrPixelConfigIsSint(desc.fConfig) || !caps.mipMapSupport())) { 71 return false; 72 } 73 return true; 74 } 75 76 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 77 const GrMipLevel texels[], int mipLevelCount, 78 SkDestinationSurfaceColorMode mipColorMode) { 79 ASSERT_SINGLE_OWNER 80 81 SkASSERT(mipLevelCount >= 1); 82 83 if (this->isAbandoned()) { 84 return nullptr; 85 } 86 87 if (!validate_desc(desc, *fCaps, mipLevelCount)) { 88 return nullptr; 89 } 90 91 sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texels, mipLevelCount)); 92 if (tex) { 93 tex->texturePriv().setMipColorMode(mipColorMode); 94 } 95 96 return tex; 97 } 98 99 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc, 100 SkBudgeted budgeted, uint32_t flags) { 101 flags |= kExact_Flag | kNoCreate_Flag; 102 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags)); 103 if (tex && SkBudgeted::kNo == budgeted) { 104 tex->resourcePriv().makeUnbudgeted(); 105 } 106 107 return tex; 108 } 109 110 static bool make_info(int w, int h, GrPixelConfig config, SkImageInfo* ii) { 111 SkColorType colorType; 112 if (!GrPixelConfigToColorType(config, &colorType)) { 113 return false; 114 } 115 116 *ii = SkImageInfo::Make(w, h, colorType, kUnknown_SkAlphaType, nullptr); 117 return true; 118 } 119 120 sk_sp<GrTextureProxy> GrResourceProvider::createTextureProxy(const GrSurfaceDesc& desc, 121 SkBudgeted budgeted, 122 const GrMipLevel& mipLevel) { 123 ASSERT_SINGLE_OWNER 124 125 if (this->isAbandoned()) { 126 return nullptr; 127 } 128 129 if (!mipLevel.fPixels) { 130 return nullptr; 131 } 132 133 if (!validate_desc(desc, *fCaps)) { 134 return nullptr; 135 } 136 137 GrContext* context = fGpu->getContext(); 138 139 SkImageInfo srcInfo; 140 141 if (make_info(desc.fWidth, desc.fHeight, desc.fConfig, &srcInfo)) { 142 sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, 0); 143 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeWrapped(std::move(tex)); 144 if (proxy) { 145 sk_sp<GrSurfaceContext> sContext = 146 context->contextPriv().makeWrappedSurfaceContext(std::move(proxy), nullptr); 147 if (sContext) { 148 if (sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0)) { 149 return sContext->asTextureProxyRef(); 150 } 151 } 152 } 153 } 154 155 sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, &mipLevel, 1)); 156 return GrSurfaceProxy::MakeWrapped(std::move(tex)); 157 } 158 159 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 160 uint32_t flags) { 161 ASSERT_SINGLE_OWNER 162 163 if (this->isAbandoned()) { 164 return nullptr; 165 } 166 167 if (!validate_desc(desc, *fCaps)) { 168 return nullptr; 169 } 170 171 sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags); 172 if (tex) { 173 return tex; 174 } 175 176 return fGpu->createTexture(desc, budgeted); 177 } 178 179 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, 180 uint32_t flags) { 181 ASSERT_SINGLE_OWNER 182 SkASSERT(0 == flags || kNoPendingIO_Flag == flags); 183 184 if (this->isAbandoned()) { 185 return nullptr; 186 } 187 188 if (!validate_desc(desc, *fCaps)) { 189 return nullptr; 190 } 191 192 return this->refScratchTexture(desc, flags); 193 } 194 195 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc, 196 uint32_t flags) { 197 ASSERT_SINGLE_OWNER 198 SkASSERT(!this->isAbandoned()); 199 SkASSERT(validate_desc(inDesc, *fCaps)); 200 201 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc); 202 203 // We could make initial clears work with scratch textures but it is a rare case so we just opt 204 // to fall back to making a new texture. 205 if (!SkToBool(inDesc.fFlags & kPerformInitialClear_GrSurfaceFlag) && 206 (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag))) { 207 if (!(kExact_Flag & flags)) { 208 // bin by pow2 with a reasonable min 209 GrSurfaceDesc* wdesc = desc.writable(); 210 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth)); 211 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight)); 212 } 213 214 GrScratchKey key; 215 GrTexturePriv::ComputeScratchKey(*desc, &key); 216 uint32_t scratchFlags = 0; 217 if (kNoPendingIO_Flag & flags) { 218 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; 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::kPreferNoPendingIO_ScratchFlag; 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 if (!(kNoCreate_Flag & flags)) { 234 return fGpu->createTexture(*desc, SkBudgeted::kYes); 235 } 236 237 return nullptr; 238 } 239 240 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex, 241 GrSurfaceOrigin origin, 242 GrBackendTextureFlags flags, 243 int sampleCnt, 244 GrWrapOwnership ownership) { 245 ASSERT_SINGLE_OWNER 246 if (this->isAbandoned()) { 247 return nullptr; 248 } 249 return fGpu->wrapBackendTexture(tex, origin, flags, sampleCnt, ownership); 250 } 251 252 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget( 253 const GrBackendRenderTarget& backendRT, GrSurfaceOrigin origin) 254 { 255 ASSERT_SINGLE_OWNER 256 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT, origin); 257 } 258 259 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key, 260 GrGpuResource* resource) { 261 ASSERT_SINGLE_OWNER 262 if (this->isAbandoned() || !resource) { 263 return; 264 } 265 resource->resourcePriv().setUniqueKey(key); 266 } 267 268 GrGpuResource* GrResourceProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) { 269 ASSERT_SINGLE_OWNER 270 return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key); 271 } 272 273 GrTexture* GrResourceProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) { 274 ASSERT_SINGLE_OWNER 275 GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key); 276 if (resource) { 277 GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture(); 278 SkASSERT(texture); 279 return texture; 280 } 281 return NULL; 282 } 283 284 void GrResourceProvider::assignUniqueKeyToTexture(const GrUniqueKey& key, GrTexture* texture) { 285 SkASSERT(key.isValid()); 286 this->assignUniqueKeyToResource(key, texture); 287 } 288 289 // MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs 290 void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { 291 ASSERT_SINGLE_OWNER 292 SkASSERT(key.isValid()); 293 if (this->isAbandoned() || !proxy) { 294 return; 295 } 296 297 if (!proxy->instantiate(this)) { 298 return; 299 } 300 GrTexture* texture = proxy->priv().peekTexture(); 301 302 this->assignUniqueKeyToResource(key, texture); 303 } 304 305 // MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs 306 sk_sp<GrTextureProxy> GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key) { 307 ASSERT_SINGLE_OWNER 308 309 sk_sp<GrTexture> texture(this->findAndRefTextureByUniqueKey(key)); 310 if (!texture) { 311 return nullptr; 312 } 313 314 return GrSurfaceProxy::MakeWrapped(std::move(texture)); 315 } 316 317 const GrBuffer* GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern, 318 int patternSize, 319 int reps, 320 int vertCount, 321 const GrUniqueKey& key) { 322 size_t bufferSize = patternSize * reps * sizeof(uint16_t); 323 324 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO. 325 GrBuffer* buffer = this->createBuffer(bufferSize, kIndex_GrBufferType, kStatic_GrAccessPattern, 326 kNoPendingIO_Flag); 327 if (!buffer) { 328 return nullptr; 329 } 330 uint16_t* data = (uint16_t*) buffer->map(); 331 bool useTempData = (nullptr == data); 332 if (useTempData) { 333 data = new uint16_t[reps * patternSize]; 334 } 335 for (int i = 0; i < reps; ++i) { 336 int baseIdx = i * patternSize; 337 uint16_t baseVert = (uint16_t)(i * vertCount); 338 for (int j = 0; j < patternSize; ++j) { 339 data[baseIdx+j] = baseVert + pattern[j]; 340 } 341 } 342 if (useTempData) { 343 if (!buffer->updateData(data, bufferSize)) { 344 buffer->unref(); 345 return nullptr; 346 } 347 delete[] data; 348 } else { 349 buffer->unmap(); 350 } 351 this->assignUniqueKeyToResource(key, buffer); 352 return buffer; 353 } 354 355 const GrBuffer* GrResourceProvider::createQuadIndexBuffer() { 356 static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1; 357 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535); 358 static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 }; 359 360 return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey); 361 } 362 363 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) { 364 SkASSERT(this->gpu()->pathRendering()); 365 return this->gpu()->pathRendering()->createPath(path, style); 366 } 367 368 sk_sp<GrPathRange> GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen, 369 const GrStyle& style) { 370 SkASSERT(this->gpu()->pathRendering()); 371 return this->gpu()->pathRendering()->createPathRange(gen, style); 372 } 373 374 sk_sp<GrPathRange> GrResourceProvider::createGlyphs(const SkTypeface* tf, 375 const SkScalerContextEffects& effects, 376 const SkDescriptor* desc, 377 const GrStyle& style) { 378 379 SkASSERT(this->gpu()->pathRendering()); 380 return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style); 381 } 382 383 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType, 384 GrAccessPattern accessPattern, uint32_t flags, 385 const void* data) { 386 if (this->isAbandoned()) { 387 return nullptr; 388 } 389 if (kDynamic_GrAccessPattern != accessPattern) { 390 return this->gpu()->createBuffer(size, intendedType, accessPattern, data); 391 } 392 if (!(flags & kRequireGpuMemory_Flag) && 393 this->gpu()->caps()->preferClientSideDynamicBuffers() && 394 GrBufferTypeIsVertexOrIndex(intendedType) && 395 kDynamic_GrAccessPattern == accessPattern) { 396 return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data); 397 } 398 399 // bin by pow2 with a reasonable min 400 static const size_t MIN_SIZE = 1 << 12; 401 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size)); 402 403 GrScratchKey key; 404 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key); 405 uint32_t scratchFlags = 0; 406 if (flags & kNoPendingIO_Flag) { 407 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; 408 } else { 409 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; 410 } 411 GrBuffer* buffer = static_cast<GrBuffer*>( 412 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags)); 413 if (!buffer) { 414 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern); 415 if (!buffer) { 416 return nullptr; 417 } 418 } 419 if (data) { 420 buffer->updateData(data, size); 421 } 422 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs. 423 return buffer; 424 } 425 426 GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) { 427 SkASSERT(rt); 428 if (rt->renderTargetPriv().getStencilAttachment()) { 429 return rt->renderTargetPriv().getStencilAttachment(); 430 } 431 432 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) { 433 GrUniqueKey sbKey; 434 435 int width = rt->width(); 436 int height = rt->height(); 437 #if 0 438 if (this->caps()->oversizedStencilSupport()) { 439 width = SkNextPow2(width); 440 height = SkNextPow2(height); 441 } 442 #endif 443 bool newStencil = false; 444 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, 445 rt->numStencilSamples(), &sbKey); 446 GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>( 447 this->findAndRefResourceByUniqueKey(sbKey)); 448 if (!stencil) { 449 // Need to try and create a new stencil 450 stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height); 451 if (stencil) { 452 this->assignUniqueKeyToResource(sbKey, stencil); 453 newStencil = true; 454 } 455 } 456 if (rt->renderTargetPriv().attachStencilAttachment(stencil)) { 457 if (newStencil) { 458 // Right now we're clearing the stencil attachment here after it is 459 // attached to a RT for the first time. When we start matching 460 // stencil buffers with smaller color targets this will no longer 461 // be correct because it won't be guaranteed to clear the entire 462 // sb. 463 // We used to clear down in the GL subclass using a special purpose 464 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported 465 // FBO status. 466 this->gpu()->clearStencil(rt); 467 } 468 } 469 } 470 return rt->renderTargetPriv().getStencilAttachment(); 471 } 472 473 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget( 474 const GrBackendTexture& tex, GrSurfaceOrigin origin, int sampleCnt) 475 { 476 if (this->isAbandoned()) { 477 return nullptr; 478 } 479 return this->gpu()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt); 480 } 481 482 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) { 483 return fGpu->makeSemaphore(isOwned); 484 } 485 486 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, 487 GrWrapOwnership ownership) { 488 ASSERT_SINGLE_OWNER 489 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, ownership); 490 } 491 492 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) { 493 semaphore->resetGpu(fGpu); 494 } 495 496 void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) { 497 semaphore->resetGpu(nullptr); 498 } 499