Home | History | Annotate | Download | only in gpu
      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