diff options
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/font/Font.cpp | 81 | ||||
-rw-r--r-- | libs/hwui/font/Font.h | 3 | ||||
-rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 10 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java | 64 |
7 files changed, 166 insertions, 35 deletions
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 710f12f..16218fa 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -406,7 +406,7 @@ status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, i if (addDrawOp(op)) { // precache if draw operation is visible FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); - fontRenderer.precache(paint, text, count, *mSnapshot->transform); + fontRenderer.precache(paint, text, count, mat4::identity()); } return DrawGlInfo::kStatusDone; } @@ -423,7 +423,7 @@ status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int if (addDrawOp(op)) { // precache if draw operation is visible FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); - fontRenderer.precache(paint, text, count, *mSnapshot->transform); + fontRenderer.precache(paint, text, count, mat4::identity()); } return DrawGlInfo::kStatusDone; } @@ -442,7 +442,9 @@ status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int cou if (addDrawOp(op)) { // precache if draw operation is visible FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); - fontRenderer.precache(paint, text, count, *mSnapshot->transform); + const bool pureTranslate = mSnapshot->transform->isPureTranslate(); + fontRenderer.precache(paint, text, count, + pureTranslate ? mat4::identity() : *mSnapshot->transform); } return DrawGlInfo::kStatusDone; } diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index db65b88..d5ea0f9 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -180,7 +180,17 @@ CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph, void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) { checkInit(); + + // If the glyph bitmap is empty let's assum the glyph is valid + // so we can avoid doing extra work later on + if (glyph.fWidth == 0 || glyph.fHeight == 0) { + cachedGlyph->mIsValid = true; + cachedGlyph->mCacheTexture = NULL; + return; + } + cachedGlyph->mIsValid = false; + // If the glyph is too tall, don't cache it if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheTextures[mCacheTextures.size() - 1]->getHeight()) { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index fb77ef6..7e9734f 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2151,17 +2151,17 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const alpha *= mSnapshot->alpha; - mCaches.activeTexture(0); - Texture* texture = mCaches.textureCache.get(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; - const AutoTexture autoCleanup(texture); - texture->setWrap(GL_CLAMP_TO_EDGE, true); - texture->setFilter(GL_LINEAR, true); - const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { + mCaches.activeTexture(0); + Texture* texture = mCaches.textureCache.get(bitmap); + if (!texture) return DrawGlInfo::kStatusDone; + const AutoTexture autoCleanup(texture); + texture->setWrap(GL_CLAMP_TO_EDGE, true); + texture->setFilter(GL_LINEAR, true); + const bool pureTranslate = mSnapshot->transform->isPureTranslate(); // Mark the current layer dirty where we are going to draw the patch if (hasLayer() && mesh->hasEmptyQuads) { @@ -2666,6 +2666,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, const float oldX = x; const float oldY = y; const bool pureTranslate = mSnapshot->transform->isPureTranslate(); + const bool isPerspective = mSnapshot->transform->isPerspective(); if (CC_LIKELY(pureTranslate)) { x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); @@ -2687,8 +2688,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, fontRenderer.setFont(paint, pureTranslate ? mat4::identity() : *mSnapshot->transform); // Pick the appropriate texture filtering - bool linearFilter = !mSnapshot->transform->isPureTranslate() || - fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; + bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; // The font renderer will always use texture unit 0 mCaches.activeTexture(0); @@ -2701,13 +2701,13 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, setupDrawShader(); setupDrawBlending(true, mode); setupDrawProgram(); - setupDrawModelView(x, y, x, y, true, true); + setupDrawModelView(x, y, x, y, !isPerspective, true); // See comment above; the font renderer must use texture unit 0 // assert(mTextureUnit == 0) setupDrawTexture(fontRenderer.getTexture(linearFilter)); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); - setupDrawShaderUniforms(true); + setupDrawShaderUniforms(!isPerspective); setupDrawTextGammaUniforms(); const Rect* clip = mSnapshot->hasPerspectiveTransform() ? NULL : mSnapshot->clipRect; @@ -2727,6 +2727,9 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, } if (status && hasActiveLayer) { + if (isPerspective) { + mSnapshot->transform->mapRect(bounds); + } dirtyLayerUnchecked(bounds, getRegion()); } diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index ea9fd03..d48b612 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -52,6 +52,7 @@ Font::FontDescription::FontDescription(const SkPaint* paint, const mat4& matrix) mStyle = paint->getStyle(); mStrokeWidth = paint->getStrokeWidth(); mAntiAliasing = paint->isAntiAlias(); + mLookupTransform.reset(); mLookupTransform[SkMatrix::kMScaleX] = matrix.data[mat4::kScaleX]; mLookupTransform[SkMatrix::kMScaleY] = matrix.data[mat4::kScaleY]; mLookupTransform[SkMatrix::kMSkewX] = matrix.data[mat4::kSkewX]; @@ -165,7 +166,7 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { float nPenX = x + glyph->mBitmapLeft; - float nPenY = y + (glyph->mBitmapTop + glyph->mBitmapHeight); + float nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; float width = (float) glyph->mBitmapWidth; float height = (float) glyph->mBitmapHeight; @@ -181,6 +182,38 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, nPenX, nPenY - height, u1, v1, glyph->mCacheTexture); } +void Font::drawCachedGlyphPerspective(CachedGlyphInfo* glyph, int x, int y, + uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { + SkMatrix i; + if (!mDescription.mLookupTransform.invert(&i)) { + return; + } + + SkPoint p[4]; + p[0].set(glyph->mBitmapLeft, glyph->mBitmapTop + glyph->mBitmapHeight); + p[1].set(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop + glyph->mBitmapHeight); + p[2].set(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop); + p[3].set(glyph->mBitmapLeft, glyph->mBitmapTop); + + i.mapPoints(p, 4); + + p[0].offset(x, y); + p[1].offset(x, y); + p[2].offset(x, y); + p[3].offset(x, y); + + float u1 = glyph->mBitmapMinU; + float u2 = glyph->mBitmapMaxU; + float v1 = glyph->mBitmapMinV; + float v2 = glyph->mBitmapMaxV; + + mState->appendRotatedMeshQuad( + p[0].fX, p[0].fY, u1, v2, + p[1].fX, p[1].fY, u2, v2, + p[2].fX, p[2].fY, u2, v1, + p[3].fX, p[3].fY, u1, v1, glyph->mCacheTexture); +} + void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { int nPenX = x + glyph->mBitmapLeft; @@ -307,7 +340,7 @@ void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); prevRsbDelta = cachedGlyph->mRsbDelta; - if (cachedGlyph->mIsValid) { + if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent); } @@ -328,7 +361,6 @@ void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t le } void Font::precache(SkPaint* paint, const char* text, int numGlyphs) { - if (numGlyphs == 0 || text == NULL) { return; } @@ -357,14 +389,18 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len static RenderGlyph gRenderGlyph[] = { &android::uirenderer::Font::drawCachedGlyph, + &android::uirenderer::Font::drawCachedGlyphPerspective, + &android::uirenderer::Font::drawCachedGlyphBitmap, &android::uirenderer::Font::drawCachedGlyphBitmap, + &android::uirenderer::Font::measureCachedGlyph, &android::uirenderer::Font::measureCachedGlyph }; - RenderGlyph render = gRenderGlyph[mode]; + RenderGlyph render = gRenderGlyph[(mode << 1) + mTransform.isPerspective()]; text += start; int glyphsCount = 0; + const bool applyTransform = !mTransform.isIdentity() && !mTransform.isPerspective(); const SkPaint::Align align = paint->getTextAlign(); while (glyphsCount < numGlyphs) { @@ -377,12 +413,13 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); - // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage - if (cachedGlyph->mIsValid) { + // If it's still not valid, we couldn't cache it, so we shouldn't + // draw garbage; also skip empty glyphs (spaces) + if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { float penX = x + positions[(glyphsCount << 1)]; float penY = y + positions[(glyphsCount << 1) + 1]; - if (!mTransform.isIdentity()) { + if (applyTransform) { mTransform.mapPoint(penX, penY); } @@ -424,15 +461,18 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp glyph->mBitmapWidth = skiaGlyph.fWidth; glyph->mBitmapHeight = skiaGlyph.fHeight; - uint32_t cacheWidth = glyph->mCacheTexture->getWidth(); - uint32_t cacheHeight = glyph->mCacheTexture->getHeight(); + bool empty = skiaGlyph.fWidth == 0 || skiaGlyph.fHeight == 0; + if (!empty) { + uint32_t cacheWidth = glyph->mCacheTexture->getWidth(); + uint32_t cacheHeight = glyph->mCacheTexture->getHeight(); - glyph->mBitmapMinU = startX / (float) cacheWidth; - glyph->mBitmapMinV = startY / (float) cacheHeight; - glyph->mBitmapMaxU = endX / (float) cacheWidth; - glyph->mBitmapMaxV = endY / (float) cacheHeight; + glyph->mBitmapMinU = startX / (float) cacheWidth; + glyph->mBitmapMinV = startY / (float) cacheHeight; + glyph->mBitmapMaxU = endX / (float) cacheWidth; + glyph->mBitmapMaxV = endY / (float) cacheHeight; - mState->setTextureDirty(); + mState->setTextureDirty(); + } } CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) { @@ -440,8 +480,8 @@ CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching mCachedGlyphs.add(glyph, newGlyph); const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph, &mDescription.mLookupTransform); - newGlyph->mGlyphIndex = skiaGlyph.fID; newGlyph->mIsValid = false; + newGlyph->mGlyphIndex = skiaGlyph.fID; updateGlyphCache(paint, skiaGlyph, newGlyph, precaching); @@ -452,14 +492,13 @@ Font* Font::create(FontRenderer* state, const SkPaint* paint, const mat4& matrix FontDescription description(paint, matrix); Font* font = state->mActiveFonts.get(description); - if (font) { - font->mTransform.load(matrix); - return font; + if (!font) { + font = new Font(state, description); + state->mActiveFonts.put(description, font); } + font->mTransform.load(matrix); - Font* newFont = new Font(state, description); - state->mActiveFonts.put(description, newFont); - return newFont; + return font; } }; // namespace uirenderer diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h index 26b10afd..542b552 100644 --- a/libs/hwui/font/Font.h +++ b/libs/hwui/font/Font.h @@ -124,6 +124,9 @@ private: void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos); + void drawCachedGlyphPerspective(CachedGlyphInfo* glyph, int x, int y, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, + Rect* bounds, const float* pos); void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos); diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 0c59f30..46a539e 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -51,6 +51,16 @@ </activity> <activity + android:name="Rotate3dTextActivity" + android:label="Text/3D Rotation" + android:theme="@android:style/Theme.Holo.Light"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="NoAATextActivity" android:label="Text/Aliased"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java new file mode 100644 index 0000000..93b8705 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class Rotate3dTextActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Rotate3dTextView view = new Rotate3dTextView(this); + setContentView(view); + } + + public static class Rotate3dTextView extends View { + private static final String TEXT = "Hello libhwui! "; + + private final Paint mPaint; + + public Rotate3dTextView(Context c) { + super(c); + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(50.0f); + mPaint.setTextAlign(Paint.Align.CENTER); + + setRotationY(45.0f); + setScaleX(2.0f); + setScaleY(2.0f); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.drawText(TEXT, getWidth() / 2.0f, getHeight() / 2.0f, mPaint); + + invalidate(); + } + } +} |