2011-04-05 17:08:27 +00:00
|
|
|
|
2011-07-28 14:26:00 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2011 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
2011-04-05 17:08:27 +00:00
|
|
|
*/
|
|
|
|
|
2011-07-28 14:26:00 +00:00
|
|
|
|
2011-04-05 17:08:27 +00:00
|
|
|
#include "GrTexture.h"
|
2011-07-29 15:13:20 +00:00
|
|
|
|
2011-04-05 17:08:27 +00:00
|
|
|
#include "GrContext.h"
|
2011-05-02 21:14:59 +00:00
|
|
|
#include "GrGpu.h"
|
2011-07-29 15:13:20 +00:00
|
|
|
#include "GrRenderTarget.h"
|
2012-06-04 20:05:28 +00:00
|
|
|
#include "GrResourceCache.h"
|
2011-05-02 12:53:34 +00:00
|
|
|
|
2012-06-13 18:54:08 +00:00
|
|
|
SK_DEFINE_INST_COUNT(GrTexture)
|
2012-12-20 14:23:26 +00:00
|
|
|
GR_DEFINE_RESOURCE_CACHE_TYPE(GrTexture)
|
2012-06-13 18:54:08 +00:00
|
|
|
|
2012-08-23 18:14:13 +00:00
|
|
|
/**
|
2012-06-22 12:41:43 +00:00
|
|
|
* This method allows us to interrupt the normal deletion process and place
|
|
|
|
* textures back in the texture cache when their ref count goes to zero.
|
|
|
|
*/
|
|
|
|
void GrTexture::internal_dispose() const {
|
|
|
|
|
|
|
|
if (this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit) &&
|
|
|
|
NULL != this->INHERITED::getContext()) {
|
|
|
|
GrTexture* nonConstThis = const_cast<GrTexture *>(this);
|
|
|
|
this->fRefCnt = 1; // restore ref count to initial setting
|
|
|
|
|
|
|
|
nonConstThis->resetFlag((GrTextureFlags) kReturnToCache_FlagBit);
|
|
|
|
nonConstThis->INHERITED::getContext()->addExistingTextureToCache(nonConstThis);
|
|
|
|
|
2012-08-23 18:14:13 +00:00
|
|
|
// Note: "this" texture might be freed inside addExistingTextureToCache
|
2012-06-25 17:26:29 +00:00
|
|
|
// if it is purged.
|
2012-06-22 12:41:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->INHERITED::internal_dispose();
|
|
|
|
}
|
|
|
|
|
2011-04-05 17:08:27 +00:00
|
|
|
bool GrTexture::readPixels(int left, int top, int width, int height,
|
2011-11-16 20:36:03 +00:00
|
|
|
GrPixelConfig config, void* buffer,
|
2012-08-20 19:22:38 +00:00
|
|
|
size_t rowBytes, uint32_t pixelOpsFlags) {
|
2011-04-05 17:08:27 +00:00
|
|
|
// go through context so that all necessary flushing occurs
|
2011-11-16 20:36:03 +00:00
|
|
|
GrContext* context = this->getContext();
|
|
|
|
if (NULL == context) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-04-05 17:08:27 +00:00
|
|
|
return context->readTexturePixels(this,
|
2012-08-20 19:22:38 +00:00
|
|
|
left, top, width, height,
|
|
|
|
config, buffer, rowBytes,
|
|
|
|
pixelOpsFlags);
|
2011-11-16 20:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GrTexture::writePixels(int left, int top, int width, int height,
|
|
|
|
GrPixelConfig config, const void* buffer,
|
2012-08-20 19:22:38 +00:00
|
|
|
size_t rowBytes, uint32_t pixelOpsFlags) {
|
2011-11-16 20:36:03 +00:00
|
|
|
// go through context so that all necessary flushing occurs
|
|
|
|
GrContext* context = this->getContext();
|
|
|
|
if (NULL == context) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
context->writeTexturePixels(this,
|
2012-08-20 19:22:38 +00:00
|
|
|
left, top, width, height,
|
|
|
|
config, buffer, rowBytes,
|
|
|
|
pixelOpsFlags);
|
2011-04-05 17:08:27 +00:00
|
|
|
}
|
2011-07-26 12:32:36 +00:00
|
|
|
|
2011-07-29 15:13:20 +00:00
|
|
|
void GrTexture::releaseRenderTarget() {
|
|
|
|
if (NULL != fRenderTarget) {
|
|
|
|
GrAssert(fRenderTarget->asTexture() == this);
|
2012-06-04 12:48:45 +00:00
|
|
|
GrAssert(fDesc.fFlags & kRenderTarget_GrTextureFlagBit);
|
|
|
|
|
2011-07-29 15:13:20 +00:00
|
|
|
fRenderTarget->onTextureReleaseRenderTarget();
|
|
|
|
fRenderTarget->unref();
|
|
|
|
fRenderTarget = NULL;
|
2012-06-04 12:48:45 +00:00
|
|
|
|
|
|
|
fDesc.fFlags = fDesc.fFlags &
|
|
|
|
~(kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit);
|
|
|
|
fDesc.fSampleCnt = 0;
|
2011-07-29 15:13:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 12:41:43 +00:00
|
|
|
void GrTexture::onRelease() {
|
|
|
|
GrAssert(!this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit));
|
|
|
|
this->releaseRenderTarget();
|
2012-09-05 18:37:39 +00:00
|
|
|
|
|
|
|
INHERITED::onRelease();
|
2012-06-22 12:41:43 +00:00
|
|
|
}
|
|
|
|
|
2011-07-29 15:13:20 +00:00
|
|
|
void GrTexture::onAbandon() {
|
|
|
|
if (NULL != fRenderTarget) {
|
|
|
|
fRenderTarget->abandon();
|
|
|
|
}
|
2012-09-05 18:37:39 +00:00
|
|
|
|
|
|
|
INHERITED::onAbandon();
|
2011-07-29 15:13:20 +00:00
|
|
|
}
|
|
|
|
|
2012-06-04 12:48:45 +00:00
|
|
|
void GrTexture::validateDesc() const {
|
|
|
|
if (NULL != this->asRenderTarget()) {
|
|
|
|
// This texture has a render target
|
|
|
|
GrAssert(0 != (fDesc.fFlags & kRenderTarget_GrTextureFlagBit));
|
|
|
|
|
|
|
|
if (NULL != this->asRenderTarget()->getStencilBuffer()) {
|
|
|
|
GrAssert(0 != (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
|
|
|
|
} else {
|
|
|
|
GrAssert(0 == (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
|
|
|
|
}
|
|
|
|
|
|
|
|
GrAssert(fDesc.fSampleCnt == this->asRenderTarget()->numSamples());
|
|
|
|
} else {
|
|
|
|
GrAssert(0 == (fDesc.fFlags & kRenderTarget_GrTextureFlagBit));
|
|
|
|
GrAssert(0 == (fDesc.fFlags & kNoStencil_GrTextureFlagBit));
|
|
|
|
GrAssert(0 == fDesc.fSampleCnt);
|
|
|
|
}
|
|
|
|
}
|
2012-06-04 20:05:28 +00:00
|
|
|
|
2012-12-20 14:23:26 +00:00
|
|
|
// These flags need to fit in <= 8 bits so they can be folded into the texture
|
2012-08-08 10:42:44 +00:00
|
|
|
// key
|
2012-12-20 14:23:26 +00:00
|
|
|
enum TextureBits {
|
|
|
|
/*
|
|
|
|
* The kNPOT bit is set when the texture is NPOT and is being repeated
|
|
|
|
* but the hardware doesn't support that feature.
|
2012-06-04 20:05:28 +00:00
|
|
|
*/
|
2012-12-20 14:23:26 +00:00
|
|
|
kNPOT_TextureBit = 0x1,
|
|
|
|
/*
|
|
|
|
* The kFilter bit can only be set when the kNPOT flag is set and indicates
|
|
|
|
* whether the resizing of the texture should use filtering. This is
|
|
|
|
* to handle cases where the original texture is indexed to disable
|
|
|
|
* filtering.
|
2012-06-04 20:05:28 +00:00
|
|
|
*/
|
2012-12-20 14:23:26 +00:00
|
|
|
kFilter_TextureBit = 0x2,
|
|
|
|
/*
|
|
|
|
* The kScratch bit is set if the texture is being used as a scratch
|
|
|
|
* texture.
|
|
|
|
*/
|
|
|
|
kScratch_TextureBit = 0x4,
|
2012-06-04 20:05:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
2012-12-20 14:23:26 +00:00
|
|
|
void gen_texture_key_values(const GrGpu* gpu,
|
|
|
|
const GrTextureParams* params,
|
|
|
|
const GrTextureDesc& desc,
|
|
|
|
const GrCacheData& cacheData,
|
|
|
|
bool scratch,
|
|
|
|
GrCacheID* cacheID) {
|
|
|
|
|
|
|
|
uint64_t clientKey = cacheData.fClientCacheID;
|
|
|
|
|
|
|
|
if (scratch) {
|
|
|
|
// Instead of a client-provided key of the texture contents
|
|
|
|
// we create a key from the descriptor.
|
|
|
|
GrAssert(GrCacheData::kScratch_CacheID == clientKey);
|
|
|
|
clientKey = (desc.fFlags << 8) | ((uint64_t) desc.fConfig << 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
cacheID->fPublicID = clientKey;
|
|
|
|
cacheID->fDomain = cacheData.fResourceDomain;
|
|
|
|
|
|
|
|
// we assume we only need 16 bits of width and height
|
|
|
|
// assert that texture creation will fail anyway if this assumption
|
|
|
|
// would cause key collisions.
|
|
|
|
GrAssert(gpu->getCaps().maxTextureSize() <= SK_MaxU16);
|
|
|
|
cacheID->fResourceSpecific32 = desc.fWidth | (desc.fHeight << 16);
|
|
|
|
|
|
|
|
GrAssert(desc.fSampleCnt >= 0 && desc.fSampleCnt < 256);
|
|
|
|
cacheID->fResourceSpecific16 = desc.fSampleCnt << 8;
|
|
|
|
|
|
|
|
if (!gpu->getCaps().npotTextureTileSupport()) {
|
|
|
|
bool isPow2 = GrIsPow2(desc.fWidth) && GrIsPow2(desc.fHeight);
|
|
|
|
|
|
|
|
bool tiled = NULL != params && params->isTiled();
|
|
|
|
|
|
|
|
if (tiled && !isPow2) {
|
|
|
|
cacheID->fResourceSpecific16 |= kNPOT_TextureBit;
|
2012-07-25 21:27:09 +00:00
|
|
|
if (params->isBilerp()) {
|
2012-12-20 14:23:26 +00:00
|
|
|
cacheID->fResourceSpecific16 |= kFilter_TextureBit;
|
2012-06-04 20:05:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-20 14:23:26 +00:00
|
|
|
if (scratch) {
|
|
|
|
cacheID->fResourceSpecific16 |= kScratch_TextureBit;
|
|
|
|
}
|
2012-06-04 20:05:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GrResourceKey GrTexture::ComputeKey(const GrGpu* gpu,
|
2012-07-25 21:27:09 +00:00
|
|
|
const GrTextureParams* params,
|
2012-06-04 20:05:28 +00:00
|
|
|
const GrTextureDesc& desc,
|
2012-12-20 14:23:26 +00:00
|
|
|
const GrCacheData& cacheData,
|
|
|
|
bool scratch) {
|
|
|
|
GrCacheID id(GrTexture::GetResourceType());
|
|
|
|
gen_texture_key_values(gpu, params, desc, cacheData, scratch, &id);
|
|
|
|
|
|
|
|
uint32_t v[4];
|
|
|
|
id.toRaw(v);
|
|
|
|
return GrResourceKey(v);
|
2012-06-04 20:05:28 +00:00
|
|
|
}
|
|
|
|
|
2012-12-20 14:23:26 +00:00
|
|
|
bool GrTexture::NeedsResizing(const GrResourceKey& key) {
|
|
|
|
return 0 != (key.getValue32(3) & kNPOT_TextureBit);
|
2012-06-04 20:05:28 +00:00
|
|
|
}
|
|
|
|
|
2012-12-20 14:23:26 +00:00
|
|
|
bool GrTexture::IsScratchTexture(const GrResourceKey& key) {
|
|
|
|
return 0 != (key.getValue32(3) & kScratch_TextureBit);
|
2012-06-04 20:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GrTexture::NeedsFiltering(const GrResourceKey& key) {
|
2012-12-20 14:23:26 +00:00
|
|
|
return 0 != (key.getValue32(3) & kFilter_TextureBit);
|
2012-06-04 20:05:28 +00:00
|
|
|
}
|