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