Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2010 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 
      9 #include "GrGpu.h"
     10 
     11 #include "GrBackendSemaphore.h"
     12 #include "GrBackendSurface.h"
     13 #include "GrBuffer.h"
     14 #include "GrCaps.h"
     15 #include "GrContext.h"
     16 #include "GrContextPriv.h"
     17 #include "GrGpuResourcePriv.h"
     18 #include "GrMesh.h"
     19 #include "GrPathRendering.h"
     20 #include "GrPipeline.h"
     21 #include "GrRenderTargetPriv.h"
     22 #include "GrResourceCache.h"
     23 #include "GrResourceProvider.h"
     24 #include "GrSemaphore.h"
     25 #include "GrStencilAttachment.h"
     26 #include "GrStencilSettings.h"
     27 #include "GrSurfacePriv.h"
     28 #include "GrTexturePriv.h"
     29 #include "GrTracing.h"
     30 #include "SkJSONWriter.h"
     31 #include "SkMathPriv.h"
     32 
     33 ////////////////////////////////////////////////////////////////////////////////
     34 
     35 GrGpu::GrGpu(GrContext* context)
     36     : fResetTimestamp(kExpiredTimestamp+1)
     37     , fResetBits(kAll_GrBackendState)
     38     , fContext(context) {
     39     fMultisampleSpecs.emplace_back(0, 0, nullptr); // Index 0 is an invalid unique id.
     40 }
     41 
     42 GrGpu::~GrGpu() {}
     43 
     44 void GrGpu::disconnect(DisconnectType) {}
     45 
     46 ////////////////////////////////////////////////////////////////////////////////
     47 
     48 bool GrGpu::isACopyNeededForTextureParams(int width, int height,
     49                                           const GrSamplerState& textureParams,
     50                                           GrTextureProducer::CopyParams* copyParams,
     51                                           SkScalar scaleAdjust[2]) const {
     52     const GrCaps& caps = *this->caps();
     53     if (textureParams.isRepeated() && !caps.npotTextureTileSupport() &&
     54         (!SkIsPow2(width) || !SkIsPow2(height))) {
     55         SkASSERT(scaleAdjust);
     56         copyParams->fWidth = GrNextPow2(width);
     57         copyParams->fHeight = GrNextPow2(height);
     58         scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width;
     59         scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height;
     60         switch (textureParams.filter()) {
     61             case GrSamplerState::Filter::kNearest:
     62                 copyParams->fFilter = GrSamplerState::Filter::kNearest;
     63                 break;
     64             case GrSamplerState::Filter::kBilerp:
     65             case GrSamplerState::Filter::kMipMap:
     66                 // We are only ever scaling up so no reason to ever indicate kMipMap.
     67                 copyParams->fFilter = GrSamplerState::Filter::kBilerp;
     68                 break;
     69         }
     70         return true;
     71     }
     72     return false;
     73 }
     74 
     75 /**
     76  * Prior to creating a texture, make sure the type of texture being created is
     77  * supported by calling check_texture_creation_params.
     78  *
     79  * @param caps          The capabilities of the GL device.
     80  * @param desc          The descriptor of the texture to create.
     81  * @param isRT          Indicates if the texture can be a render target.
     82  * @param texels        The texel data for the mipmap levels
     83  * @param mipLevelCount The number of GrMipLevels in 'texels'
     84  */
     85 static bool check_texture_creation_params(const GrCaps& caps, const GrSurfaceDesc& desc,
     86                                           bool* isRT,
     87                                           const GrMipLevel texels[], int mipLevelCount) {
     88     if (!caps.isConfigTexturable(desc.fConfig)) {
     89         return false;
     90     }
     91 
     92     if (GrPixelConfigIsSint(desc.fConfig) && mipLevelCount > 1) {
     93         return false;
     94     }
     95 
     96     *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
     97     if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 1)) {
     98         return false;
     99     }
    100 
    101     if (desc.fSampleCnt < 1) {
    102         return false;
    103     }
    104 
    105     // We currently do not support multisampled textures
    106     if (!*isRT && desc.fSampleCnt > 1) {
    107         return false;
    108     }
    109 
    110     if (*isRT) {
    111         int maxRTSize = caps.maxRenderTargetSize();
    112         if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) {
    113             return false;
    114         }
    115     } else {
    116         int maxSize = caps.maxTextureSize();
    117         if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
    118             return false;
    119         }
    120     }
    121 
    122     return true;
    123 }
    124 
    125 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted,
    126                                       const GrMipLevel texels[], int mipLevelCount) {
    127     GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "createTexture", fContext);
    128     GrSurfaceDesc desc = origDesc;
    129 
    130     const GrCaps* caps = this->caps();
    131     bool isRT = false;
    132     bool textureCreationParamsValid = check_texture_creation_params(*caps, desc, &isRT,
    133                                                                     texels, mipLevelCount);
    134     if (!textureCreationParamsValid) {
    135         return nullptr;
    136     }
    137 
    138     if (isRT) {
    139         desc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig);
    140         if (!desc.fSampleCnt) {
    141             return nullptr;
    142         }
    143     }
    144     // Attempt to catch un- or wrongly initialized sample counts.
    145     SkASSERT(desc.fSampleCnt > 0 && desc.fSampleCnt <= 64);
    146 
    147     if (mipLevelCount && (desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) {
    148         return nullptr;
    149     }
    150 
    151     this->handleDirtyContext();
    152     sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount);
    153     if (tex) {
    154         if (!caps->reuseScratchTextures() && !isRT) {
    155             tex->resourcePriv().removeScratchKey();
    156         }
    157         fStats.incTextureCreates();
    158         if (mipLevelCount) {
    159             if (texels[0].fPixels) {
    160                 fStats.incTextureUploads();
    161             }
    162         }
    163     }
    164     return tex;
    165 }
    166 
    167 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted) {
    168     return this->createTexture(desc, budgeted, nullptr, 0);
    169 }
    170 
    171 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
    172                                            GrWrapOwnership ownership) {
    173     this->handleDirtyContext();
    174     if (!this->caps()->isConfigTexturable(backendTex.config())) {
    175         return nullptr;
    176     }
    177     if (backendTex.width() > this->caps()->maxTextureSize() ||
    178         backendTex.height() > this->caps()->maxTextureSize()) {
    179         return nullptr;
    180     }
    181     sk_sp<GrTexture> tex = this->onWrapBackendTexture(backendTex, ownership);
    182     if (!tex) {
    183         return nullptr;
    184     }
    185     return tex;
    186 }
    187 
    188 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
    189                                                      int sampleCnt, GrWrapOwnership ownership) {
    190     this->handleDirtyContext();
    191     if (sampleCnt < 1) {
    192         return nullptr;
    193     }
    194     if (!this->caps()->isConfigTexturable(backendTex.config()) ||
    195         !this->caps()->isConfigRenderable(backendTex.config(), sampleCnt > 1)) {
    196         return nullptr;
    197     }
    198 
    199     if (backendTex.width() > this->caps()->maxRenderTargetSize() ||
    200         backendTex.height() > this->caps()->maxRenderTargetSize()) {
    201         return nullptr;
    202     }
    203     sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, ownership);
    204     if (!tex) {
    205         return nullptr;
    206     }
    207     SkASSERT(tex->asRenderTarget());
    208     return tex;
    209 }
    210 
    211 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
    212     if (!this->caps()->isConfigRenderable(backendRT.config(), backendRT.sampleCnt() > 1)) {
    213         return nullptr;
    214     }
    215     this->handleDirtyContext();
    216     return this->onWrapBackendRenderTarget(backendRT);
    217 }
    218 
    219 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
    220                                                               int sampleCnt) {
    221     this->handleDirtyContext();
    222     if (!this->caps()->isConfigRenderable(tex.config(), sampleCnt > 1)) {
    223         return nullptr;
    224     }
    225     int maxSize = this->caps()->maxTextureSize();
    226     if (tex.width() > maxSize || tex.height() > maxSize) {
    227         return nullptr;
    228     }
    229     return this->onWrapBackendTextureAsRenderTarget(tex, sampleCnt);
    230 }
    231 
    232 GrBuffer* GrGpu::createBuffer(size_t size, GrBufferType intendedType,
    233                               GrAccessPattern accessPattern, const void* data) {
    234     this->handleDirtyContext();
    235     GrBuffer* buffer = this->onCreateBuffer(size, intendedType, accessPattern, data);
    236     if (!this->caps()->reuseScratchBuffers()) {
    237         buffer->resourcePriv().removeScratchKey();
    238     }
    239     return buffer;
    240 }
    241 
    242 bool GrGpu::copySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
    243                         GrSurface* src, GrSurfaceOrigin srcOrigin,
    244                         const SkIRect& srcRect, const SkIPoint& dstPoint,
    245                         bool canDiscardOutsideDstRect) {
    246     GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "copySurface", fContext);
    247     SkASSERT(dst && src);
    248     this->handleDirtyContext();
    249     // We don't allow conversion between integer configs and float/fixed configs.
    250     if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) {
    251         return false;
    252     }
    253     return this->onCopySurface(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint,
    254                                canDiscardOutsideDstRect);
    255 }
    256 
    257 bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
    258                               int width, int height, size_t rowBytes,
    259                               GrPixelConfig readConfig, DrawPreference* drawPreference,
    260                               ReadPixelTempDrawInfo* tempDrawInfo) {
    261     SkASSERT(drawPreference);
    262     SkASSERT(tempDrawInfo);
    263     SkASSERT(srcSurface);
    264     SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
    265 
    266     // We currently do not support reading into the packed formats 565 or 4444 as they are not
    267     // required to have read back support on all devices and backends.
    268     if (kRGB_565_GrPixelConfig == readConfig || kRGBA_4444_GrPixelConfig == readConfig) {
    269         return false;
    270     }
    271 
    272    if (!this->onGetReadPixelsInfo(srcSurface, srcOrigin, width, height, rowBytes, readConfig,
    273                                   drawPreference, tempDrawInfo)) {
    274         return false;
    275     }
    276 
    277     // Check to see if we're going to request that the caller draw when drawing is not possible.
    278     if (!srcSurface->asTexture() ||
    279         !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig, false)) {
    280         // If we don't have a fallback to a straight read then fail.
    281         if (kRequireDraw_DrawPreference == *drawPreference) {
    282             return false;
    283         }
    284         *drawPreference = kNoDraw_DrawPreference;
    285     }
    286 
    287     return true;
    288 }
    289 bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
    290                                int width, int height,
    291                                GrPixelConfig srcConfig, DrawPreference* drawPreference,
    292                                WritePixelTempDrawInfo* tempDrawInfo) {
    293     SkASSERT(drawPreference);
    294     SkASSERT(tempDrawInfo);
    295     SkASSERT(dstSurface);
    296     SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
    297 
    298     if (!this->onGetWritePixelsInfo(dstSurface, dstOrigin, width, height, srcConfig, drawPreference,
    299                                     tempDrawInfo)) {
    300         return false;
    301     }
    302 
    303     // Check to see if we're going to request that the caller draw when drawing is not possible.
    304     if (!dstSurface->asRenderTarget() ||
    305         !this->caps()->isConfigTexturable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
    306         // If we don't have a fallback to a straight upload then fail.
    307         if (kRequireDraw_DrawPreference == *drawPreference ||
    308             !this->caps()->isConfigTexturable(srcConfig)) {
    309             return false;
    310         }
    311         *drawPreference = kNoDraw_DrawPreference;
    312     }
    313     return true;
    314 }
    315 
    316 bool GrGpu::readPixels(GrSurface* surface, GrSurfaceOrigin origin,
    317                        int left, int top, int width, int height,
    318                        GrPixelConfig config, void* buffer,
    319                        size_t rowBytes) {
    320     SkASSERT(surface);
    321 
    322     // We don't allow conversion between integer configs and float/fixed configs.
    323     if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
    324         return false;
    325     }
    326 
    327     size_t bpp = GrBytesPerPixel(config);
    328     if (!GrSurfacePriv::AdjustReadPixelParams(surface->width(), surface->height(), bpp,
    329                                               &left, &top, &width, &height,
    330                                               &buffer,
    331                                               &rowBytes)) {
    332         return false;
    333     }
    334 
    335     this->handleDirtyContext();
    336 
    337     return this->onReadPixels(surface, origin,
    338                               left, top, width, height,
    339                               config, buffer,
    340                               rowBytes);
    341 }
    342 
    343 bool GrGpu::writePixels(GrSurface* surface, GrSurfaceOrigin origin,
    344                         int left, int top, int width, int height,
    345                         GrPixelConfig config, const GrMipLevel texels[], int mipLevelCount) {
    346     SkASSERT(surface);
    347     if (1 == mipLevelCount) {
    348         // We require that if we are not mipped, then the write region is contained in the surface
    349         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
    350         SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height());
    351         if (!bounds.contains(subRect)) {
    352             return false;
    353         }
    354     } else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) {
    355         // We require that if the texels are mipped, than the write region is the entire surface
    356         return false;
    357     }
    358 
    359     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
    360         if (!texels[currentMipLevel].fPixels ) {
    361             return false;
    362         }
    363     }
    364 
    365     // We don't allow conversion between integer configs and float/fixed configs.
    366     if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
    367         return false;
    368     }
    369 
    370     this->handleDirtyContext();
    371     if (this->onWritePixels(surface, origin, left, top, width, height, config,
    372                             texels, mipLevelCount)) {
    373         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
    374         this->didWriteToSurface(surface, &rect, mipLevelCount);
    375         fStats.incTextureUploads();
    376         return true;
    377     }
    378     return false;
    379 }
    380 
    381 bool GrGpu::writePixels(GrSurface* surface, GrSurfaceOrigin origin,
    382                         int left, int top, int width, int height,
    383                         GrPixelConfig config, const void* buffer,
    384                         size_t rowBytes) {
    385     GrMipLevel mipLevel = { buffer, rowBytes };
    386 
    387     return this->writePixels(surface, origin, left, top, width, height, config, &mipLevel, 1);
    388 }
    389 
    390 bool GrGpu::transferPixels(GrTexture* texture,
    391                            int left, int top, int width, int height,
    392                            GrPixelConfig config, GrBuffer* transferBuffer,
    393                            size_t offset, size_t rowBytes) {
    394     SkASSERT(transferBuffer);
    395 
    396     // We don't allow conversion between integer configs and float/fixed configs.
    397     if (GrPixelConfigIsSint(texture->config()) != GrPixelConfigIsSint(config)) {
    398         return false;
    399     }
    400 
    401     // We require that the write region is contained in the texture
    402     SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
    403     SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
    404     if (!bounds.contains(subRect)) {
    405         return false;
    406     }
    407 
    408     this->handleDirtyContext();
    409     if (this->onTransferPixels(texture, left, top, width, height, config,
    410                                transferBuffer, offset, rowBytes)) {
    411         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
    412         this->didWriteToSurface(texture, &rect);
    413         fStats.incTransfersToTexture();
    414 
    415         return true;
    416     }
    417     return false;
    418 }
    419 
    420 void GrGpu::resolveRenderTarget(GrRenderTarget* target, GrSurfaceOrigin origin) {
    421     SkASSERT(target);
    422     this->handleDirtyContext();
    423     this->onResolveRenderTarget(target, origin);
    424 }
    425 
    426 void GrGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_t mipLevels) const {
    427     SkASSERT(surface);
    428     // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds.
    429     if (nullptr == bounds || !bounds->isEmpty()) {
    430         if (GrRenderTarget* target = surface->asRenderTarget()) {
    431             target->flagAsNeedingResolve(bounds);
    432         }
    433         GrTexture* texture = surface->asTexture();
    434         if (texture && 1 == mipLevels) {
    435             texture->texturePriv().markMipMapsDirty();
    436         }
    437     }
    438 }
    439 
    440 const GrGpu::MultisampleSpecs& GrGpu::queryMultisampleSpecs(const GrPipeline& pipeline) {
    441     GrRenderTarget* rt = pipeline.renderTarget();
    442     SkASSERT(rt->numStencilSamples() > 1);
    443 
    444     GrStencilSettings stencil;
    445     if (pipeline.isStencilEnabled()) {
    446         // TODO: attach stencil and create settings during render target flush.
    447         SkASSERT(rt->renderTargetPriv().getStencilAttachment());
    448         stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
    449                       rt->renderTargetPriv().numStencilBits());
    450     }
    451 
    452     int effectiveSampleCnt;
    453     SkSTArray<16, SkPoint, true> pattern;
    454     this->onQueryMultisampleSpecs(rt, pipeline.proxy()->origin(), stencil,
    455                                   &effectiveSampleCnt, &pattern);
    456     SkASSERT(effectiveSampleCnt >= rt->numStencilSamples());
    457 
    458     uint8_t id;
    459     if (this->caps()->sampleLocationsSupport()) {
    460         SkASSERT(pattern.count() == effectiveSampleCnt);
    461         const auto& insertResult = fMultisampleSpecsIdMap.insert(
    462             MultisampleSpecsIdMap::value_type(pattern, SkTMin(fMultisampleSpecs.count(), 255)));
    463         id = insertResult.first->second;
    464         if (insertResult.second) {
    465             // This means the insert did not find the pattern in the map already, and therefore an
    466             // actual insertion took place. (We don't expect to see many unique sample patterns.)
    467             const SkPoint* sampleLocations = insertResult.first->first.begin();
    468             SkASSERT(id == fMultisampleSpecs.count());
    469             fMultisampleSpecs.emplace_back(id, effectiveSampleCnt, sampleLocations);
    470         }
    471     } else {
    472         id = effectiveSampleCnt;
    473         for (int i = fMultisampleSpecs.count(); i <= id; ++i) {
    474             fMultisampleSpecs.emplace_back(i, i, nullptr);
    475         }
    476     }
    477     SkASSERT(id > 0);
    478 
    479     return fMultisampleSpecs[id];
    480 }
    481 
    482 bool GrGpu::SamplePatternComparator::operator()(const SamplePattern& a,
    483                                                 const SamplePattern& b) const {
    484     if (a.count() != b.count()) {
    485         return a.count() < b.count();
    486     }
    487     for (int i = 0; i < a.count(); ++i) {
    488         // This doesn't have geometric meaning. We just need to define an ordering for std::map.
    489         if (a[i].x() != b[i].x()) {
    490             return a[i].x() < b[i].x();
    491         }
    492         if (a[i].y() != b[i].y()) {
    493             return a[i].y() < b[i].y();
    494         }
    495     }
    496     return false; // Equal.
    497 }
    498 
    499 GrSemaphoresSubmitted GrGpu::finishFlush(int numSemaphores,
    500                                          GrBackendSemaphore backendSemaphores[]) {
    501     GrResourceProvider* resourceProvider = fContext->contextPriv().resourceProvider();
    502 
    503     if (this->caps()->fenceSyncSupport()) {
    504         for (int i = 0; i < numSemaphores; ++i) {
    505             sk_sp<GrSemaphore> semaphore;
    506             if (backendSemaphores[i].isInitialized()) {
    507                 semaphore = resourceProvider->wrapBackendSemaphore(
    508                         backendSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillSignal,
    509                         kBorrow_GrWrapOwnership);
    510             } else {
    511                 semaphore = resourceProvider->makeSemaphore(false);
    512             }
    513             this->insertSemaphore(semaphore, false);
    514 
    515             if (!backendSemaphores[i].isInitialized()) {
    516                 semaphore->setBackendSemaphore(&backendSemaphores[i]);
    517             }
    518         }
    519     }
    520     this->onFinishFlush((numSemaphores > 0 && this->caps()->fenceSyncSupport()));
    521     return this->caps()->fenceSyncSupport() ? GrSemaphoresSubmitted::kYes
    522                                             : GrSemaphoresSubmitted::kNo;
    523 }
    524 
    525 void GrGpu::dumpJSON(SkJSONWriter* writer) const {
    526     writer->beginObject();
    527 
    528     // TODO: Is there anything useful in the base class to dump here?
    529 
    530     this->onDumpJSON(writer);
    531 
    532     writer->endObject();
    533 }
    534