summaryrefslogtreecommitdiff
path: root/gpu/GrTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/GrTexture.cpp')
-rw-r--r--gpu/GrTexture.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/gpu/GrTexture.cpp b/gpu/GrTexture.cpp
new file mode 100644
index 00000000..c05f35d9
--- /dev/null
+++ b/gpu/GrTexture.cpp
@@ -0,0 +1,196 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTexture.h"
+
+#include "GrContext.h"
+#include "GrDrawTargetCaps.h"
+#include "GrGpu.h"
+#include "GrRenderTarget.h"
+#include "GrResourceCache.h"
+
+SK_DEFINE_INST_COUNT(GrTexture)
+
+GrTexture::~GrTexture() {
+ if (NULL != fRenderTarget.get()) {
+ fRenderTarget.get()->owningTextureDestroyed();
+ }
+}
+
+/**
+ * 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);
+
+ // Note: "this" texture might be freed inside addExistingTextureToCache
+ // if it is purged.
+ return;
+ }
+
+ this->INHERITED::internal_dispose();
+}
+
+bool GrTexture::readPixels(int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes, uint32_t pixelOpsFlags) {
+ // go through context so that all necessary flushing occurs
+ GrContext* context = this->getContext();
+ if (NULL == context) {
+ return false;
+ }
+ return context->readTexturePixels(this,
+ left, top, width, height,
+ config, buffer, rowBytes,
+ pixelOpsFlags);
+}
+
+void GrTexture::writePixels(int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes, uint32_t pixelOpsFlags) {
+ // go through context so that all necessary flushing occurs
+ GrContext* context = this->getContext();
+ if (NULL == context) {
+ return;
+ }
+ context->writeTexturePixels(this,
+ left, top, width, height,
+ config, buffer, rowBytes,
+ pixelOpsFlags);
+}
+
+void GrTexture::onRelease() {
+ GrAssert(!this->isSetFlag((GrTextureFlags) kReturnToCache_FlagBit));
+ INHERITED::onRelease();
+}
+
+void GrTexture::onAbandon() {
+ if (NULL != fRenderTarget.get()) {
+ fRenderTarget->abandon();
+ }
+ INHERITED::onAbandon();
+}
+
+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);
+ }
+}
+
+// These flags need to fit in a GrResourceKey::ResourceFlags so they can be folded into the texture
+// key
+enum TextureFlags {
+ /**
+ * The kStretchToPOT bit is set when the texture is NPOT and is being repeated but the
+ * hardware doesn't support that feature.
+ */
+ kStretchToPOT_TextureFlag = 0x1,
+ /**
+ * The kBilerp bit can only be set when the kStretchToPOT flag is set and indicates whether the
+ * stretched texture should be bilerped.
+ */
+ kBilerp_TextureFlag = 0x2,
+};
+
+namespace {
+GrResourceKey::ResourceFlags get_texture_flags(const GrGpu* gpu,
+ const GrTextureParams* params,
+ const GrTextureDesc& desc) {
+ GrResourceKey::ResourceFlags flags = 0;
+ bool tiled = NULL != params && params->isTiled();
+ if (tiled && !gpu->caps()->npotTextureTileSupport()) {
+ if (!GrIsPow2(desc.fWidth) || !GrIsPow2(desc.fHeight)) {
+ flags |= kStretchToPOT_TextureFlag;
+ switch(params->filterMode()) {
+ case GrTextureParams::kNone_FilterMode:
+ break;
+ case GrTextureParams::kBilerp_FilterMode:
+ case GrTextureParams::kMipMap_FilterMode:
+ flags |= kBilerp_TextureFlag;
+ break;
+ }
+ }
+ }
+ return flags;
+}
+
+GrResourceKey::ResourceType texture_resource_type() {
+ static const GrResourceKey::ResourceType gType = GrResourceKey::GenerateResourceType();
+ return gType;
+}
+
+// FIXME: This should be refactored with the code in gl/GrGpuGL.cpp.
+GrSurfaceOrigin resolve_origin(const GrTextureDesc& desc) {
+ // By default, GrRenderTargets are GL's normal orientation so that they
+ // can be drawn to by the outside world without the client having
+ // to render upside down.
+ bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit);
+ if (kDefault_GrSurfaceOrigin == desc.fOrigin) {
+ return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
+ } else {
+ return desc.fOrigin;
+ }
+}
+}
+
+GrResourceKey GrTexture::ComputeKey(const GrGpu* gpu,
+ const GrTextureParams* params,
+ const GrTextureDesc& desc,
+ const GrCacheID& cacheID) {
+ GrResourceKey::ResourceFlags flags = get_texture_flags(gpu, params, desc);
+ return GrResourceKey(cacheID, texture_resource_type(), flags);
+}
+
+GrResourceKey GrTexture::ComputeScratchKey(const GrTextureDesc& desc) {
+ GrCacheID::Key idKey;
+ // Instead of a client-provided key of the texture contents we create a key from the
+ // descriptor.
+ GR_STATIC_ASSERT(sizeof(idKey) >= 16);
+ GrAssert(desc.fHeight < (1 << 16));
+ GrAssert(desc.fWidth < (1 << 16));
+ idKey.fData32[0] = (desc.fWidth) | (desc.fHeight << 16);
+ idKey.fData32[1] = desc.fConfig | desc.fSampleCnt << 16;
+ idKey.fData32[2] = desc.fFlags;
+ idKey.fData32[3] = resolve_origin(desc); // Only needs 2 bits actually
+ static const int kPadSize = sizeof(idKey) - 16;
+ GR_STATIC_ASSERT(kPadSize >= 0);
+ memset(idKey.fData8 + 16, 0, kPadSize);
+
+ GrCacheID cacheID(GrResourceKey::ScratchDomain(), idKey);
+ return GrResourceKey(cacheID, texture_resource_type(), 0);
+}
+
+bool GrTexture::NeedsResizing(const GrResourceKey& key) {
+ return SkToBool(key.getResourceFlags() & kStretchToPOT_TextureFlag);
+}
+
+bool GrTexture::NeedsBilerp(const GrResourceKey& key) {
+ return SkToBool(key.getResourceFlags() & kBilerp_TextureFlag);
+}