summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorVictoria Lease <violets@google.com>2013-06-25 14:25:17 -0700
committerVictoria Lease <violets@google.com>2013-07-31 15:50:47 -0700
commit1e546815bbb736c50679a8aefc25f48561026fc5 (patch)
tree11a3b7106638c123d052d50ce3e2a1757e004cb4 /libs
parent3a6f25512c0a682b10961a5a7428e3393ffb0b75 (diff)
downloadframeworks_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.cpp11
-rw-r--r--libs/hwui/FontRenderer.cpp297
-rw-r--r--libs/hwui/FontRenderer.h50
-rw-r--r--libs/hwui/GammaFontRenderer.h14
-rw-r--r--libs/hwui/OpenGLRenderer.cpp69
-rw-r--r--libs/hwui/PixelBuffer.h21
-rw-r--r--libs/hwui/font/CacheTexture.cpp37
-rw-r--r--libs/hwui/font/CacheTexture.h13
-rw-r--r--libs/hwui/font/FontUtil.h3
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