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