blob: 19dc32220de7a83a2c6f37ce4e6495ae96dde667 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
bsalomon@google.com669fdc42011-04-05 17:08:27 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com669fdc42011-04-05 17:08:27 +000010#include "GrTexture.h"
bsalomon@google.comaa5b6732011-07-29 15:13:20 +000011
bsalomon@google.com669fdc42011-04-05 17:08:27 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.comaa5b6732011-07-29 15:13:20 +000014#include "GrRenderTarget.h"
robertphillips@google.coma1e57952012-06-04 20:05:28 +000015#include "GrResourceCache.h"
bsalomon@google.com8295dc12011-05-02 12:53:34 +000016
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000017SK_DEFINE_INST_COUNT(GrTexture)
18
robertphillips@google.com15c0fea2012-06-22 12:41:43 +000019/**
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 next assert is only correct for the texture cache's
34 // current single threaded usage. If we ever start accessing it via
35 // threads it isn't guaranteed to be correct.
36 GrAssert(1 == this->INHERITED::getRefCnt());
37 return;
38 }
39
40 this->INHERITED::internal_dispose();
41}
42
bsalomon@google.com669fdc42011-04-05 17:08:27 +000043bool GrTexture::readPixels(int left, int top, int width, int height,
bsalomon@google.com6f379512011-11-16 20:36:03 +000044 GrPixelConfig config, void* buffer,
45 size_t rowBytes) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000046 // go through context so that all necessary flushing occurs
bsalomon@google.com6f379512011-11-16 20:36:03 +000047 GrContext* context = this->getContext();
48 if (NULL == context) {
49 return false;
50 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +000051 return context->readTexturePixels(this,
bsalomon@google.com6f379512011-11-16 20:36:03 +000052 left, top,
53 width, height,
54 config, buffer, rowBytes);
55}
56
57void GrTexture::writePixels(int left, int top, int width, int height,
58 GrPixelConfig config, const void* buffer,
59 size_t rowBytes) {
60 // go through context so that all necessary flushing occurs
61 GrContext* context = this->getContext();
62 if (NULL == context) {
63 return;
64 }
65 context->writeTexturePixels(this,
66 left, top,
67 width, height,
68 config, buffer, rowBytes);
bsalomon@google.com669fdc42011-04-05 17:08:27 +000069}
bsalomon@google.comcee661a2011-07-26 12:32:36 +000070
bsalomon@google.comaa5b6732011-07-29 15:13:20 +000071void GrTexture::releaseRenderTarget() {
72 if (NULL != fRenderTarget) {
73 GrAssert(fRenderTarget->asTexture() == this);
robertphillips@google.com32716282012-06-04 12:48:45 +000074 GrAssert(fDesc.fFlags & kRenderTarget_GrTextureFlagBit);
75
bsalomon@google.comaa5b6732011-07-29 15:13:20 +000076 fRenderTarget->onTextureReleaseRenderTarget();
77 fRenderTarget->unref();
78 fRenderTarget = NULL;
robertphillips@google.com32716282012-06-04 12:48:45 +000079
80 fDesc.fFlags = fDesc.fFlags &
81 ~(kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit);
82 fDesc.fSampleCnt = 0;
bsalomon@google.comaa5b6732011-07-29 15:13:20 +000083 }
84}
85
robertphillips@google.com15c0fea2012-06-22 12:41:43 +000086void GrTexture::onRelease() {
87 GrAssert(!this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit));
88 this->releaseRenderTarget();
89}
90
bsalomon@google.comaa5b6732011-07-29 15:13:20 +000091void GrTexture::onAbandon() {
92 if (NULL != fRenderTarget) {
93 fRenderTarget->abandon();
94 }
95}
96
robertphillips@google.com32716282012-06-04 12:48:45 +000097void GrTexture::validateDesc() const {
98 if (NULL != this->asRenderTarget()) {
99 // This texture has a render target
100 GrAssert(0 != (fDesc.fFlags & kRenderTarget_GrTextureFlagBit));
101
102 if (NULL != this->asRenderTarget()->getStencilBuffer()) {
103 GrAssert(0 != (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
104 } else {
105 GrAssert(0 == (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
106 }
107
108 GrAssert(fDesc.fSampleCnt == this->asRenderTarget()->numSamples());
109 } else {
110 GrAssert(0 == (fDesc.fFlags & kRenderTarget_GrTextureFlagBit));
111 GrAssert(0 == (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
112 GrAssert(0 == fDesc.fSampleCnt);
113 }
114}
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000115
116enum TextureBits {
117 kFirst_TextureBit = (GrResourceKey::kLastPublic_TypeBit << 1),
118
119 /*
120 * The kNPOT bit is set when the texture is NPOT and is being repeated
121 * but the hardware doesn't support that feature.
122 */
123 kNPOT_TextureBit = kFirst_TextureBit,
124 /*
125 * The kFilter bit can only be set when the kNPOT flag is set and indicates
126 * whether the resizing of the texture should use filtering. This is
127 * to handle cases where the original texture is indexed to disable
128 * filtering.
129 */
130 kFilter_TextureBit = kNPOT_TextureBit << 1,
131 /*
132 * The kScratch bit is set if the texture is being used as a scratch
133 * texture.
134 */
135 kScratch_TextureBit = kFilter_TextureBit << 1,
136};
137
138namespace {
139void gen_texture_key_values(const GrGpu* gpu,
140 const GrSamplerState* sampler,
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000141 const GrTextureDesc& desc,
142 bool scratch,
143 uint32_t v[4]) {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000144
145 uint64_t clientKey = desc.fClientCacheID;
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000146
147 if (scratch) {
148 // Instead of a client-provided key of the texture contents
149 // we create a key of from the descriptor.
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000150 GrAssert(kScratch_CacheID == clientKey);
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000151 clientKey = (desc.fFlags << 8) | ((uint64_t) desc.fConfig << 32);
152 }
153
154 // we assume we only need 16 bits of width and height
155 // assert that texture creation will fail anyway if this assumption
156 // would cause key collisions.
157 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000158 v[0] = (uint32_t) (clientKey & 0xffffffffUL);
159 v[1] = (uint32_t) ((clientKey >> 32) & 0xffffffffUL);
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000160 v[2] = desc.fWidth | (desc.fHeight << 16);
161
162 v[3] = (desc.fSampleCnt << 24);
163 GrAssert(desc.fSampleCnt >= 0 && desc.fSampleCnt < 256);
164
165 if (!gpu->getCaps().fNPOTTextureTileSupport) {
166 bool isPow2 = GrIsPow2(desc.fWidth) && GrIsPow2(desc.fHeight);
167
168 bool tiled = NULL != sampler &&
169 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
170 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
171
172 if (tiled && !isPow2) {
173 v[3] |= kNPOT_TextureBit;
174 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
175 v[3] |= kFilter_TextureBit;
176 }
177 }
178 }
179
180 if (scratch) {
181 v[3] |= kScratch_TextureBit;
182 }
183
184 v[3] |= GrResourceKey::kTexture_TypeBit;
185}
186}
187
188GrResourceKey GrTexture::ComputeKey(const GrGpu* gpu,
189 const GrSamplerState* sampler,
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000190 const GrTextureDesc& desc,
191 bool scratch) {
192 uint32_t v[4];
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000193 gen_texture_key_values(gpu, sampler, desc, scratch, v);
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000194 return GrResourceKey(v);
195}
196
197bool GrTexture::NeedsResizing(const GrResourceKey& key) {
198 return 0 != (key.getValue32(3) & kNPOT_TextureBit);
199}
200
201bool GrTexture::IsScratchTexture(const GrResourceKey& key) {
202 return 0 != (key.getValue32(3) & kScratch_TextureBit);
203}
204
205bool GrTexture::NeedsFiltering(const GrResourceKey& key) {
206 return 0 != (key.getValue32(3) & kFilter_TextureBit);
207}