diff options
Diffstat (limited to 'skia/gl')
-rw-r--r-- | skia/gl/SkGL.cpp | 101 | ||||
-rw-r--r-- | skia/gl/SkGL.h | 12 | ||||
-rw-r--r-- | skia/gl/SkGLCanvas.cpp | 50 | ||||
-rw-r--r-- | skia/gl/SkGLDevice.cpp | 29 | ||||
-rw-r--r-- | skia/gl/SkGLDevice.h | 3 | ||||
-rw-r--r-- | skia/gl/SkGLTextCache.cpp | 24 | ||||
-rw-r--r-- | skia/gl/SkGLTextCache.h | 13 | ||||
-rw-r--r-- | skia/gl/SkTextureCache.cpp | 53 | ||||
-rw-r--r-- | skia/gl/SkTextureCache.h | 11 |
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); |