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