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