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