summaryrefslogtreecommitdiffstats
path: root/libs/hwui/FontRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/FontRenderer.cpp')
-rw-r--r--libs/hwui/FontRenderer.cpp205
1 files changed, 115 insertions, 90 deletions
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5b5b098..6bef7c7 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -14,7 +14,20 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
+#include "FontRenderer.h"
+
+#include "Caches.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "Glop.h"
+#include "GlopBuilder.h"
+#include "OpenGLRenderer.h"
+#include "PixelBuffer.h"
+#include "Rect.h"
+#include "renderstate/RenderState.h"
+#include "utils/Blur.h"
+#include "utils/MathUtils.h"
+#include "utils/Timing.h"
#include <SkGlyph.h>
#include <SkUtils.h>
@@ -27,30 +40,18 @@
#include <RenderScript.h>
#endif
-#include "utils/Blur.h"
-#include "utils/Timing.h"
-
-#include "Caches.h"
-#include "Debug.h"
-#include "Extensions.h"
-#include "FontRenderer.h"
-#include "OpenGLRenderer.h"
-#include "PixelBuffer.h"
-#include "Rect.h"
-
namespace android {
namespace uirenderer {
// blur inputs smaller than this constant will bypass renderscript
#define RS_MIN_INPUT_CUTOFF 10000
+#define USE_GLOPS true
+
///////////////////////////////////////////////////////////////////////////////
// TextSetupFunctor
///////////////////////////////////////////////////////////////////////////////
-status_t TextSetupFunctor::operator ()(int what, void* data) {
- Data* typedData = reinterpret_cast<Data*>(data);
- GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
-
+void TextSetupFunctor::setup(GLenum glyphFormat) {
renderer->setupDraw();
renderer->setupDrawTextGamma(paint);
renderer->setupDrawDirtyRegionsDisabled();
@@ -87,8 +88,24 @@ status_t TextSetupFunctor::operator ()(int what, void* data) {
renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
renderer->setupDrawTextGammaUniforms();
+}
- return NO_ERROR;
+void TextSetupFunctor::draw(CacheTexture& texture, bool linearFiltering) {
+ int textureFillFlags = static_cast<int>(texture.getFormat() == GL_ALPHA
+ ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+ if (linearFiltering) {
+ textureFillFlags |= TextureFillFlags::kForceFilter;
+ }
+ const Matrix4& transform = pureTranslate ? Matrix4::identity() : *(renderer->currentTransform());
+ Glop glop;
+ GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
+ .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
+ .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
+ .setTransform(renderer->currentSnapshot()->getOrthoMatrix(), transform, false)
+ .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+ .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
+ .build();
+ renderer->renderGlop(glop);
}
///////////////////////////////////////////////////////////////////////////////
@@ -97,47 +114,51 @@ status_t TextSetupFunctor::operator ()(int what, void* data) {
static bool sLogFontRendererCreate = true;
-FontRenderer::FontRenderer() :
- mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
+FontRenderer::FontRenderer()
+ : mGammaTable(nullptr)
+ , mCurrentFont(nullptr)
+ , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
+ , mCurrentCacheTexture(nullptr)
+ , mUploadTexture(false)
+ , mFunctor(nullptr)
+ , mClip(nullptr)
+ , mBounds(nullptr)
+ , mDrawn(false)
+ , mInitialized(false)
+ , mLinearFiltering(false) {
if (sLogFontRendererCreate) {
INIT_LOGD("Creating FontRenderer");
}
- mGammaTable = NULL;
- mInitialized = false;
-
- mCurrentCacheTexture = NULL;
-
- mLinearFiltering = false;
-
mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
mSmallCacheWidth = atoi(property);
}
- if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
mSmallCacheHeight = atoi(property);
}
- if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
mLargeCacheWidth = atoi(property);
}
- if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
mLargeCacheHeight = atoi(property);
}
uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
- mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
- mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
- mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
- mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
+
+ mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
+ mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
+ mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
+ mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
if (sLogFontRendererCreate) {
INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
@@ -195,7 +216,7 @@ void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
while (it.next()) {
it.value()->invalidateTextureCache(cacheTexture);
}
- cacheTexture->releaseTexture();
+ cacheTexture->releasePixelBuffer();
}
}
}
@@ -213,7 +234,7 @@ CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTex
}
}
// Could not fit glyph into current cache textures
- return NULL;
+ return nullptr;
}
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
@@ -224,7 +245,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
// so we can avoid doing extra work later on
if (glyph.fWidth == 0 || glyph.fHeight == 0) {
cachedGlyph->mIsValid = true;
- cachedGlyph->mCacheTexture = NULL;
+ cachedGlyph->mCacheTexture = nullptr;
return;
}
@@ -232,7 +253,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
// choose an appropriate cache texture list for this glyph format
SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
- Vector<CacheTexture*>* cacheTextures = NULL;
+ Vector<CacheTexture*>* cacheTextures = nullptr;
switch (format) {
case SkMask::kA8_Format:
case SkMask::kBW_Format:
@@ -287,9 +308,9 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
uint32_t cacheWidth = cacheTexture->getWidth();
if (!cacheTexture->getPixelBuffer()) {
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
// Large-glyph texture memory is allocated only as needed
- cacheTexture->allocateTexture();
+ cacheTexture->allocatePixelBuffer();
}
if (!cacheTexture->mesh()) {
cacheTexture->allocateMesh();
@@ -397,11 +418,11 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
bool allocate) {
- CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
+ CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
if (allocate) {
- Caches::getInstance().activeTexture(0);
- cacheTexture->allocateTexture();
+ Caches::getInstance().textureState().activateTexture(0);
+ cacheTexture->allocatePixelBuffer();
cacheTexture->allocateMesh();
}
@@ -446,8 +467,8 @@ void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheText
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
if (cacheTexture->getTextureId() != lastTextureId) {
lastTextureId = cacheTexture->getTextureId();
- caches.activeTexture(0);
- caches.bindTexture(lastTextureId);
+ caches.textureState().activateTexture(0);
+ caches.textureState().bindTexture(lastTextureId);
}
if (cacheTexture->upload()) {
@@ -473,7 +494,7 @@ void FontRenderer::checkTextureUpdate() {
checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
// Unbind any PBO we might have used to update textures
- caches.unbindPixelBuffer();
+ caches.pixelBufferState().unbind();
// Reset to default unpack row length to avoid affecting texture
// uploads in other parts of the renderer
@@ -485,44 +506,53 @@ void FontRenderer::checkTextureUpdate() {
}
void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
- Caches& caches = Caches::getInstance();
+ if (!mFunctor) return;
+
+#if !USE_GLOPS
+ Caches& caches = mFunctor->renderer->getCaches();
+ RenderState& renderState = mFunctor->renderer->renderState();
+#endif
+
bool first = true;
- bool force = false;
+ bool forceRebind = false;
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* texture = cacheTextures[i];
if (texture->canDraw()) {
if (first) {
- if (mFunctor) {
- TextSetupFunctor::Data functorData(texture->getFormat());
- (*mFunctor)(0, &functorData);
- }
-
checkTextureUpdate();
- caches.bindQuadIndicesBuffer();
+#if !USE_GLOPS
+ mFunctor->setup(texture->getFormat());
- if (!mDrawn) {
- // If returns true, a VBO was bound and we must
- // rebind our vertex attrib pointers even if
- // they have the same values as the current pointers
- force = caches.unbindMeshBuffer();
- }
+ renderState.meshState().bindQuadIndicesBuffer();
- caches.activeTexture(0);
+ // If returns true, a VBO was bound and we must
+ // rebind our vertex attrib pointers even if
+ // they have the same values as the current pointers
+ forceRebind = renderState.meshState().unbindMeshBuffer();
+
+ caches.textureState().activateTexture(0);
+#endif
first = false;
+ mDrawn = true;
}
+#if USE_GLOPS
+ mFunctor->draw(*texture, mLinearFiltering);
+#endif
- caches.bindTexture(texture->getTextureId());
- texture->setLinearFiltering(mLinearFiltering, false);
+#if !USE_GLOPS
+ caches.textureState().bindTexture(texture->getTextureId());
+ texture->setLinearFiltering(mLinearFiltering);
TextureVertex* mesh = texture->mesh();
- caches.bindPositionVertexPointer(force, &mesh[0].x);
- caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
- force = false;
+ MeshState& meshState = renderState.meshState();
+ meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
+ meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
GL_UNSIGNED_SHORT, texture->indices());
-
+#endif
texture->resetMesh();
+ forceRebind = false;
}
}
}
@@ -530,8 +560,6 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
void FontRenderer::issueDrawCommand() {
issueDrawCommand(mACacheTextures);
issueDrawCommand(mRGBACacheTextures);
-
- mDrawn = true;
}
void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
@@ -598,7 +626,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
DropShadow image;
image.width = 0;
image.height = 0;
- image.image = NULL;
+ image.image = nullptr;
image.penX = 0;
image.penY = 0;
@@ -607,8 +635,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
}
mDrawn = false;
- mClip = NULL;
- mBounds = NULL;
+ mClip = nullptr;
+ mBounds = nullptr;
Rect bounds;
mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
@@ -644,10 +672,10 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
// NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
// TODO: don't draw pure whitespace in the first place, and avoid needing this check
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
- Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
+ Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
// Unbind any PBO we might have used
- Caches::getInstance().unbindPixelBuffer();
+ Caches::getInstance().pixelBufferState().unbind();
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
}
@@ -661,7 +689,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
return image;
}
-void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
checkInit();
mDrawn = false;
@@ -671,8 +699,8 @@ void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor)
}
void FontRenderer::finishRender() {
- mBounds = NULL;
- mClip = NULL;
+ mBounds = nullptr;
+ mClip = nullptr;
issueDrawCommand();
}
@@ -689,7 +717,7 @@ void FontRenderer::endPrecaching() {
bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
- const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
+ const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -707,7 +735,7 @@ bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const c
bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* bounds, Functor* functor) {
+ float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -724,7 +752,7 @@ void FontRenderer::removeFont(const Font* font) {
mActiveFonts.remove(font->getDescription());
if (mCurrentFont == font) {
- mCurrentFont = NULL;
+ mCurrentFont = nullptr;
}
}
@@ -734,7 +762,7 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
- if (mRs == 0) {
+ if (mRs == nullptr) {
mRs = new RSC::RS();
// a null path is OK because there are no custom kernels used
// hence nothing gets cached by RS
@@ -746,7 +774,7 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
}
}
- if (mRs != 0) {
+ if (mRs != nullptr) {
RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
RS_ALLOCATION_MIPMAP_NONE,
@@ -770,15 +798,12 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
}
#endif
- float *gaussian = new float[2 * intRadius + 1];
- Blur::generateGaussianWeights(gaussian, intRadius);
-
- uint8_t* scratch = new uint8_t[width * height];
- Blur::horizontal(gaussian, intRadius, *image, scratch, width, height);
- Blur::vertical(gaussian, intRadius, scratch, *image, width, height);
+ std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
+ Blur::generateGaussianWeights(gaussian.get(), intRadius);
- delete[] gaussian;
- delete[] scratch;
+ std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
+ Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
+ Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
}
static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {