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 "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