diff options
author | Victoria Lease <violets@google.com> | 2013-06-25 14:25:17 -0700 |
---|---|---|
committer | Victoria Lease <violets@google.com> | 2013-07-31 15:50:47 -0700 |
commit | 1e546815bbb736c50679a8aefc25f48561026fc5 (patch) | |
tree | 11a3b7106638c123d052d50ce3e2a1757e004cb4 /libs | |
parent | 3a6f25512c0a682b10961a5a7428e3393ffb0b75 (diff) | |
download | frameworks_base-1e546815bbb736c50679a8aefc25f48561026fc5.zip frameworks_base-1e546815bbb736c50679a8aefc25f48561026fc5.tar.gz frameworks_base-1e546815bbb736c50679a8aefc25f48561026fc5.tar.bz2 |
Support RGBA fonts and bitmap fonts (and RGBA bitmap fonts)
Quite a few things going on in this commit:
- Enable bitmap strikes by default in Paint objects.
The SkPaint parameter that enables bitmap strikes was not previously
included in DEFAULT_PAINT_FLAGS. This effectively disabled bitmap
fonts. Oops! It's for the best, though, as additional work was needed
in Skia to make bitmap fonts work anyway.
- Complain if TEXTURE_BORDER_SIZE is not 1.
Our glyph cache code does not currently handle any value other than 1
here, including zero. I've added a little C preprocessor check to
prevent future engineers (including especially future-me) from
thinking that they can change this value without updating the related
code.
- Add GL_RGBA support to hwui's FontRenderer and friends
This also happened to involve some refactoring for convenience and
cleanliness.
Bug: 9577689
Change-Id: I0abd1e5a0d6623106247fb6421787e2c2f2ea19c
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/Caches.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 297 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 50 | ||||
-rw-r--r-- | libs/hwui/GammaFontRenderer.h | 14 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 69 | ||||
-rw-r--r-- | libs/hwui/PixelBuffer.h | 21 | ||||
-rw-r--r-- | libs/hwui/font/CacheTexture.cpp | 37 | ||||
-rw-r--r-- | libs/hwui/font/CacheTexture.h | 13 | ||||
-rw-r--r-- | libs/hwui/font/FontUtil.h | 3 |
9 files changed, 343 insertions, 172 deletions
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 6ac637e..df966e1 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -256,8 +256,12 @@ void Caches::dumpMemoryUsage(String8 &log) { log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(), patchCache.getMaxSize()); for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { - const uint32_t size = fontRenderer->getFontRendererSize(i); - log.appendFormat(" FontRenderer %d %8d / %8d\n", i, size, size); + const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA); + const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA); + log.appendFormat(" FontRenderer %d A8 %8d / %8d\n", i, sizeA8, sizeA8); + log.appendFormat(" FontRenderer %d RGBA %8d / %8d\n", i, sizeRGBA, sizeRGBA); + log.appendFormat(" FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA, + sizeA8 + sizeRGBA); } log.appendFormat("Other:\n"); log.appendFormat(" FboCache %8d / %8d\n", @@ -272,7 +276,8 @@ void Caches::dumpMemoryUsage(String8 &log) { total += dropShadowCache.getSize(); total += patchCache.getSize(); for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { - total += fontRenderer->getFontRendererSize(i); + total += fontRenderer->getFontRendererSize(i, GL_ALPHA); + total += fontRenderer->getFontRendererSize(i, GL_RGBA); } log.appendFormat("Total memory usage:\n"); diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 79a7a93..1b2f651 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -21,7 +21,6 @@ #include <cutils/properties.h> -#include <utils/Functor.h> #include <utils/Log.h> #ifdef ANDROID_ENABLE_RENDERSCRIPT @@ -35,6 +34,7 @@ #include "Debug.h" #include "Extensions.h" #include "FontRenderer.h" +#include "OpenGLRenderer.h" #include "PixelBuffer.h" #include "Rect.h" @@ -45,6 +45,52 @@ namespace uirenderer { #define RS_MIN_INPUT_CUTOFF 10000 /////////////////////////////////////////////////////////////////////////////// +// TextSetupFunctor +/////////////////////////////////////////////////////////////////////////////// +status_t TextSetupFunctor::operator ()(int what, void* data) { + Data* typedData = reinterpret_cast<Data*>(data); + GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA; + + renderer->setupDraw(); + renderer->setupDrawTextGamma(paint); + renderer->setupDrawDirtyRegionsDisabled(); + renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA); + switch (glyphFormat) { + case GL_ALPHA: { + renderer->setupDrawAlpha8Color(paint->getColor(), alpha); + break; + } + case GL_RGBA: { + float floatAlpha = alpha / 255.0f; + renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha); + break; + } + default: { +#if DEBUG_FONT_RENDERER + ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat); +#endif + break; + } + } + renderer->setupDrawColorFilter(); + renderer->setupDrawShader(); + renderer->setupDrawBlending(true, mode); + renderer->setupDrawProgram(); + renderer->setupDrawModelView(x, y, x, y, pureTranslate, true); + // Calling setupDrawTexture with the name 0 will enable the + // uv attributes and increase the texture unit count + // texture binding will be performed by the font renderer as + // needed + renderer->setupDrawTexture(0); + renderer->setupDrawPureColorUniforms(); + renderer->setupDrawColorFilterUniforms(); + renderer->setupDrawShaderUniforms(pureTranslate); + renderer->setupDrawTextGammaUniforms(); + + return NO_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// // FontRenderer /////////////////////////////////////////////////////////////////////////////// @@ -103,11 +149,16 @@ FontRenderer::FontRenderer() : sLogFontRendererCreate = false; } -FontRenderer::~FontRenderer() { - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - delete mCacheTextures[i]; +void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) { + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + delete cacheTextures[i]; } - mCacheTextures.clear(); + cacheTextures.clear(); +} + +FontRenderer::~FontRenderer() { + clearCacheTextures(mACacheTextures); + clearCacheTextures(mRGBACacheTextures); LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); while (it.next()) { @@ -124,15 +175,19 @@ void FontRenderer::flushAllAndInvalidate() { it.value()->invalidateTextureCache(); } - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - mCacheTextures[i]->init(); + for (uint32_t i = 0; i < mACacheTextures.size(); i++) { + mACacheTextures[i]->init(); + } + + for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) { + mRGBACacheTextures[i]->init(); } } -void FontRenderer::flushLargeCaches() { +void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) { // Start from 1; don't deallocate smallest/default texture - for (uint32_t i = 1; i < mCacheTextures.size(); i++) { - CacheTexture* cacheTexture = mCacheTextures[i]; + for (uint32_t i = 1; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; if (cacheTexture->getPixelBuffer()) { cacheTexture->init(); LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); @@ -144,11 +199,16 @@ void FontRenderer::flushLargeCaches() { } } -CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph, - uint32_t* startX, uint32_t* startY) { - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) { - return mCacheTextures[i]; +void FontRenderer::flushLargeCaches() { + flushLargeCaches(mACacheTextures); + flushLargeCaches(mRGBACacheTextures); +} + +CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures, + const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) { + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) { + return cacheTextures[i]; } } // Could not fit glyph into current cache textures @@ -169,9 +229,26 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp cachedGlyph->mIsValid = false; + // choose an appropriate cache texture list for this glyph format + SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat); + Vector<CacheTexture*>* cacheTextures = NULL; + switch (format) { + case SkMask::kA8_Format: + cacheTextures = &mACacheTextures; + break; + case SkMask::kARGB32_Format: + cacheTextures = &mRGBACacheTextures; + break; + default: +#if DEBUG_FONT_RENDERER + ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format); +#endif + return; + } + // If the glyph is too tall, don't cache it if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > - mCacheTextures[mCacheTextures.size() - 1]->getHeight()) { + (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) { ALOGE("Font size too large to fit in cache. width, height = %i, %i", (int) glyph.fWidth, (int) glyph.fHeight); return; @@ -181,14 +258,14 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp uint32_t startX = 0; uint32_t startY = 0; - CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); + CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY); if (!cacheTexture) { if (!precaching) { // If the new glyph didn't fit and we are not just trying to precache it, // clear out the cache and try again flushAllAndInvalidate(); - cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); + cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY); } if (!cacheTexture) { @@ -216,24 +293,21 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp cacheTexture->allocateMesh(); } - // Tells us whether the glyphs is B&W (1 bit per pixel) - // or anti-aliased (8 bits per pixel) - SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat); - uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map(); - uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; - - // Copy the glyph image, taking the mask format into account uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; - int stride = glyph.rowBytes(); - - uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE; - memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE); + int srcStride = glyph.rowBytes(); + // Copy the glyph image, taking the mask format into account switch (format) { case SkMask::kA8_Format: { + uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; + uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX + - TEXTURE_BORDER_SIZE; + // write leading border line + memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE); + // write glyph data if (mGammaTable) { - for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) { + for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) { row = cacheY * cacheWidth; cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0; for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { @@ -243,21 +317,55 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0; } } else { - for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) { + for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) { row = cacheY * cacheWidth; memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth); cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0; cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0; } } + // write trailing border line + row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE; + memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE); + break; + } + case SkMask::kARGB32_Format: { + // prep data lengths + const size_t formatSize = PixelBuffer::formatSize(GL_RGBA); + const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE; + size_t rowSize = formatSize * glyph.fWidth; + // prep advances + size_t dstStride = formatSize * cacheWidth; + // prep indices + // - we actually start one row early, and then increment before first copy + uint8_t* src = &bitmapBuffer[0 - srcStride]; + uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)]; + uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)]; + uint8_t* dstL = dst - borderSize; + uint8_t* dstR = dst + rowSize; + // write leading border line + memset(dstL, 0, rowSize + 2 * borderSize); + // write glyph data + while (dst < dstEnd) { + memset(dstL += dstStride, 0, borderSize); // leading border column + memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data + memset(dstR += dstStride, 0, borderSize); // trailing border column + } + // write trailing border line + memset(dstL, 0, rowSize + 2 * borderSize); break; } case SkMask::kBW_Format: { + uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; + uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX + - TEXTURE_BORDER_SIZE; static const uint8_t COLORS[2] = { 0, 255 }; - + // write leading border line + memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE); + // write glyph data for (cacheY = startY; cacheY < endY; cacheY++) { cacheX = startX; - int rowBytes = stride; + int rowBytes = srcStride; uint8_t* buffer = bitmapBuffer; row = cacheY * cacheWidth; @@ -270,23 +378,24 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp } cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0; - bitmapBuffer += stride; + bitmapBuffer += srcStride; } + // write trailing border line + row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE; + memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE); break; } default: - ALOGW("Unkown glyph format: 0x%x", format); + ALOGW("Unknown glyph format: 0x%x", format); break; } - row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE; - memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE); - cachedGlyph->mIsValid = true; } -CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { - CacheTexture* cacheTexture = new CacheTexture(width, height, gMaxNumberOfQuads); +CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format, + bool allocate) { + CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads); if (allocate) { Caches::getInstance().activeTexture(0); @@ -298,17 +407,23 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool alloc } void FontRenderer::initTextTexture() { - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - delete mCacheTextures[i]; - } - mCacheTextures.clear(); + clearCacheTextures(mACacheTextures); + clearCacheTextures(mRGBACacheTextures); mUploadTexture = false; - mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true)); - mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false)); - mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false)); - mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, false)); - mCurrentCacheTexture = mCacheTextures[0]; + mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, + GL_ALPHA, true)); + mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, + GL_ALPHA, false)); + mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, + GL_ALPHA, false)); + mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, + GL_ALPHA, false)); + mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, + GL_RGBA, false)); + mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, + GL_RGBA, false)); + mCurrentCacheTexture = mACacheTextures[0]; } // We don't want to allocate anything unless we actually draw text @@ -322,20 +437,10 @@ void FontRenderer::checkInit() { mInitialized = true; } -void FontRenderer::checkTextureUpdate() { - if (!mUploadTexture) { - return; - } - - Caches& caches = Caches::getInstance(); - GLuint lastTextureId = 0; - - bool resetPixelStore = false; - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - // Iterate over all the cache textures and see which ones need to be updated - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - CacheTexture* cacheTexture = mCacheTextures[i]; +void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures, + bool& resetPixelStore, GLuint& lastTextureId) { + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) { if (cacheTexture->getTextureId() != lastTextureId) { lastTextureId = cacheTexture->getTextureId(); @@ -346,13 +451,24 @@ void FontRenderer::checkTextureUpdate() { if (cacheTexture->upload()) { resetPixelStore = true; } - -#if DEBUG_FONT_RENDERER - ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d", - i, x, y, width, height); -#endif } } +} + +void FontRenderer::checkTextureUpdate() { + if (!mUploadTexture) { + return; + } + + Caches& caches = Caches::getInstance(); + GLuint lastTextureId = 0; + + bool resetPixelStore = false; + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + // Iterate over all the cache textures and see which ones need to be updated + checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId); + checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId); // Unbind any PBO we might have used to update textures caches.unbindPixelBuffer(); @@ -366,18 +482,18 @@ void FontRenderer::checkTextureUpdate() { mUploadTexture = false; } -void FontRenderer::issueDrawCommand() { +void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) { + Caches& caches = Caches::getInstance(); bool first = true; bool force = false; - - GLuint lastId = 0; - Caches& caches = Caches::getInstance(); - - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - CacheTexture* texture = mCacheTextures[i]; + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* texture = cacheTextures[i]; if (texture->canDraw()) { if (first) { - if (mFunctor) (*mFunctor)(0, NULL); + if (mFunctor) { + TextSetupFunctor::Data functorData(texture->getFormat()); + (*mFunctor)(0, &functorData); + } checkTextureUpdate(); caches.bindIndicesBuffer(); @@ -407,6 +523,11 @@ void FontRenderer::issueDrawCommand() { texture->resetMesh(); } } +} + +void FontRenderer::issueDrawCommand() { + issueDrawCommand(mACacheTextures); + issueDrawCommand(mRGBACacheTextures); mDrawn = true; } @@ -582,13 +703,13 @@ bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *t bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path, - float hOffset, float vOffset, Rect* bounds) { + float hOffset, float vOffset, Rect* bounds, Functor* functor) { if (!mCurrentFont) { ALOGE("No font set"); return false; } - initRender(clip, bounds, NULL); + initRender(clip, bounds, functor); mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset); finishRender(); @@ -646,10 +767,10 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int delete[] scratch; } -uint32_t FontRenderer::getCacheSize() const { +static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) { uint32_t size = 0; - for (uint32_t i = 0; i < mCacheTextures.size(); i++) { - CacheTexture* cacheTexture = mCacheTextures[i]; + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; if (cacheTexture && cacheTexture->getPixelBuffer()) { size += cacheTexture->getPixelBuffer()->getSize(); } @@ -657,5 +778,19 @@ uint32_t FontRenderer::getCacheSize() const { return size; } +uint32_t FontRenderer::getCacheSize(GLenum format) const { + switch (format) { + case GL_ALPHA: { + return calculateCacheSize(mACacheTextures); + } + case GL_RGBA: { + return calculateCacheSize(mRGBACacheTextures); + } + default: { + return 0; + } + } +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index c1072ed..aca47b4 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -17,6 +17,7 @@ #ifndef ANDROID_HWUI_FONT_RENDERER_H #define ANDROID_HWUI_FONT_RENDERER_H +#include <utils/Functor.h> #include <utils/LruCache.h> #include <utils/Vector.h> #include <utils/StrongPointer.h> @@ -46,8 +47,40 @@ class Functor; namespace android { namespace uirenderer { +class OpenGLRenderer; + +/////////////////////////////////////////////////////////////////////////////// +// TextSetupFunctor +/////////////////////////////////////////////////////////////////////////////// +class TextSetupFunctor: public Functor { +public: + struct Data { + Data(GLenum glyphFormat) : glyphFormat(glyphFormat) { + } + + GLenum glyphFormat; + }; + + TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate, + int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(), + renderer(renderer), x(x), y(y), pureTranslate(pureTranslate), + alpha(alpha), mode(mode), paint(paint) { + } + ~TextSetupFunctor() { } + + status_t operator ()(int what, void* data); + + OpenGLRenderer* renderer; + float x; + float y; + bool pureTranslate; + int alpha; + SkXfermode::Mode mode; + SkPaint* paint; +}; + /////////////////////////////////////////////////////////////////////////////// -// Renderer +// FontRenderer /////////////////////////////////////////////////////////////////////////////// class FontRenderer { @@ -55,6 +88,7 @@ public: FontRenderer(); ~FontRenderer(); + void flushLargeCaches(Vector<CacheTexture*>& cacheTextures); void flushLargeCaches(); void setGammaTable(const uint8_t* gammaTable) { @@ -73,7 +107,8 @@ public: // bounds is an out parameter bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, - uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds); + uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds, + Functor* functor); struct DropShadow { DropShadow() { }; @@ -100,7 +135,7 @@ public: mLinearFiltering = linearFiltering; } - uint32_t getCacheSize() const; + uint32_t getCacheSize(GLenum format) const; private: friend class Font; @@ -110,10 +145,11 @@ private: void allocateTextureMemory(CacheTexture* cacheTexture); void deallocateTextureMemory(CacheTexture* cacheTexture); void initTextTexture(); - CacheTexture* createCacheTexture(int width, int height, bool allocate); + CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate); void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t *retOriginX, uint32_t *retOriginY, bool precaching); - CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY); + CacheTexture* cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph, + uint32_t* startX, uint32_t* startY); void flushAllAndInvalidate(); @@ -121,6 +157,7 @@ private: void initRender(const Rect* clip, Rect* bounds, Functor* functor); void finishRender(); + void issueDrawCommand(Vector<CacheTexture*>& cacheTextures); void issueDrawCommand(); void appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2, float u2, float v2, @@ -148,7 +185,8 @@ private: uint32_t mLargeCacheWidth; uint32_t mLargeCacheHeight; - Vector<CacheTexture*> mCacheTextures; + Vector<CacheTexture*> mACacheTextures; + Vector<CacheTexture*> mRGBACacheTextures; Font* mCurrentFont; LruCache<Font::FontDescription, Font*> mActiveFonts; diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h index bbfa66d..46cfd04 100644 --- a/libs/hwui/GammaFontRenderer.h +++ b/libs/hwui/GammaFontRenderer.h @@ -35,7 +35,7 @@ public: virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0; virtual uint32_t getFontRendererCount() const = 0; - virtual uint32_t getFontRendererSize(uint32_t fontRenderer) const = 0; + virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0; virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0; virtual void setupProgram(ProgramDescription& description, Program* program) const = 0; @@ -81,8 +81,8 @@ public: return 1; } - uint32_t getFontRendererSize(uint32_t fontRenderer) const { - return mRenderer ? mRenderer->getCacheSize() : 0; + uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const { + return mRenderer ? mRenderer->getCacheSize(format) : 0; } void describe(ProgramDescription& description, const SkPaint* paint) const; @@ -128,8 +128,8 @@ public: return 1; } - uint32_t getFontRendererSize(uint32_t fontRenderer) const { - return mRenderer ? mRenderer->getCacheSize() : 0; + uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const { + return mRenderer ? mRenderer->getCacheSize(format) : 0; } void describe(ProgramDescription& description, const SkPaint* paint) const { @@ -162,13 +162,13 @@ public: return kGammaCount; } - uint32_t getFontRendererSize(uint32_t fontRenderer) const { + uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const { if (fontRenderer >= kGammaCount) return 0; FontRenderer* renderer = mRenderers[fontRenderer]; if (!renderer) return 0; - return renderer->getCacheSize(); + return renderer->getCacheSize(format); } void describe(ProgramDescription& description, const SkPaint* paint) const { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index bc00ce8..be0cd2a 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2825,48 +2825,6 @@ bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; } -class TextSetupFunctor: public Functor { -public: - TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate, - int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(), - renderer(renderer), x(x), y(y), pureTranslate(pureTranslate), - alpha(alpha), mode(mode), paint(paint) { - } - ~TextSetupFunctor() { } - - status_t operator ()(int what, void* data) { - renderer.setupDraw(); - renderer.setupDrawTextGamma(paint); - renderer.setupDrawDirtyRegionsDisabled(); - renderer.setupDrawWithTexture(true); - renderer.setupDrawAlpha8Color(paint->getColor(), alpha); - renderer.setupDrawColorFilter(); - renderer.setupDrawShader(); - renderer.setupDrawBlending(true, mode); - renderer.setupDrawProgram(); - renderer.setupDrawModelView(x, y, x, y, pureTranslate, true); - // Calling setupDrawTexture with the name 0 will enable the - // uv attributes and increase the texture unit count - // texture binding will be performed by the font renderer as - // needed - renderer.setupDrawTexture(0); - renderer.setupDrawPureColorUniforms(); - renderer.setupDrawColorFilterUniforms(); - renderer.setupDrawShaderUniforms(pureTranslate); - renderer.setupDrawTextGammaUniforms(); - - return NO_ERROR; - } - - OpenGLRenderer& renderer; - float x; - float y; - bool pureTranslate; - int alpha; - SkXfermode::Mode mode; - SkPaint* paint; -}; - status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint) { if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) { @@ -2912,7 +2870,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count const bool hasActiveLayer = hasLayer(); - TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint); + TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, positions, hasActiveLayer ? &bounds : NULL, &functor)) { if (hasActiveLayer) { @@ -3003,7 +2961,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); bool status; - TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint); + TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); // don't call issuedrawcommand, do it at end of batch bool forceFinish = (drawOpMode != kDrawOpMode_Defer); @@ -3045,26 +3003,7 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - - setupDraw(); - setupDrawTextGamma(paint); - setupDrawDirtyRegionsDisabled(); - setupDrawWithTexture(true); - setupDrawAlpha8Color(paint->getColor(), alpha); - setupDrawColorFilter(); - setupDrawShader(); - setupDrawBlending(true, mode); - setupDrawProgram(); - setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true); - // Calling setupDrawTexture with the name 0 will enable the - // uv attributes and increase the texture unit count - // texture binding will be performed by the font renderer as - // needed - setupDrawTexture(0); - setupDrawPureColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderUniforms(false); - setupDrawTextGammaUniforms(); + TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint); const Rect* clip = &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); @@ -3072,7 +3011,7 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co const bool hasActiveLayer = hasLayer(); if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, - hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) { + hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) { if (hasActiveLayer) { currentTransform().mapRect(bounds); dirtyLayerUnchecked(bounds, getRegion()); diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h index 32d5417..9725a61 100644 --- a/libs/hwui/PixelBuffer.h +++ b/libs/hwui/PixelBuffer.h @@ -112,13 +112,25 @@ public: virtual uint8_t* getMappedPointer() const = 0; /** - * Upload the specified rectangle of this pixe buffer as a + * Upload the specified rectangle of this pixel buffer as a * GL_TEXTURE_2D texture. Calling this method will trigger * an unmap() if necessary. */ virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0; /** + * Upload the specified rectangle of this pixel buffer as a + * GL_TEXTURE_2D texture. Calling this method will trigger + * an unmap() if necessary. + * + * This is a convenience function provided to save callers the + * trouble of computing the offset parameter. + */ + void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { + upload(x, y, width, height, getOffset(x, y)); + } + + /** * Returns the width of the render buffer in pixels. */ uint32_t getWidth() const { @@ -140,6 +152,13 @@ public: } /** + * Returns the offset of a pixel in this pixel buffer, in bytes. + */ + uint32_t getOffset(uint32_t x, uint32_t y) const { + return (y * mWidth + x) * formatSize(mFormat); + } + + /** * Returns the number of bytes per pixel in the specified format. * * Supported formats: diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 5f15724..55503ce 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -108,8 +108,8 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) // CacheTexture /////////////////////////////////////////////////////////////////////////////// -CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount) : - mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), +CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) : + mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format), mLinearFiltering(false), mDirty(false), mNumGlyphs(0), mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount), mCaches(Caches::getInstance()) { @@ -182,7 +182,7 @@ void CacheTexture::allocateMesh() { void CacheTexture::allocateTexture() { if (!mTexture) { - mTexture = PixelBuffer::create(GL_ALPHA, mWidth, mHeight); + mTexture = PixelBuffer::create(mFormat, mWidth, mHeight); } if (!mTextureId) { @@ -191,8 +191,8 @@ void CacheTexture::allocateTexture() { mCaches.bindTexture(mTextureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Initialize texture dimensions - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0, - GL_ALPHA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, + mFormat, GL_UNSIGNED_BYTE, 0); const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); @@ -217,8 +217,7 @@ bool CacheTexture::upload() { glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth); } - mTexture->upload(x, y, width, height, y * mWidth + x); - + mTexture->upload(x, y, width, height); setDirty(false); return mHasES3; @@ -232,6 +231,30 @@ void CacheTexture::setDirty(bool dirty) { } bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { + switch (glyph.fMaskFormat) { + case SkMask::kA8_Format: + if (mFormat != GL_ALPHA) { +#if DEBUG_FONT_RENDERER + ALOGD("fitBitmap: kA8_Format glyph cannot fit into texture format %x", mFormat); +#endif + return false; + } + break; + case SkMask::kARGB32_Format: + if (mFormat != GL_RGBA) { +#if DEBUG_FONT_RENDERER + ALOGD("fitBitmap: kARGB32_Format glyph cannot fit into texture format %x", mFormat); +#endif + return false; + } + break; + default: +#if DEBUG_FONT_RENDERER + ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat); +#endif + return false; + } + if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) { return false; } diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 208b1ff..028b611 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -24,6 +24,7 @@ #include <utils/Log.h> #include "FontUtil.h" +#include "../PixelBuffer.h" #include "../Rect.h" #include "../Vertex.h" @@ -31,7 +32,6 @@ namespace android { namespace uirenderer { class Caches; -class PixelBuffer; /** * CacheBlock is a node in a linked list of current free space areas in a CacheTexture. @@ -74,7 +74,7 @@ struct CacheBlock { class CacheTexture { public: - CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount); + CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount); ~CacheTexture(); void reset(); @@ -100,6 +100,14 @@ public: return mHeight; } + inline GLenum getFormat() const { + return mFormat; + } + + inline uint32_t getOffset(uint16_t x, uint16_t y) const { + return (y * mWidth + x) * PixelBuffer::formatSize(mFormat); + } + inline const Rect* getDirtyRect() const { return &mDirtyRect; } @@ -173,6 +181,7 @@ private: GLuint mTextureId; uint16_t mWidth; uint16_t mHeight; + GLenum mFormat; bool mLinearFiltering; bool mDirty; uint16_t mNumGlyphs; diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h index f758666..cdcb23c 100644 --- a/libs/hwui/font/FontUtil.h +++ b/libs/hwui/font/FontUtil.h @@ -31,6 +31,9 @@ #define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512 #define TEXTURE_BORDER_SIZE 1 +#if TEXTURE_BORDER_SIZE != 1 +# error TEXTURE_BORDER_SIZE other than 1 is not currently supported +#endif #define CACHE_BLOCK_ROUNDING_SIZE 4 |