Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "GrTexture.h"
     11 
     12 #include "GrContext.h"
     13 #include "GrDrawTargetCaps.h"
     14 #include "GrGpu.h"
     15 #include "GrRenderTarget.h"
     16 #include "GrResourceCache.h"
     17 
     18 SK_DEFINE_INST_COUNT(GrTexture)
     19 
     20 GrTexture::~GrTexture() {
     21     if (NULL != fRenderTarget.get()) {
     22         fRenderTarget.get()->owningTextureDestroyed();
     23     }
     24 }
     25 
     26 /**
     27  * This method allows us to interrupt the normal deletion process and place
     28  * textures back in the texture cache when their ref count goes to zero.
     29  */
     30 void GrTexture::internal_dispose() const {
     31 
     32     if (this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit) &&
     33         NULL != this->INHERITED::getContext()) {
     34         GrTexture* nonConstThis = const_cast<GrTexture *>(this);
     35         this->fRefCnt = 1;      // restore ref count to initial setting
     36 
     37         nonConstThis->resetFlag((GrTextureFlags) kReturnToCache_FlagBit);
     38         nonConstThis->INHERITED::getContext()->addExistingTextureToCache(nonConstThis);
     39 
     40         // Note: "this" texture might be freed inside addExistingTextureToCache
     41         // if it is purged.
     42         return;
     43     }
     44 
     45     this->INHERITED::internal_dispose();
     46 }
     47 
     48 bool GrTexture::readPixels(int left, int top, int width, int height,
     49                            GrPixelConfig config, void* buffer,
     50                            size_t rowBytes, uint32_t pixelOpsFlags) {
     51     // go through context so that all necessary flushing occurs
     52     GrContext* context = this->getContext();
     53     if (NULL == context) {
     54         return false;
     55     }
     56     return context->readTexturePixels(this,
     57                                       left, top, width, height,
     58                                       config, buffer, rowBytes,
     59                                       pixelOpsFlags);
     60 }
     61 
     62 void GrTexture::writePixels(int left, int top, int width, int height,
     63                             GrPixelConfig config, const void* buffer,
     64                             size_t rowBytes, uint32_t pixelOpsFlags) {
     65     // go through context so that all necessary flushing occurs
     66     GrContext* context = this->getContext();
     67     if (NULL == context) {
     68         return;
     69     }
     70     context->writeTexturePixels(this,
     71                                 left, top, width, height,
     72                                 config, buffer, rowBytes,
     73                                 pixelOpsFlags);
     74 }
     75 
     76 void GrTexture::onRelease() {
     77     GrAssert(!this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit));
     78     INHERITED::onRelease();
     79 }
     80 
     81 void GrTexture::onAbandon() {
     82     if (NULL != fRenderTarget.get()) {
     83         fRenderTarget->abandon();
     84     }
     85     INHERITED::onAbandon();
     86 }
     87 
     88 void GrTexture::validateDesc() const {
     89     if (NULL != this->asRenderTarget()) {
     90         // This texture has a render target
     91         GrAssert(0 != (fDesc.fFlags & kRenderTarget_GrTextureFlagBit));
     92 
     93         if (NULL != this->asRenderTarget()->getStencilBuffer()) {
     94             GrAssert(0 != (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
     95         } else {
     96             GrAssert(0 == (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
     97         }
     98 
     99         GrAssert(fDesc.fSampleCnt == this->asRenderTarget()->numSamples());
    100     } else {
    101         GrAssert(0 == (fDesc.fFlags & kRenderTarget_GrTextureFlagBit));
    102         GrAssert(0 == (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
    103         GrAssert(0 == fDesc.fSampleCnt);
    104     }
    105 }
    106 
    107 // These flags need to fit in a GrResourceKey::ResourceFlags so they can be folded into the texture
    108 // key
    109 enum TextureFlags {
    110     /**
    111      * The kStretchToPOT bit is set when the texture is NPOT and is being repeated but the
    112      * hardware doesn't support that feature.
    113      */
    114     kStretchToPOT_TextureFlag = 0x1,
    115     /**
    116      * The kBilerp bit can only be set when the kStretchToPOT flag is set and indicates whether the
    117      * stretched texture should be bilerped.
    118      */
    119      kBilerp_TextureFlag       = 0x2,
    120 };
    121 
    122 namespace {
    123 GrResourceKey::ResourceFlags get_texture_flags(const GrGpu* gpu,
    124                                                const GrTextureParams* params,
    125                                                const GrTextureDesc& desc) {
    126     GrResourceKey::ResourceFlags flags = 0;
    127     bool tiled = NULL != params && params->isTiled();
    128     if (tiled && !gpu->caps()->npotTextureTileSupport()) {
    129         if (!GrIsPow2(desc.fWidth) || !GrIsPow2(desc.fHeight)) {
    130             flags |= kStretchToPOT_TextureFlag;
    131             switch(params->filterMode()) {
    132                 case GrTextureParams::kNone_FilterMode:
    133                     break;
    134                 case GrTextureParams::kBilerp_FilterMode:
    135                 case GrTextureParams::kMipMap_FilterMode:
    136                     flags |= kBilerp_TextureFlag;
    137                     break;
    138             }
    139         }
    140     }
    141     return flags;
    142 }
    143 
    144 GrResourceKey::ResourceType texture_resource_type() {
    145     static const GrResourceKey::ResourceType gType = GrResourceKey::GenerateResourceType();
    146     return gType;
    147 }
    148 
    149 // FIXME:  This should be refactored with the code in gl/GrGpuGL.cpp.
    150 GrSurfaceOrigin resolve_origin(const GrTextureDesc& desc) {
    151     // By default, GrRenderTargets are GL's normal orientation so that they
    152     // can be drawn to by the outside world without the client having
    153     // to render upside down.
    154     bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit);
    155     if (kDefault_GrSurfaceOrigin == desc.fOrigin) {
    156         return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
    157     } else {
    158         return desc.fOrigin;
    159     }
    160 }
    161 }
    162 
    163 GrResourceKey GrTexture::ComputeKey(const GrGpu* gpu,
    164                                     const GrTextureParams* params,
    165                                     const GrTextureDesc& desc,
    166                                     const GrCacheID& cacheID) {
    167     GrResourceKey::ResourceFlags flags = get_texture_flags(gpu, params, desc);
    168     return GrResourceKey(cacheID, texture_resource_type(), flags);
    169 }
    170 
    171 GrResourceKey GrTexture::ComputeScratchKey(const GrTextureDesc& desc) {
    172     GrCacheID::Key idKey;
    173     // Instead of a client-provided key of the texture contents we create a key from the
    174     // descriptor.
    175     GR_STATIC_ASSERT(sizeof(idKey) >= 16);
    176     GrAssert(desc.fHeight < (1 << 16));
    177     GrAssert(desc.fWidth < (1 << 16));
    178     idKey.fData32[0] = (desc.fWidth) | (desc.fHeight << 16);
    179     idKey.fData32[1] = desc.fConfig | desc.fSampleCnt << 16;
    180     idKey.fData32[2] = desc.fFlags;
    181     idKey.fData32[3] = resolve_origin(desc);    // Only needs 2 bits actually
    182     static const int kPadSize = sizeof(idKey) - 16;
    183     GR_STATIC_ASSERT(kPadSize >= 0);
    184     memset(idKey.fData8 + 16, 0, kPadSize);
    185 
    186     GrCacheID cacheID(GrResourceKey::ScratchDomain(), idKey);
    187     return GrResourceKey(cacheID, texture_resource_type(), 0);
    188 }
    189 
    190 bool GrTexture::NeedsResizing(const GrResourceKey& key) {
    191     return SkToBool(key.getResourceFlags() & kStretchToPOT_TextureFlag);
    192 }
    193 
    194 bool GrTexture::NeedsBilerp(const GrResourceKey& key) {
    195     return SkToBool(key.getResourceFlags() & kBilerp_TextureFlag);
    196 }
    197