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