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