GrTexture.cpp revision ed8659b51d9f2bad3f004df6033d72cc32d71c0d
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 17SK_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 */ 23void 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 41bool 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 55void 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 69void 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 84void GrTexture::onRelease() { 85 GrAssert(!this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit)); 86 this->releaseRenderTarget(); 87 88 INHERITED::onRelease(); 89} 90 91void GrTexture::onAbandon() { 92 if (NULL != fRenderTarget) { 93 fRenderTarget->abandon(); 94 } 95 96 INHERITED::onAbandon(); 97} 98 99void 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 120enum 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 133namespace { 134GrResourceKey::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 150GrResourceKey::ResourceType texture_resource_type() { 151 static const GrResourceKey::ResourceType gType = GrResourceKey::GenerateResourceType(); 152 return gType; 153} 154} 155 156GrResourceKey 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 164GrResourceKey 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) >= 16); 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 idKey.fData32[3] = desc.fOrigin; // Only needs 2 bits actually 175 static const int kPadSize = sizeof(idKey) - 16; 176 GR_STATIC_ASSERT(kPadSize >= 0); 177 memset(idKey.fData8 + 16, 0, kPadSize); 178 179 GrCacheID cacheID(GrResourceKey::ScratchDomain(), idKey); 180 return GrResourceKey(cacheID, texture_resource_type(), 0); 181} 182 183bool GrTexture::NeedsResizing(const GrResourceKey& key) { 184 return SkToBool(key.getResourceFlags() & kStretchToPOT_TextureFlag); 185} 186 187bool GrTexture::NeedsFiltering(const GrResourceKey& key) { 188 return SkToBool(key.getResourceFlags() & kFilter_TextureFlag); 189} 190