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