summaryrefslogtreecommitdiffstats
path: root/skia/gl
diff options
context:
space:
mode:
Diffstat (limited to 'skia/gl')
-rw-r--r--skia/gl/SkGL.cpp101
-rw-r--r--skia/gl/SkGL.h12
-rw-r--r--skia/gl/SkGLCanvas.cpp50
-rw-r--r--skia/gl/SkGLDevice.cpp29
-rw-r--r--skia/gl/SkGLDevice.h3
-rw-r--r--skia/gl/SkGLTextCache.cpp24
-rw-r--r--skia/gl/SkGLTextCache.h13
-rw-r--r--skia/gl/SkTextureCache.cpp53
-rw-r--r--skia/gl/SkTextureCache.h11
9 files changed, 194 insertions, 102 deletions
diff --git a/skia/gl/SkGL.cpp b/skia/gl/SkGL.cpp
index e4effba..0634709 100644
--- a/skia/gl/SkGL.cpp
+++ b/skia/gl/SkGL.cpp
@@ -151,9 +151,14 @@ static bool canBeTexture(const SkBitmap& bm, GLenum* format, GLenum* type) {
*type = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case SkBitmap::kIndex8_Config:
+#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
+ *format = GL_PALETTE8_RGBA8_OES;
+ *type = GL_UNSIGNED_BYTE; // unused I think
+#else
// we promote index to argb32
*format = GL_RGBA;
*type = GL_UNSIGNED_BYTE;
+#endif
break;
case SkBitmap::kA8_Config:
*format = GL_ALPHA;
@@ -165,8 +170,11 @@ static bool canBeTexture(const SkBitmap& bm, GLenum* format, GLenum* type) {
return true;
}
+#define SK_GL_SIZE_OF_PALETTE (256 * sizeof(SkPMColor))
+
size_t SkGL::ComputeTextureMemorySize(const SkBitmap& bitmap) {
int shift = 0;
+ size_t adder = 0;
switch (bitmap.config()) {
case SkBitmap::kARGB_8888_Config:
case SkBitmap::kRGB_565_Config:
@@ -175,22 +183,74 @@ size_t SkGL::ComputeTextureMemorySize(const SkBitmap& bitmap) {
// we're good as is
break;
case SkBitmap::kIndex8_Config:
+#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
+ // account for the colortable
+ adder = SK_GL_SIZE_OF_PALETTE;
+#else
// we promote index to argb32
shift = 2;
+#endif
break;
default:
return 0;
}
- return bitmap.getSize() << shift;
+ return (bitmap.getSize() << shift) + adder;
+}
+
+#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
+/* Fill out buffer with the compressed format GL expects from a colortable
+ based bitmap. [palette (colortable) + indices].
+
+ At the moment I always take the 8bit version, since that's what my data
+ is. I could detect that the colortable.count is <= 16, and then repack the
+ indices as nibbles to save RAM, but it would take more time (i.e. a lot
+ slower than memcpy), so I'm skipping that for now.
+
+ GL wants a full 256 palette entry, even though my ctable is only as big
+ as the colortable.count says it is. I presume it is OK to leave any
+ trailing entries uninitialized, since none of my indices should exceed
+ ctable->count().
+*/
+static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
+ SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
+
+ SkColorTable* ctable = bitmap.getColorTable();
+ uint8_t* dst = (uint8_t*)buffer;
+
+ memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
+ ctable->unlockColors(false);
+
+ // always skip a full 256 number of entries, even if we memcpy'd fewer
+ dst += SK_GL_SIZE_OF_PALETTE;
+ memcpy(dst, bitmap.getPixels(), bitmap.getSize());
+}
+#endif
+
+/* Return true if the bitmap cannot be supported in its current config as a
+ texture, and it needs to be promoted to ARGB32.
+ */
+static bool needToPromoteTo32bit(const SkBitmap& bitmap) {
+ if (bitmap.config() == SkBitmap::kIndex8_Config) {
+#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ if (SkNextPow2(w) == w && SkNextPow2(h) == h) {
+ // we can handle Indx8 if we're a POW2
+ return false;
+ }
+#endif
+ return true; // must promote to ARGB32
+ }
+ return false;
}
GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) {
SkBitmap tmpBitmap;
const SkBitmap* bitmap = &origBitmap;
- if (origBitmap.config() == SkBitmap::kIndex8_Config) {
- // we promote index to argb32
+ if (needToPromoteTo32bit(origBitmap)) {
origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
+ // now bitmap points to our temp, which has been promoted to 32bits
bitmap = &tmpBitmap;
}
@@ -200,7 +260,7 @@ GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) {
}
SkAutoLockPixels alp(*bitmap);
- if (bitmap->getPixels() == NULL) {
+ if (!bitmap->readyToDraw()) {
return 0;
}
@@ -218,15 +278,30 @@ GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) {
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
// check if we need to scale to create power-of-2 dimensions
- if (ow != nw || oh != nh) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0,
- format, type, NULL);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh,
- format, type, bitmap->getPixels());
- } else {
- // easy case, the bitmap is already pow2
- glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
- format, type, bitmap->getPixels());
+#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
+ if (SkBitmap::kIndex8_Config == bitmap->config()) {
+ size_t imagesize = bitmap->getSize() + SK_GL_SIZE_OF_PALETTE;
+ SkAutoMalloc storage(imagesize);
+
+ build_compressed_data(storage.get(), *bitmap);
+ // we only support POW2 here (GLES 1.0 restriction)
+ SkASSERT(ow == nw);
+ SkASSERT(oh == nh);
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
+ imagesize, storage.get());
+ } else // fall through to non-compressed logic
+#endif
+ {
+ if (ow != nw || oh != nh) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0,
+ format, type, NULL);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh,
+ format, type, bitmap->getPixels());
+ } else {
+ // easy case, the bitmap is already pow2
+ glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
+ format, type, bitmap->getPixels());
+ }
}
#ifdef TRACE_TEXTURE_CREATION
diff --git a/skia/gl/SkGL.h b/skia/gl/SkGL.h
index cf3c65e..d4cd3b6 100644
--- a/skia/gl/SkGL.h
+++ b/skia/gl/SkGL.h
@@ -23,16 +23,12 @@ class SkGLClipIter;
//#define TRACE_TEXTURE_CREATE
-static inline void* SkGetGLContext() {
-#ifdef ANDROID
- return (void*)eglGetCurrentContext();
-#else
- return NULL;
-#endif
-}
-
///////////////////////////////////////////////////////////////////////////////
+#if GL_OES_compressed_paletted_texture
+ #define SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
+#endif
+
#if GL_OES_fixed_point && defined(SK_SCALAR_IS_FIXED)
#define SK_GLType GL_FIXED
#else
diff --git a/skia/gl/SkGLCanvas.cpp b/skia/gl/SkGLCanvas.cpp
index d9f2201..2e93209 100644
--- a/skia/gl/SkGLCanvas.cpp
+++ b/skia/gl/SkGLCanvas.cpp
@@ -90,18 +90,11 @@ SkDevice* SkGLCanvas::createDevice(SkBitmap::Config, int width, int height,
static SkMutex gTextureCacheMutex;
static SkTextureCache gTextureCache(kTexCountMax_Default, kTexSizeMax_Default);
-static void* gTextureGLContext;
SkGLDevice::TexCache* SkGLDevice::LockTexCache(const SkBitmap& bitmap,
GLuint* name, SkPoint* size) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
- void* ctx = SkGetGLContext();
- if (gTextureGLContext != ctx) {
- gTextureGLContext = ctx;
- gTextureCache.zapAllTextures();
- }
-
SkTextureCache::Entry* entry = gTextureCache.lock(bitmap);
if (NULL != entry) {
if (name) {
@@ -141,3 +134,46 @@ void SkGLCanvas::SetTextureCacheMaxSize(size_t size) {
gTextureCache.setMaxSize(size);
}
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkGLTextCache.h"
+
+static bool deleteCachesProc(SkGlyphCache* cache, void* texturesAreValid) {
+ void* auxData;
+ if (cache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) {
+ bool valid = texturesAreValid != NULL;
+ SkGLTextCache* textCache = static_cast<SkGLTextCache*>(auxData);
+ // call this before delete, in case valid is false
+ textCache->deleteAllStrikes(valid);
+ // now free the memory for the cache itself
+ SkDELETE(textCache);
+ // now remove the entry in the glyphcache (does not call the proc)
+ cache->removeAuxProc(SkGLDevice::GlyphCacheAuxProc);
+ }
+ return false; // keep going
+}
+
+void SkGLCanvas::DeleteAllTextures() {
+ // free the textures in our cache
+
+ gTextureCacheMutex.acquire();
+ gTextureCache.deleteAllCaches(true);
+ gTextureCacheMutex.release();
+
+ // now free the textures in the font cache
+
+ SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(true));
+}
+
+void SkGLCanvas::AbandonAllTextures() {
+ // abandon the textures in our cache
+
+ gTextureCacheMutex.acquire();
+ gTextureCache.deleteAllCaches(false);
+ gTextureCacheMutex.release();
+
+ // abandon the textures in the font cache
+
+ SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(false));
+}
+
diff --git a/skia/gl/SkGLDevice.cpp b/skia/gl/SkGLDevice.cpp
index 2271b05..70968e2 100644
--- a/skia/gl/SkGLDevice.cpp
+++ b/skia/gl/SkGLDevice.cpp
@@ -21,11 +21,8 @@ public:
glTexCoordPointer(2, SK_TextGLType, 0, fTexs);
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, SK_TextGLType, 0, fVerts);
-
- fCtx = SkGetGLContext();
}
- void* ctx() const { return fCtx; }
GLenum texture() const { return fCurrTexture; }
void flush() {
@@ -68,7 +65,6 @@ private:
int fCurrQuad;
int fViewportHeight;
const SkRegion* fClip;
- void* fCtx;
};
///////////////////////////////////////////////////////////////////////////////
@@ -177,7 +173,7 @@ SkGLDevice::TexCache* SkGLDevice::setupGLPaintShader(const SkPaint& paint) {
}
bitmap.lockPixels();
- if (bitmap.getPixels() == NULL) {
+ if (!bitmap.readyToDraw()) {
return NULL;
}
@@ -327,7 +323,7 @@ void SkGLDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
TRACE_DRAW("coreDrawBitmap", this, draw);
SkAutoLockPixels alp(bitmap);
- if (bitmap.getPixels() == NULL) {
+ if (!bitmap.readyToDraw()) {
return;
}
@@ -396,7 +392,7 @@ void SkGLDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
TRACE_DRAW("coreDrawSprite", this, draw);
SkAutoLockPixels alp(bitmap);
- if (bitmap.getPixels() == NULL) {
+ if (!bitmap.readyToDraw()) {
return;
}
@@ -539,11 +535,8 @@ DONE:
#include "SkGlyphCache.h"
#include "SkGLTextCache.h"
-static void SkGL_GlyphCacheAuxProc(void* data) {
- SkGLTextCache* cache = (SkGLTextCache*)data;
-
- SkDebugf("-------------- delete text texture cache, ctx=%p\n",
- cache->getCtx());
+void SkGLDevice::GlyphCacheAuxProc(void* data) {
+ SkDebugf("-------------- delete text texture cache\n");
SkDELETE((SkGLTextCache*)data);
}
@@ -576,19 +569,13 @@ static void SkGL_Draw1Glyph(const SkDraw1Glyph& state, const SkGlyph& glyph,
void* auxData;
SkGLTextCache* textCache = NULL;
- if (gcache->getAuxProcData(SkGL_GlyphCacheAuxProc, &auxData)) {
- textCache = (SkGLTextCache*)auxData;
- if (textCache->getCtx() != procs->ctx()) {
- SkDebugf("------- textcache: old ctx %p new ctx %p\n",
- textCache->getCtx(), procs->ctx());
- SkDELETE(textCache);
- textCache = NULL;
- }
+ if (gcache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) {
+ textCache = (SkGLTextCache*)auxData;
}
if (NULL == textCache) {
// need to create one
textCache = SkNEW(SkGLTextCache);
- gcache->setAuxProc(SkGL_GlyphCacheAuxProc, textCache);
+ gcache->setAuxProc(SkGLDevice::GlyphCacheAuxProc, textCache);
}
int offset;
diff --git a/skia/gl/SkGLDevice.h b/skia/gl/SkGLDevice.h
index 9e86f3f..0fc9e47 100644
--- a/skia/gl/SkGLDevice.h
+++ b/skia/gl/SkGLDevice.h
@@ -12,6 +12,9 @@ public:
SkGLDevice(const SkBitmap& bitmap, bool offscreen);
virtual ~SkGLDevice();
+ // used to identify GLTextCache data in the glyphcache
+ static void GlyphCacheAuxProc(void* data);
+
enum TexOrientation {
kNo_TexOrientation,
kTopToBottom_TexOrientation,
diff --git a/skia/gl/SkGLTextCache.cpp b/skia/gl/SkGLTextCache.cpp
index 25f822e..141e100 100644
--- a/skia/gl/SkGLTextCache.cpp
+++ b/skia/gl/SkGLTextCache.cpp
@@ -84,7 +84,7 @@ SkGLTextCache::Strike::addGlyphAndBind(const SkGlyph& glyph,
if (fGlyphCount == kMaxGlyphCount ||
fNextFreeOffsetX + rowBytes >= fStrikeWidth) {
// this will bind the next texture for us
- SkDebugf("--- extend strike %p\n", this);
+// SkDebugf("--- extend strike %p\n", this);
strike = SkNEW_ARGS(Strike, (this, rowBytes, glyph.fHeight));
} else {
glBindTexture(GL_TEXTURE_2D, fTexName);
@@ -127,36 +127,30 @@ SkGLTextCache::Strike::addGlyphAndBind(const SkGlyph& glyph,
///////////////////////////////////////////////////////////////////////////////
SkGLTextCache::SkGLTextCache() {
- fCtx = SkGetGLContext();
bzero(fStrikeList, sizeof(fStrikeList));
}
SkGLTextCache::~SkGLTextCache() {
- SkDebugf("--- delete textcache %p\n", this);
-
- // if true, we need to not call glDeleteTexture, since they will have
- // already gone out of scope
- bool zap = SkGetGLContext() != fCtx;
+ this->deleteAllStrikes(true);
+}
+void SkGLTextCache::deleteAllStrikes(bool texturesAreValid) {
for (size_t i = 0; i < SK_ARRAY_COUNT(fStrikeList); i++) {
Strike* strike = fStrikeList[i];
while (strike != NULL) {
Strike* next = strike->fNext;
- if (zap) {
- strike->zapTexture();
+ if (!texturesAreValid) {
+ strike->abandonTexture();
}
SkDELETE(strike);
strike = next;
}
}
+ bzero(fStrikeList, sizeof(fStrikeList));
}
SkGLTextCache::Strike* SkGLTextCache::findGlyph(const SkGlyph& glyph,
int* offset) {
- if (SkGetGLContext() != fCtx) {
- SkDebugf("====== stale context for text texture\n");
- }
-
SkASSERT(glyph.fWidth != 0);
SkASSERT(glyph.fHeight != 0);
@@ -175,10 +169,6 @@ SkGLTextCache::Strike* SkGLTextCache::findGlyph(const SkGlyph& glyph,
SkGLTextCache::Strike* SkGLTextCache::addGlyphAndBind(const SkGlyph& glyph,
const uint8_t image[], int* offset) {
- if (SkGetGLContext() != fCtx) {
- SkDebugf("====== stale context for text texture\n");
- }
-
SkASSERT(image != NULL);
SkASSERT(glyph.fWidth != 0);
SkASSERT(glyph.fHeight != 0);
diff --git a/skia/gl/SkGLTextCache.h b/skia/gl/SkGLTextCache.h
index 386b274..eb552aa 100644
--- a/skia/gl/SkGLTextCache.h
+++ b/skia/gl/SkGLTextCache.h
@@ -9,8 +9,13 @@ class SkGLTextCache {
public:
SkGLTextCache();
~SkGLTextCache();
-
- void* getCtx() const { return fCtx; }
+
+ /** Delete all of the strikes in the cache. Pass true if the texture IDs are
+ still valid, in which case glDeleteTextures will be called. Pass false
+ if they are invalid (e.g. the gl-context has changed), in which case
+ they will just be abandoned.
+ */
+ void deleteAllStrikes(bool texturesAreValid);
class Strike {
public:
@@ -22,7 +27,7 @@ public:
// call this to force us to ignore the texture name in our destructor
// only call it right before our destructor
- void zapTexture() { fTexName = 0; }
+ void abandonTexture() { fTexName = 0; }
private:
// if next is non-null, its height must match our height
@@ -66,8 +71,6 @@ public:
Strike* addGlyphAndBind(const SkGlyph&, const uint8_t image[], int* offset);
private:
- void* fCtx;
-
enum {
// greater than this we won't cache
kMaxGlyphHeightShift = 9,
diff --git a/skia/gl/SkTextureCache.cpp b/skia/gl/SkTextureCache.cpp
index 6d578fe..17b37ca 100644
--- a/skia/gl/SkTextureCache.cpp
+++ b/skia/gl/SkTextureCache.cpp
@@ -1,6 +1,7 @@
#include "SkTextureCache.h"
//#define TRACE_HASH_HITS
+//#define TRACE_TEXTURE_CACHE_PURGE
SkTextureCache::Entry::Entry(const SkBitmap& bitmap)
: fName(0), fKey(bitmap), fPrev(NULL), fNext(NULL) {
@@ -37,6 +38,30 @@ SkTextureCache::~SkTextureCache() {
this->validate();
}
+void SkTextureCache::deleteAllCaches(bool texturesAreValid) {
+ this->validate();
+
+ Entry* entry = fHead;
+ while (entry) {
+ Entry* next = entry->fNext;
+ if (!texturesAreValid) {
+ entry->abandonTexture();
+ }
+ SkDELETE(entry);
+ entry = next;
+ }
+
+ fSorted.reset();
+ bzero(fHash, sizeof(fHash));
+
+ fTexCount = 0;
+ fTexSize = 0;
+
+ fTail = fHead = NULL;
+
+ this->validate();
+}
+
///////////////////////////////////////////////////////////////////////////////
int SkTextureCache::findInSorted(const Key& key) const {
@@ -237,8 +262,10 @@ void SkTextureCache::purgeIfNecessary(size_t extraSize) {
}
// now delete it
+#ifdef TRACE_TEXTURE_CACHE_PURGE
SkDebugf("---- purge texture cache %d size=%d\n",
entry->name(), entry->memSize());
+#endif
SkDELETE(entry);
// keep going
@@ -264,32 +291,6 @@ void SkTextureCache::setMaxSize(size_t size) {
///////////////////////////////////////////////////////////////////////////////
-void SkTextureCache::zapAllTextures() {
- SkDebugf("---- zapAllTextures\n");
-
- this->validate();
-
- Entry* entry = fHead;
- while (entry) {
- Entry* next = entry->fNext;
- entry->zapName();
- SkDELETE(entry);
- entry = next;
- }
-
- fSorted.reset();
- bzero(fHash, sizeof(fHash));
-
- fTexCount = 0;
- fTexSize = 0;
-
- fTail = fHead = NULL;
-
- this->validate();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
#ifdef SK_DEBUG
void SkTextureCache::validate() const {
if (0 == fTexCount) {
diff --git a/skia/gl/SkTextureCache.h b/skia/gl/SkTextureCache.h
index e4ffc78..0bc3091 100644
--- a/skia/gl/SkTextureCache.h
+++ b/skia/gl/SkTextureCache.h
@@ -17,11 +17,12 @@ public:
void setMaxCount(size_t count);
void setMaxSize(size_t size);
- /** Call this if the context has changed behind our backs, and the cache
- needs to abandon all of its existing textures. This saves us from using
- or deleting a texture created from a different context
+ /** Deletes all the caches. Pass true if the texture IDs are still valid,
+ and if so, it will call glDeleteTextures. Pass false if the texture IDs
+ are invalid (e.g. the gl-context has changed), in which case they will
+ just be abandoned.
*/
- void zapAllTextures();
+ void deleteAllCaches(bool texturesAreValid);
static int HashMask() { return kHashMask; }
@@ -90,7 +91,7 @@ public:
// call this to clear the texture name, in case the context has changed
// in which case we should't reference or delete this texture in GL
- void zapName() { fName = 0; }
+ void abandonTexture() { fName = 0; }
private:
Entry(const SkBitmap& bitmap);