diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/androidfw/tests/ObbFile_test.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Android.mk | 11 | ||||
-rw-r--r-- | libs/hwui/Caches.cpp | 54 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 11 | ||||
-rw-r--r-- | libs/hwui/Debug.h | 3 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 140 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 6 | ||||
-rw-r--r-- | libs/hwui/Extensions.h | 9 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 30 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 9 | ||||
-rw-r--r-- | libs/hwui/GammaFontRenderer.cpp | 126 | ||||
-rw-r--r-- | libs/hwui/GammaFontRenderer.h | 147 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/GradientCache.h | 4 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.h | 3 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 279 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 94 | ||||
-rw-r--r-- | libs/hwui/Program.h | 15 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 80 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 29 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 4 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 23 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.h | 21 |
25 files changed, 798 insertions, 328 deletions
diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp index 09d4d7d..2c9f650 100644 --- a/libs/androidfw/tests/ObbFile_test.cpp +++ b/libs/androidfw/tests/ObbFile_test.cpp @@ -22,6 +22,8 @@ #include <gtest/gtest.h> +#include <sys/types.h> +#include <sys/stat.h> #include <fcntl.h> #include <string.h> @@ -43,7 +45,7 @@ protected: mFileName = new char[totalLen]; snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME); - int fd = ::open(mFileName, O_CREAT | O_TRUNC); + int fd = ::open(mFileName, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) { FAIL() << "Couldn't create " << mFileName << " for tests"; } diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 5ec3983..a54c188 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -40,12 +40,19 @@ ifeq ($(USE_OPENGL_RENDERER),true) external/skia/include/utils LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES - LOCAL_CFLAGS += -fvisibility=hidden LOCAL_MODULE_CLASS := SHARED_LIBRARIES LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui LOCAL_MODULE := libhwui LOCAL_MODULE_TAGS := optional - + + ifndef HWUI_COMPILE_SYMBOLS + LOCAL_CFLAGS += -fvisibility=hidden + endif + + ifdef HWUI_COMPILE_FOR_PERF + LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs + endif + include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index f210820..258ced0 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -49,6 +49,7 @@ namespace uirenderer { Caches::Caches(): Singleton<Caches>(), mInitialized(false) { init(); + initFont(); initExtensions(); initConstraints(); @@ -74,6 +75,8 @@ void Caches::init() { mTexCoordsArrayEnabled = false; + glDisable(GL_SCISSOR_TEST); + scissorEnabled = false; mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0; glActiveTexture(gTextureUnits[0]); @@ -89,6 +92,10 @@ void Caches::init() { mInitialized = true; } +void Caches::initFont() { + fontRenderer = GammaFontRenderer::createRenderer(); +} + void Caches::initExtensions() { if (extensions.hasDebugMarker()) { eventMark = glInsertEventMarkerEXT; @@ -169,8 +176,8 @@ void Caches::dumpMemoryUsage(String8 &log) { arcShapeCache.getSize(), arcShapeCache.getMaxSize()); log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(), dropShadowCache.getMaxSize()); - for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { - const uint32_t size = fontRenderer.getFontRendererSize(i); + 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); } log.appendFormat("Other:\n"); @@ -190,8 +197,8 @@ void Caches::dumpMemoryUsage(String8 &log) { total += ovalShapeCache.getSize(); total += rectShapeCache.getSize(); total += arcShapeCache.getSize(); - for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { - total += fontRenderer.getFontRendererSize(i); + for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { + total += fontRenderer->getFontRendererSize(i); } log.appendFormat("Total memory usage:\n"); @@ -244,10 +251,10 @@ void Caches::flush(FlushMode mode) { patchCache.clear(); dropShadowCache.clear(); gradientCache.clear(); - fontRenderer.clear(); + fontRenderer->clear(); // fall through case kFlushMode_Moderate: - fontRenderer.flush(); + fontRenderer->flush(); textureCache.flush(); pathCache.clear(); roundRectShapeCache.clear(); @@ -351,14 +358,45 @@ void Caches::activeTexture(GLuint textureUnit) { } } -void Caches::setScissor(GLint x, GLint y, GLint width, GLint height) { - if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) { +bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) { + if (scissorEnabled && (x != mScissorX || y != mScissorY || + width != mScissorWidth || height != mScissorHeight)) { + glScissor(x, y, width, height); mScissorX = x; mScissorY = y; mScissorWidth = width; mScissorHeight = height; + + return true; + } + return false; +} + +bool Caches::enableScissor() { + if (!scissorEnabled) { + glEnable(GL_SCISSOR_TEST); + scissorEnabled = true; + return true; + } + return false; +} + +bool Caches::disableScissor() { + if (scissorEnabled) { + glDisable(GL_SCISSOR_TEST); + scissorEnabled = false; + return true; + } + return false; +} + +void Caches::setScissorEnabled(bool enabled) { + if (scissorEnabled != enabled) { + if (enabled) glEnable(GL_SCISSOR_TEST); + else glDisable(GL_SCISSOR_TEST); + scissorEnabled = enabled; } } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 58361c9..4cbac41 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -197,13 +197,17 @@ public: /** * Sets the scissor for the current surface. */ - void setScissor(GLint x, GLint y, GLint width, GLint height); + bool setScissor(GLint x, GLint y, GLint width, GLint height); /** * Resets the scissor state. */ void resetScissor(); + bool enableScissor(); + bool disableScissor(); + void setScissorEnabled(bool enabled); + /** * Returns the mesh used to draw regions. Calling this method will * bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the @@ -221,6 +225,7 @@ public: GLenum lastSrcMode; GLenum lastDstMode; Program* currentProgram; + bool scissorEnabled; // VBO to draw with GLuint meshBuffer; @@ -244,9 +249,10 @@ public: PatchCache patchCache; TextDropShadowCache dropShadowCache; FboCache fboCache; - GammaFontRenderer fontRenderer; ResourceCache resourceCache; + GammaFontRenderer* fontRenderer; + // Debug methods PFNGLINSERTEVENTMARKEREXTPROC eventMark; PFNGLPUSHGROUPMARKEREXTPROC startMark; @@ -256,6 +262,7 @@ public: PFNGLGETOBJECTLABELEXTPROC getLabel; private: + void initFont(); void initExtensions(); void initConstraints(); diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index 55a860e..6795ac3 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -68,6 +68,9 @@ // Turn on to dump display list state #define DEBUG_DISPLAY_LIST 0 +// Turn on to insert an event marker for each display list op +#define DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 0 + #if DEBUG_INIT #define INIT_LOGD(...) ALOGD(__VA_ARGS__) #else diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 0c89014..7161c58 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -61,9 +61,9 @@ const char* DisplayList::OP_NAMES[] = { "DrawPath", "DrawLines", "DrawPoints", - "DrawText", "DrawTextOnPath", "DrawPosText", + "DrawGeneralText", "ResetShader", "SetupShader", "ResetColorFilter", @@ -486,7 +486,8 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { float top = getFloat(); float right = getFloat(); float bottom = getFloat(); - SkPaint* paint = getPaint(renderer); + int alpha = getInt(); + SkXfermode::Mode mode = (SkXfermode::Mode) getInt(); ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", (char*) indent, OP_NAMES[op], left, top, right, bottom); } @@ -571,17 +572,6 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } break; - case DrawText: { - getText(&text); - int32_t count = getInt(); - float x = getFloat(); - float y = getFloat(); - SkPaint* paint = getPaint(renderer); - float length = getFloat(); - ALOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op], - text.text(), text.length(), count, x, y, paint, length); - } - break; case DrawTextOnPath: { getText(&text); int32_t count = getInt(); @@ -602,6 +592,17 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op], text.text(), text.length(), count, paint); } + break; + case DrawGeneralText: { + getText(&text); + int count = getInt(); + int positionsCount = 0; + float* positions = getFloats(positionsCount); + SkPaint* paint = getPaint(renderer); + ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op], + text.text(), text.length(), count, paint); + } + break; case ResetShader: { ALOGD("%s%s", (char*) indent, OP_NAMES[op]); } @@ -851,11 +852,13 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag #endif renderer.startMark(mName.string()); + int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); DISPLAY_LIST_LOGD("%s%s %d %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); setViewProperties(renderer, level); - if (renderer.quickReject(0, 0, mWidth, mHeight)) { + + if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) { DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo); renderer.restoreToCount(restoreTo); renderer.endMark(); @@ -864,6 +867,7 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); int saveCount = renderer.getSaveCount() - 1; + while (!mReader.eof()) { int op = mReader.readInt(); if (op & OP_MAY_BE_SKIPPED_MASK) { @@ -879,6 +883,10 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag } logBuffer.writeCommand(level, op); +#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS + Caches::getInstance().eventMark(strlen(OP_NAMES[op]), OP_NAMES[op]); +#endif + switch (op) { case DrawGLFunction: { Functor *functor = (Functor *) getInt(); @@ -1089,11 +1097,14 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag float top = getFloat(); float right = getFloat(); float bottom = getFloat(); - SkPaint* paint = getPaint(renderer); + + int alpha = getInt(); + SkXfermode::Mode mode = (SkXfermode::Mode) getInt(); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); drawGlStatus |= renderer.drawPatch(bitmap, xDivs, yDivs, colors, - xDivsCount, yDivsCount, numColors, left, top, right, bottom, paint); + xDivsCount, yDivsCount, numColors, left, top, right, bottom, + alpha, mode); } break; case DrawColor: { @@ -1185,19 +1196,6 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag drawGlStatus |= renderer.drawPoints(points, count, paint); } break; - case DrawText: { - getText(&text); - int32_t count = getInt(); - float x = getFloat(); - float y = getFloat(); - SkPaint* paint = getPaint(renderer); - float length = getFloat(); - DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, - OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length); - drawGlStatus |= renderer.drawText(text.text(), text.length(), count, x, y, - paint, length); - } - break; case DrawTextOnPath: { getText(&text); int32_t count = getInt(); @@ -1223,6 +1221,21 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag positions, paint); } break; + case DrawGeneralText: { + getText(&text); + int32_t count = getInt(); + float x = getFloat(); + float y = getFloat(); + int32_t positionsCount = 0; + float* positions = getFloats(positionsCount); + SkPaint* paint = getPaint(renderer); + float length = getFloat(); + DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, + OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length); + drawGlStatus |= renderer.drawGeneralText(text.text(), text.length(), count, + x, y, positions, paint, length); + } + break; case ResetShader: { DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShader(); @@ -1570,6 +1583,10 @@ status_t DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, in status_t DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint) { + int alpha; + SkXfermode::Mode mode; + OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode); + const bool reject = quickReject(left, top, right, bottom); uint32_t* location = addOp(DisplayList::DrawPatch, reject); addBitmap(bitmap); @@ -1577,7 +1594,8 @@ status_t DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, addInts(yDivs, height); addUInts(colors, numColors); addBounds(left, top, right, bottom); - addPaint(paint); + addInt(alpha); + addInt(mode); addSkip(location); return DrawGlInfo::kStatusDone; } @@ -1668,8 +1686,34 @@ status_t DisplayListRenderer::drawPoints(float* points, int count, SkPaint* pain return DrawGlInfo::kStatusDone; } -status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count, - float x, float y, SkPaint* paint, float length) { +status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count, + SkPath* path, float hOffset, float vOffset, SkPaint* paint) { + if (!text || count <= 0) return DrawGlInfo::kStatusDone; + addOp(DisplayList::DrawTextOnPath); + addText(text, bytesCount); + addInt(count); + addPath(path); + addFloat(hOffset); + addFloat(vOffset); + paint->setAntiAlias(true); + addPaint(paint); + return DrawGlInfo::kStatusDone; +} + +status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count, + const float* positions, SkPaint* paint) { + if (!text || count <= 0) return DrawGlInfo::kStatusDone; + addOp(DisplayList::DrawPosText); + addText(text, bytesCount); + addInt(count); + addFloats(positions, count * 2); + paint->setAntiAlias(true); + addPaint(paint); + return DrawGlInfo::kStatusDone; +} + +status_t DisplayListRenderer::drawGeneralText(const char* text, int bytesCount, int count, + float x, float y, const float* positions, SkPaint* paint, float length) { if (!text || count <= 0) return DrawGlInfo::kStatusDone; // TODO: We should probably make a copy of the paint instead of modifying @@ -1689,42 +1733,18 @@ status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int cou reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom); } - uint32_t* location = addOp(DisplayList::DrawText, reject); + uint32_t* location = addOp(DisplayList::DrawGeneralText, reject); addText(text, bytesCount); addInt(count); - addPoint(x, y); + addFloat(x); + addFloat(y); + addFloats(positions, count * 2); addPaint(paint); addFloat(length); addSkip(location); return DrawGlInfo::kStatusDone; } -status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count, - SkPath* path, float hOffset, float vOffset, SkPaint* paint) { - if (!text || count <= 0) return DrawGlInfo::kStatusDone; - addOp(DisplayList::DrawTextOnPath); - addText(text, bytesCount); - addInt(count); - addPath(path); - addFloat(hOffset); - addFloat(vOffset); - paint->setAntiAlias(true); - addPaint(paint); - return DrawGlInfo::kStatusDone; -} - -status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count, - const float* positions, SkPaint* paint) { - if (!text || count <= 0) return DrawGlInfo::kStatusDone; - addOp(DisplayList::DrawPosText); - addText(text, bytesCount); - addInt(count); - addFloats(positions, count * 2); - paint->setAntiAlias(true); - addPaint(paint); - return DrawGlInfo::kStatusDone; -} - void DisplayListRenderer::resetShader() { addOp(DisplayList::ResetShader); } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 6b4c6b2..f3041dd 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -103,9 +103,9 @@ public: DrawPath, DrawLines, DrawPoints, - DrawText, DrawTextOnPath, DrawPosText, + DrawGeneralText, ResetShader, SetupShader, ResetColorFilter, @@ -599,12 +599,12 @@ public: virtual status_t drawPath(SkPath* path, SkPaint* paint); virtual status_t drawLines(float* points, int count, SkPaint* paint); virtual status_t drawPoints(float* points, int count, SkPaint* paint); - virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y, - SkPaint* paint, float length = -1.0f); virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path, float hOffset, float vOffset, SkPaint* paint); virtual status_t drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint); + virtual status_t drawGeneralText(const char* text, int bytesCount, int count, + float x, float y, const float* positions, SkPaint* paint, float length); virtual void resetShader(); virtual void setupShader(SkiaShader* shader); diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index 6b174d6..fb945a8 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -39,9 +39,6 @@ namespace uirenderer { #define EXT_LOGD(...) #endif -// Vendor strings -#define VENDOR_IMG "Imagination Technologies" - /////////////////////////////////////////////////////////////////////////////// // Classes /////////////////////////////////////////////////////////////////////////////// @@ -69,10 +66,6 @@ public: mHasDebugMarker = hasExtension("GL_EXT_debug_marker"); mHasDebugLabel = hasExtension("GL_EXT_debug_label"); - const char* vendor = (const char*) glGetString(GL_VENDOR); - EXT_LOGD("Vendor: %s", vendor); - mNeedsHighpTexCoords = strcmp(vendor, VENDOR_IMG) == 0; - // We don't need to copy the string, the OpenGL ES spec // guarantees the result of glGetString to point to a // static string as long as our OpenGL context is valid @@ -81,7 +74,6 @@ public: inline bool hasNPot() const { return mHasNPot; } inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; } - inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; } inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; } inline bool hasDebugMarker() const { return mHasDebugMarker; } inline bool hasDebugLabel() const { return mHasDebugLabel; } @@ -101,7 +93,6 @@ private: const char* mExtensions; bool mHasNPot; - bool mNeedsHighpTexCoords; bool mHasFramebufferFetch; bool mHasDiscardFramebuffer; bool mHasDebugMarker; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 0d6e62a..7f0ed73 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -288,13 +288,13 @@ void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len } void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, - int numGlyphs, Rect *bounds) { + int numGlyphs, Rect *bounds, const float* positions) { if (bounds == NULL) { ALOGE("No return rectangle provided to measure text"); return; } bounds->set(1e6, -1e6, -1e6, 1e6); - render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, NULL); + render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions); } void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, @@ -677,10 +677,19 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp unsigned int stride = glyph.rowBytes(); uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; - for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { - for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { - uint8_t tempCol = bitmapBuffer[bY * stride + bX]; - cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; + if (mGammaTable) { + for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { + for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { + uint8_t tempCol = bitmapBuffer[bY * stride + bX]; + cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; + } + } + } else { + for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { + for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { + uint8_t tempCol = bitmapBuffer[bY * stride + bX]; + cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; + } } } @@ -688,8 +697,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp } CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { - uint8_t* textureMemory = NULL; - CacheTexture* cacheTexture = new CacheTexture(textureMemory, width, height); + CacheTexture* cacheTexture = new CacheTexture(width, height); if (allocate) { allocateTextureMemory(cacheTexture); @@ -999,7 +1007,7 @@ void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { } FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, - uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { + uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { checkInit(); if (!mCurrentFont) { @@ -1017,7 +1025,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch mBounds = NULL; Rect bounds; - mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds); + mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions); uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; @@ -1031,7 +1039,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch int penY = radius - bounds.bottom; mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, - dataBuffer, paddedWidth, paddedHeight); + Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions); blurImage(dataBuffer, paddedWidth, paddedHeight, radius); DropShadow image; diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 2ab680e..9ed6932 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -61,9 +61,8 @@ class FontRenderer; class CacheTexture { public: - CacheTexture() { } - CacheTexture(uint8_t* texture, uint16_t width, uint16_t height) : - mTexture(texture), mTextureId(0), mWidth(width), mHeight(height), + CacheTexture(uint16_t width, uint16_t height) : + mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mLinearFiltering(false) { } ~CacheTexture() { if (mTexture) { @@ -185,7 +184,7 @@ protected: uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions); void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, - int numGlyphs, Rect *bounds); + int numGlyphs, Rect *bounds, const float* positions); Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth); @@ -274,7 +273,7 @@ public: // After renderDropShadow returns, the called owns the memory in DropShadow.image // and is responsible for releasing it when it's done with it DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex, - uint32_t len, int numGlyphs, uint32_t radius); + uint32_t len, int numGlyphs, uint32_t radius, const float* positions); GLuint getTexture(bool linearFiltering = false) { checkInit(); diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp index 1be957f..bd0a4b3 100644 --- a/libs/hwui/GammaFontRenderer.cpp +++ b/libs/hwui/GammaFontRenderer.cpp @@ -24,20 +24,46 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor +// Utils /////////////////////////////////////////////////////////////////////////////// -GammaFontRenderer::GammaFontRenderer() { - INIT_LOGD("Creating gamma font renderer"); +static int luminance(const SkPaint* paint) { + uint32_t c = paint->getColor(); + const int r = (c >> 16) & 0xFF; + const int g = (c >> 8) & 0xFF; + const int b = (c ) & 0xFF; + return (r * 2 + g * 5 + b) >> 3; +} + +/////////////////////////////////////////////////////////////////////////////// +// Base class GammaFontRenderer +/////////////////////////////////////////////////////////////////////////////// + +GammaFontRenderer* GammaFontRenderer::createRenderer() { + // Choose the best renderer + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_TEXT_GAMMA_METHOD, property, DEFAULT_TEXT_GAMMA_METHOD) > 0) { + if (!strcasecmp(property, "lookup")) { + return new LookupGammaFontRenderer(); + } else if (!strcasecmp(property, "shader")) { + return new ShaderGammaFontRenderer(false); + } else if (!strcasecmp(property, "shader3")) { + return new ShaderGammaFontRenderer(true); + } + } + return new Lookup3GammaFontRenderer(); +} + +GammaFontRenderer::GammaFontRenderer() { // Get the renderer properties char property[PROPERTY_VALUE_MAX]; // Get the gamma - float gamma = DEFAULT_TEXT_GAMMA; + mGamma = DEFAULT_TEXT_GAMMA; if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { INIT_LOGD(" Setting text gamma to %s", property); - gamma = atof(property); + mGamma = atof(property); } else { INIT_LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); } @@ -61,18 +87,82 @@ GammaFontRenderer::GammaFontRenderer() { INIT_LOGD(" Using default white black gamma threshold of %d", DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); } +} + +GammaFontRenderer::~GammaFontRenderer() { +} + +/////////////////////////////////////////////////////////////////////////////// +// Shader-based renderer +/////////////////////////////////////////////////////////////////////////////// + +ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() { + INIT_LOGD("Creating shader gamma font renderer"); + mRenderer = NULL; + mMultiGamma = multiGamma; +} + +void ShaderGammaFontRenderer::describe(ProgramDescription& description, + const SkPaint* paint) const { + if (paint->getShader() == NULL) { + if (mMultiGamma) { + const int l = luminance(paint); + + if (l <= mBlackThreshold) { + description.hasGammaCorrection = true; + description.gamma = mGamma; + } else if (l >= mWhiteThreshold) { + description.hasGammaCorrection = true; + description.gamma = 1.0f / mGamma; + } + } else { + description.hasGammaCorrection = true; + description.gamma = 1.0f / mGamma; + } + } +} + +void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description, + Program* program) const { + if (description.hasGammaCorrection) { + glUniform1f(program->getUniform("gamma"), description.gamma); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Lookup-based renderer +/////////////////////////////////////////////////////////////////////////////// + +LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() { + INIT_LOGD("Creating lookup gamma font renderer"); // Compute the gamma tables - const float blackGamma = gamma; - const float whiteGamma = 1.0f / gamma; + const float gamma = 1.0f / mGamma; for (uint32_t i = 0; i <= 255; i++) { - mGammaTable[i] = i; + mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f)); + } + mRenderer = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// Lookup-based renderer, using 3 different correction tables +/////////////////////////////////////////////////////////////////////////////// + +Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() { + INIT_LOGD("Creating lookup3 gamma font renderer"); + + // Compute the gamma tables + const float blackGamma = mGamma; + const float whiteGamma = 1.0f / mGamma; + + for (uint32_t i = 0; i <= 255; i++) { const float v = i / 255.0f; const float black = pow(v, blackGamma); const float white = pow(v, whiteGamma); + mGammaTable[i] = i; mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f)); mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f)); } @@ -81,20 +171,20 @@ GammaFontRenderer::GammaFontRenderer() { memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount); } -GammaFontRenderer::~GammaFontRenderer() { +Lookup3GammaFontRenderer::~Lookup3GammaFontRenderer() { for (int i = 0; i < kGammaCount; i++) { delete mRenderers[i]; } } -void GammaFontRenderer::clear() { +void Lookup3GammaFontRenderer::clear() { for (int i = 0; i < kGammaCount; i++) { delete mRenderers[i]; mRenderers[i] = NULL; } } -void GammaFontRenderer::flush() { +void Lookup3GammaFontRenderer::flush() { int count = 0; int min = -1; uint32_t minCount = UINT_MAX; @@ -122,7 +212,7 @@ void GammaFontRenderer::flush() { } } -FontRenderer* GammaFontRenderer::getRenderer(Gamma gamma) { +FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) { FontRenderer* renderer = mRenderers[gamma]; if (!renderer) { renderer = new FontRenderer(); @@ -133,17 +223,13 @@ FontRenderer* GammaFontRenderer::getRenderer(Gamma gamma) { return renderer; } -FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) { +FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) { if (paint->getShader() == NULL) { - uint32_t c = paint->getColor(); - const int r = (c >> 16) & 0xFF; - const int g = (c >> 8) & 0xFF; - const int b = (c ) & 0xFF; - const int luminance = (r * 2 + g * 5 + b) >> 3; + const int l = luminance(paint); - if (luminance <= mBlackThreshold) { + if (l <= mBlackThreshold) { return *getRenderer(kGammaBlack); - } else if (luminance >= mWhiteThreshold) { + } else if (l >= mWhiteThreshold) { return *getRenderer(kGammaWhite); } } diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h index 99f08f0..c4a50be 100644 --- a/libs/hwui/GammaFontRenderer.h +++ b/libs/hwui/GammaFontRenderer.h @@ -20,20 +20,131 @@ #include <SkPaint.h> #include "FontRenderer.h" +#include "Program.h" namespace android { namespace uirenderer { -struct GammaFontRenderer { +class GammaFontRenderer { +public: + virtual ~GammaFontRenderer(); + + virtual void clear() = 0; + virtual void flush() = 0; + + virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0; + + virtual uint32_t getFontRendererCount() const = 0; + virtual uint32_t getFontRendererSize(uint32_t fontRenderer) const = 0; + + virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0; + virtual void setupProgram(ProgramDescription& description, Program* program) const = 0; + + static GammaFontRenderer* createRenderer(); + +protected: GammaFontRenderer(); - ~GammaFontRenderer(); - enum Gamma { - kGammaDefault = 0, - kGammaBlack = 1, - kGammaWhite = 2, - kGammaCount = 3 - }; + int mBlackThreshold; + int mWhiteThreshold; + + float mGamma; +}; + +class ShaderGammaFontRenderer: public GammaFontRenderer { +public: + ~ShaderGammaFontRenderer() { + delete mRenderer; + } + + void clear() { + delete mRenderer; + mRenderer = NULL; + } + + void flush() { + if (mRenderer) { + mRenderer->flushLargeCaches(); + } + } + + FontRenderer& getFontRenderer(const SkPaint* paint) { + if (!mRenderer) { + mRenderer = new FontRenderer; + } + return *mRenderer; + } + + uint32_t getFontRendererCount() const { + return 1; + } + + uint32_t getFontRendererSize(uint32_t fontRenderer) const { + return mRenderer ? mRenderer->getCacheSize() : 0; + } + + void describe(ProgramDescription& description, const SkPaint* paint) const; + void setupProgram(ProgramDescription& description, Program* program) const; + +private: + ShaderGammaFontRenderer(bool multiGamma); + + FontRenderer* mRenderer; + bool mMultiGamma; + + friend class GammaFontRenderer; +}; + +class LookupGammaFontRenderer: public GammaFontRenderer { +public: + ~LookupGammaFontRenderer() { + delete mRenderer; + } + + void clear() { + delete mRenderer; + } + + void flush() { + if (mRenderer) { + mRenderer->flushLargeCaches(); + } + } + + FontRenderer& getFontRenderer(const SkPaint* paint) { + if (!mRenderer) { + mRenderer = new FontRenderer; + mRenderer->setGammaTable(&mGammaTable[0]); + } + return *mRenderer; + } + + uint32_t getFontRendererCount() const { + return 1; + } + + uint32_t getFontRendererSize(uint32_t fontRenderer) const { + return mRenderer ? mRenderer->getCacheSize() : 0; + } + + void describe(ProgramDescription& description, const SkPaint* paint) const { + } + + void setupProgram(ProgramDescription& description, Program* program) const { + } + +private: + LookupGammaFontRenderer(); + + FontRenderer* mRenderer; + uint8_t mGammaTable[256]; + + friend class GammaFontRenderer; +}; + +class Lookup3GammaFontRenderer: public GammaFontRenderer { +public: + ~Lookup3GammaFontRenderer(); void clear(); void flush(); @@ -53,16 +164,30 @@ struct GammaFontRenderer { return renderer->getCacheSize(); } + void describe(ProgramDescription& description, const SkPaint* paint) const { + } + + void setupProgram(ProgramDescription& description, Program* program) const { + } + private: + Lookup3GammaFontRenderer(); + + enum Gamma { + kGammaDefault = 0, + kGammaBlack = 1, + kGammaWhite = 2, + kGammaCount = 3 + }; + FontRenderer* getRenderer(Gamma gamma); uint32_t mRenderersUsageCount[kGammaCount]; FontRenderer* mRenderers[kGammaCount]; - int mBlackThreshold; - int mWhiteThreshold; - uint8_t mGammaTable[256 * kGammaCount]; + + friend class GammaFontRenderer; }; }; // namespace uirenderer diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 3678788..7026eea 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -16,8 +16,6 @@ #define LOG_TAG "OpenGLRenderer" -#include <GLES2/gl2.h> - #include <SkCanvas.h> #include <SkGradientShader.h> @@ -45,6 +43,8 @@ GradientCache::GradientCache(): INIT_LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); } + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + mCache.setOnEntryRemovedListener(this); } @@ -116,8 +116,11 @@ void GradientCache::clear() { Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode) { + int width = 256 * (count - 1); + width = width < mMaxTextureSize ? width : mMaxTextureSize; + SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1024, 1); + bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, 4); bitmap.allocPixels(); bitmap.eraseColor(0); @@ -134,7 +137,7 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, p.setStyle(SkPaint::kStrokeAndFill_Style); p.setShader(localShader)->unref(); - canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p); + canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 4.0f, p); // Asume the cache is always big enough const uint32_t size = bitmap.rowBytes() * bitmap.height(); diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index ac34684..59515a1 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -17,6 +17,8 @@ #ifndef ANDROID_HWUI_GRADIENT_CACHE_H #define ANDROID_HWUI_GRADIENT_CACHE_H +#include <GLES2/gl2.h> + #include <SkShader.h> #include <utils/Mutex.h> @@ -152,6 +154,8 @@ private: uint32_t mSize; uint32_t mMaxSize; + GLint mMaxTextureSize; + Vector<SkShader*> mGarbage; mutable Mutex mLock; }; // class GradientCache diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 65f8c7c..41a5f0d 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -233,9 +233,8 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layer->getTexture(), 0); - glDisable(GL_SCISSOR_TEST); + caches.disableScissor(); glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_SCISSOR_TEST); glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); @@ -431,7 +430,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f, bitmap->width(), bitmap->height(), !layer->isBlend()); - glDisable(GL_SCISSOR_TEST); + caches.disableScissor(); renderer.translate(0.0f, bitmap->height()); renderer.scale(1.0f, -1.0f); @@ -460,8 +459,6 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { } error: - glEnable(GL_SCISSOR_TEST); - #if DEBUG_OPENGL if (error != GL_NO_ERROR) { ALOGD("GL error while copying layer into bitmap = 0x%x", error); diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 8f3a0a3..531aa5b 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -61,12 +61,13 @@ public: bool isOpaque, GLenum renderTarget, float* transform); ANDROID_API static void destroyLayer(Layer* layer); ANDROID_API static void destroyLayerDeferred(Layer* layer); - ANDROID_API static void flushLayer(Layer* layer); ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap); private: void generateMesh(); + static void flushLayer(Layer* layer); + Layer* mLayer; }; // class LayerRenderer diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 9a90bfd..07281cc 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -45,8 +45,7 @@ namespace uirenderer { #define RAD_TO_DEG (180.0f / 3.14159265f) #define MIN_ANGLE 0.001f -// TODO: This should be set in properties -#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH) +#define ALPHA_THRESHOLD 0 #define FILTER(paint) (paint && paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST) @@ -158,7 +157,6 @@ void OpenGLRenderer::setViewport(int width, int height) { mFirstSnapshot->viewport.set(0, 0, width, height); glDisable(GL_DITHER); - glEnable(GL_SCISSOR_TEST); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glEnableVertexAttribArray(Program::kBindingPosition); @@ -182,6 +180,7 @@ int OpenGLRenderer::prepareDirty(float left, float top, float right, float botto syncState(); if (!opaque) { + mCaches.enableScissor(); mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); glClear(GL_COLOR_BUFFER_BIT); return DrawGlInfo::kStatusDrew; @@ -251,7 +250,7 @@ void OpenGLRenderer::resume() { glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glEnable(GL_SCISSOR_TEST); + mCaches.enableScissor(); mCaches.resetScissor(); dirtyClip(); @@ -314,6 +313,7 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { interrupt(); detachFunctor(functor); + mCaches.enableScissor(); if (mDirtyClip) { setScissorFromClip(); } @@ -449,7 +449,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int flags) { - if (alpha >= 255 - ALPHA_THRESHOLD) { + if (alpha >= 255) { return saveLayer(left, top, right, bottom, NULL, flags); } else { SkPaint paint; @@ -652,6 +652,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna #endif // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering + mCaches.enableScissor(); mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -982,7 +983,7 @@ void OpenGLRenderer::clearLayerRegions() { // The list contains bounds that have already been clipped // against their initial clip rect, and the current clip // is likely different so we need to disable clipping here - glDisable(GL_SCISSOR_TEST); + bool scissorChanged = mCaches.disableScissor(); Vertex mesh[count * 6]; Vertex* vertex = mesh; @@ -1010,7 +1011,7 @@ void OpenGLRenderer::clearLayerRegions() { glDrawArrays(GL_TRIANGLES, 0, count * 6); - glEnable(GL_SCISSOR_TEST); + if (scissorChanged) mCaches.enableScissor(); } else { for (uint32_t i = 0; i < count; i++) { delete mLayers.itemAt(i); @@ -1067,17 +1068,17 @@ void OpenGLRenderer::setScissorFromClip() { Rect clip(*mSnapshot->clipRect); clip.snapToPixelBoundaries(); - mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, - clip.getWidth(), clip.getHeight()); - - mDirtyClip = false; + if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, + clip.getWidth(), clip.getHeight())) { + mDirtyClip = false; + } } const Rect& OpenGLRenderer::getClipBounds() { return mSnapshot->getLocalClip(); } -bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { +bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) { if (mSnapshot->isIgnored()) { return true; } @@ -1092,6 +1093,26 @@ bool OpenGLRenderer::quickReject(float left, float top, float right, float botto return !clipRect.intersects(r); } +bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { + if (mSnapshot->isIgnored()) { + return true; + } + + Rect r(left, top, right, bottom); + mSnapshot->transform->mapRect(r); + r.snapToPixelBoundaries(); + + Rect clipRect(*mSnapshot->clipRect); + clipRect.snapToPixelBoundaries(); + + bool rejected = !clipRect.intersects(r); + if (!isDeferred() && !rejected) { + mCaches.setScissorEnabled(!clipRect.contains(r)); + } + + return rejected; +} + bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { bool clipped = mSnapshot->clip(left, top, right, bottom, op); if (clipped) { @@ -1109,6 +1130,8 @@ Rect* OpenGLRenderer::getClipRect() { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setupDraw(bool clear) { + // TODO: It would be best if we could do this before quickReject() + // changes the scissor test state if (clear) clearLayerRegions(); if (mDirtyClip) { setScissorFromClip(); @@ -1171,6 +1194,10 @@ void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) { mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA); } +void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) { + mCaches.fontRenderer->describe(mDescription, paint); +} + void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) { mColorA = a; mColorR = r; @@ -1298,6 +1325,10 @@ void OpenGLRenderer::setupDrawColorFilterUniforms() { } } +void OpenGLRenderer::setupDrawTextGammaUniforms() { + mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram); +} + void OpenGLRenderer::setupDrawSimpleMesh() { bool force = mCaches.bindMeshBuffer(); mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0); @@ -1674,10 +1705,23 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint) { + int alpha; + SkXfermode::Mode mode; + getAlphaAndModeDirect(paint, &alpha, &mode); + + return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors, + left, top, right, bottom, alpha, mode); +} + +status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode) { if (quickReject(left, top, right, bottom)) { return DrawGlInfo::kStatusDone; } + alpha *= mSnapshot->alpha; + mCaches.activeTexture(0); Texture* texture = mCaches.textureCache.get(bitmap); if (!texture) return DrawGlInfo::kStatusDone; @@ -1685,10 +1729,6 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const texture->setWrap(GL_CLAMP_TO_EDGE, true); texture->setFilter(GL_LINEAR, true); - int alpha; - SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); - const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); @@ -1743,6 +1783,7 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom int color, SkXfermode::Mode mode) { float inverseScaleX = 1.0f; float inverseScaleY = 1.0f; + // The quad that we use needs to account for scaling. if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) { Matrix4 *mat = mSnapshot->transform; @@ -1758,24 +1799,6 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; } - setupDraw(); - setupDrawNoTexture(); - setupDrawAALine(); - setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); - setupDrawColorFilter(); - setupDrawShader(); - setupDrawBlending(true, mode); - setupDrawProgram(); - setupDrawModelViewIdentity(true); - setupDrawColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderIdentityUniforms(); - - AAVertex rects[4]; - AAVertex* aaVertices = &rects[0]; - void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; - void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset; - float boundarySizeX = .5 * inverseScaleX; float boundarySizeY = .5 * inverseScaleY; @@ -1785,32 +1808,51 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom top -= boundarySizeY; bottom += boundarySizeY; - float width = right - left; - float height = bottom - top; + if (!quickReject(left, top, right, bottom)) { + setupDraw(); + setupDrawNoTexture(); + setupDrawAALine(); + setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelViewIdentity(true); + setupDrawColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderIdentityUniforms(); - int widthSlot; - int lengthSlot; + AAVertex rects[4]; + AAVertex* aaVertices = &rects[0]; + void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; + void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset; - float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0; - float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0; - setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, - boundaryWidthProportion, widthSlot, lengthSlot); + int widthSlot; + int lengthSlot; - int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); - int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength"); - glUniform1f(boundaryLengthSlot, boundaryHeightProportion); - glUniform1f(inverseBoundaryLengthSlot, (1.0f / boundaryHeightProportion)); + float width = right - left; + float height = bottom - top; + + float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0; + float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0; + setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, + boundaryWidthProportion, widthSlot, lengthSlot); + + int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); + int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength"); + glUniform1f(boundaryLengthSlot, boundaryHeightProportion); + glUniform1f(inverseBoundaryLengthSlot, (1.0f / boundaryHeightProportion)); - if (!quickReject(left, top, right, bottom)) { AAVertex::set(aaVertices++, left, bottom, 1, 1); AAVertex::set(aaVertices++, left, top, 1, 0); AAVertex::set(aaVertices++, right, bottom, 0, 1); AAVertex::set(aaVertices++, right, top, 0, 0); dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } - finishDrawAALine(widthSlot, lengthSlot); + finishDrawAALine(widthSlot, lengthSlot); + } } /** @@ -1882,6 +1924,9 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } getAlphaAndMode(paint, &alpha, &mode); + + mCaches.enableScissor(); + setupDraw(); setupDrawNoTexture(); if (isAA) { @@ -2012,7 +2057,7 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); - if (!quickReject(left, top, right, bottom)) { + if (!quickRejectNoScissor(left, top, right, bottom)) { if (!isAA) { if (prevVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge @@ -2117,6 +2162,10 @@ status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { TextureVertex pointsData[verticesCount]; TextureVertex* vertex = &pointsData[0]; + // TODO: We should optimize this method to not generate vertices for points + // that lie outside of the clip. + mCaches.enableScissor(); + setupDraw(); setupDrawNoTexture(); setupDrawPoint(strokeWidth); @@ -2254,6 +2303,44 @@ status_t OpenGLRenderer::drawRect(float left, float top, float right, float bott return DrawGlInfo::kStatusDrew; } +void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count, + const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, + float x, float y) { + mCaches.activeTexture(0); + + // NOTE: The drop shadow will not perform gamma correction + // if shader-based correction is enabled + mCaches.dropShadowCache.setFontRenderer(fontRenderer); + const ShadowTexture* shadow = mCaches.dropShadowCache.get( + paint, text, bytesCount, count, mShadowRadius, positions); + const AutoTexture autoCleanup(shadow); + + const float sx = x - shadow->left + mShadowDx; + const float sy = y - shadow->top + mShadowDy; + + const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; + int shadowColor = mShadowColor; + if (mShader) { + shadowColor = 0xffffffff; + } + + setupDraw(); + setupDrawWithTexture(true); + setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); + setupDrawTexture(shadow->id); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); + setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); +} + status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint) { if (text == NULL || count == 0 || mSnapshot->isIgnored() || @@ -2274,7 +2361,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); } - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); + FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); @@ -2282,6 +2369,11 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); + if (CC_UNLIKELY(mHasShadow)) { + drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode, + 0.0f, 0.0f); + } + // Pick the appropriate texture filtering bool linearFilter = mSnapshot->transform->changesBounds(); if (pureTranslate && !linearFilter) { @@ -2290,6 +2382,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count mCaches.activeTexture(0); setupDraw(); + setupDrawTextGamma(paint); setupDrawDirtyRegionsDisabled(); setupDrawWithTexture(true); setupDrawAlpha8Color(paint->getColor(), alpha); @@ -2302,6 +2395,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderUniforms(pureTranslate); + setupDrawTextGammaUniforms(); const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); @@ -2327,8 +2421,8 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count return DrawGlInfo::kStatusDrew; } -status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, - float x, float y, SkPaint* paint, float length) { +status_t OpenGLRenderer::drawGeneralText(const char* text, int bytesCount, int count, + float x, float y, const float* positions, SkPaint* paint, float length) { if (text == NULL || count == 0 || mSnapshot->isIgnored() || (paint->getAlpha() * mSnapshot->alpha == 0 && paint->getXfermode() == NULL)) { return DrawGlInfo::kStatusDone; @@ -2361,10 +2455,11 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, } #if DEBUG_GLYPHS - ALOGD("OpenGLRenderer drawText() with FontID=%d", SkTypeface::UniqueID(paint->getTypeface())); + ALOGD("OpenGLRenderer drawGeneralText() with FontID=%d", + SkTypeface::UniqueID(paint->getTypeface())); #endif - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); + FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); @@ -2373,37 +2468,8 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, getAlphaAndMode(paint, &alpha, &mode); if (CC_UNLIKELY(mHasShadow)) { - mCaches.activeTexture(0); - - mCaches.dropShadowCache.setFontRenderer(fontRenderer); - const ShadowTexture* shadow = mCaches.dropShadowCache.get( - paint, text, bytesCount, count, mShadowRadius); - const AutoTexture autoCleanup(shadow); - - const float sx = oldX - shadow->left + mShadowDx; - const float sy = oldY - shadow->top + mShadowDy; - - const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; - int shadowColor = mShadowColor; - if (mShader) { - shadowColor = 0xffffffff; - } - - setupDraw(); - setupDrawWithTexture(true); - setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); - setupDrawColorFilter(); - setupDrawShader(); - setupDrawBlending(true, mode); - setupDrawProgram(); - setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); - setupDrawTexture(shadow->id); - setupDrawPureColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderUniforms(); - setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode, + oldX, oldY); } // Pick the appropriate texture filtering @@ -2415,6 +2481,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, // The font renderer will always use texture unit 0 mCaches.activeTexture(0); setupDraw(); + setupDrawTextGamma(paint); setupDrawDirtyRegionsDisabled(); setupDrawWithTexture(true); setupDrawAlpha8Color(paint->getColor(), alpha); @@ -2429,6 +2496,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderUniforms(pureTranslate); + setupDrawTextGammaUniforms(); const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); @@ -2439,8 +2507,16 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, const bool hasActiveLayer = false; #endif - if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, - hasActiveLayer ? &bounds : NULL)) { + bool status; + if (positions != NULL) { + status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, + positions, hasActiveLayer ? &bounds : NULL); + } else { + // TODO: would it be okay to call renderPosText with null positions? + status = fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, + hasActiveLayer ? &bounds : NULL); + } + if (status) { #if RENDER_LAYERS_AS_REGIONS if (hasActiveLayer) { if (!pureTranslate) { @@ -2463,7 +2539,7 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co return DrawGlInfo::kStatusDone; } - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); + FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); @@ -2473,6 +2549,7 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co mCaches.activeTexture(0); setupDraw(); + setupDrawTextGamma(paint); setupDrawDirtyRegionsDisabled(); setupDrawWithTexture(true); setupDrawAlpha8Color(paint->getColor(), alpha); @@ -2485,6 +2562,7 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderUniforms(false); + setupDrawTextGammaUniforms(); const Rect* clip = &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); @@ -2918,30 +2996,9 @@ void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, flo } void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { - if (paint) { - *mode = getXfermode(paint->getXfermode()); - - // Skia draws using the color's alpha channel if < 255 - // Otherwise, it uses the paint's alpha - int color = paint->getColor(); - *alpha = (color >> 24) & 0xFF; - if (*alpha == 255) { - *alpha = paint->getAlpha(); - } - } else { - *mode = SkXfermode::kSrcOver_Mode; - *alpha = 255; - } + getAlphaAndModeDirect(paint, alpha, mode); *alpha *= mSnapshot->alpha; } -SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) { - SkXfermode::Mode resultMode; - if (!SkXfermode::AsMode(mode, &resultMode)) { - resultMode = SkXfermode::kSrcOver_Mode; - } - return resultMode; -} - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 7aac87c..378fc8c 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -105,6 +105,7 @@ public: ANDROID_API const Rect& getClipBounds(); ANDROID_API bool quickReject(float left, float top, float right, float bottom); + bool quickRejectNoScissor(float left, float top, float right, float bottom); virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); virtual Rect* getClipRect(); @@ -123,6 +124,9 @@ public: virtual status_t drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint); + status_t drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode); virtual status_t drawColor(int color, SkXfermode::Mode mode); virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint); virtual status_t drawRoundRect(float left, float top, float right, float bottom, @@ -134,12 +138,12 @@ public: virtual status_t drawPath(SkPath* path, SkPaint* paint); virtual status_t drawLines(float* points, int count, SkPaint* paint); virtual status_t drawPoints(float* points, int count, SkPaint* paint); - virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y, - SkPaint* paint, float length = -1.0f); virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path, float hOffset, float vOffset, SkPaint* paint); virtual status_t drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint); + virtual status_t drawGeneralText(const char* text, int bytesCount, int count, float x, float y, + const float* positions, SkPaint* paint, float length = -1.0f); virtual void resetShader(); virtual void setupShader(SkiaShader* shader); @@ -213,6 +217,54 @@ protected: */ void drawTextureLayer(Layer* layer, const Rect& rect); + /** + * Gets the alpha and xfermode out of a paint object. If the paint is null + * alpha will be 255 and the xfermode will be SRC_OVER. + * + * @param paint The paint to extract values from + * @param alpha Where to store the resulting alpha + * @param mode Where to store the resulting xfermode + */ + inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode); + + /** + * Gets the alpha and xfermode out of a paint object. If the paint is null + * alpha will be 255 and the xfermode will be SRC_OVER. This method does + * not multiply the paint's alpha by the current snapshot's alpha. + * + * @param paint The paint to extract values from + * @param alpha Where to store the resulting alpha + * @param mode Where to store the resulting xfermode + */ + static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { + if (paint) { + *mode = getXfermode(paint->getXfermode()); + + // Skia draws using the color's alpha channel if < 255 + // Otherwise, it uses the paint's alpha + int color = paint->getColor(); + *alpha = (color >> 24) & 0xFF; + if (*alpha == 255) { + *alpha = paint->getAlpha(); + } + } else { + *mode = SkXfermode::kSrcOver_Mode; + *alpha = 255; + } + } + + /** + * Safely retrieves the mode from the specified xfermode. If the specified + * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode. + */ + static inline SkXfermode::Mode getXfermode(SkXfermode* mode) { + SkXfermode::Mode resultMode; + if (!SkXfermode::AsMode(mode, &resultMode)) { + resultMode = SkXfermode::kSrcOver_Mode; + } + return resultMode; + } + private: /** * Ensures the state of the renderer is the same as the state of @@ -446,6 +498,24 @@ private: void drawTextDecorations(const char* text, int bytesCount, float length, float x, float y, SkPaint* paint); + /** + * Draws shadow layer on text (with optional positions). + * + * @param paint The paint to draw the shadow with + * @param text The text to draw + * @param bytesCount The number of bytes in the text + * @param count The number of glyphs in the text + * @param positions The x, y positions of individual glyphs (or NULL) + * @param fontRenderer The font renderer object + * @param alpha The alpha value for drawing the shadow + * @param mode The xfermode for drawing the shadow + * @param x The x coordinate where the shadow will be drawn + * @param y The y coordinate where the shadow will be drawn + */ + void drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count, + const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, + float x, float y); + /** * Draws a path texture. Path textures are alpha8 bitmaps that need special * compositing to apply colors/filters/etc. @@ -455,7 +525,7 @@ private: * @param y The y coordinate where the texture will be drawn * @param paint The paint to draw the texture with */ - void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint); + void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint); /** * Resets the texture coordinates stored in mMeshVertices. Setting the values @@ -471,16 +541,6 @@ private: void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2); /** - * Gets the alpha and xfermode out of a paint object. If the paint is null - * alpha will be 255 and the xfermode will be SRC_OVER. - * - * @param paint The paint to extract values from - * @param alpha Where to store the resulting alpha - * @param mode Where to store the resulting xfermode - */ - inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode); - - /** * Binds the specified texture. The texture unit must have been selected * prior to calling this method. */ @@ -504,12 +564,6 @@ private: bool swapSrcDst = false); /** - * Safely retrieves the mode from the specified xfermode. If the specified - * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode. - */ - inline SkXfermode::Mode getXfermode(SkXfermode* mode); - - /** * Use the specified program with the current GL context. If the program is already * in use, it will not be bound again. If it is not in use, the current program is * marked unused and the specified program becomes used and becomes the new @@ -537,6 +591,7 @@ private: void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); + void setupDrawTextGamma(const SkPaint* paint); void setupDrawShader(); void setupDrawColorFilter(); void setupDrawBlending(SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode, @@ -561,6 +616,7 @@ private: void setupDrawExternalTexture(GLuint texture); void setupDrawTextureTransform(); void setupDrawTextureTransformUniforms(mat4& transform); + void setupDrawTextGammaUniforms(); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords); void setupDrawVertices(GLvoid* vertices); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index eb9ee7b..491767f 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -41,8 +41,8 @@ namespace uirenderer { #define PROGRAM_LOGD(...) #endif -#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH)) -#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH) +#define COLOR_COMPONENT_THRESHOLD 1.0f +#define COLOR_COMPONENT_INV_THRESHOLD 0.0f #define PROGRAM_KEY_TEXTURE 0x1 #define PROGRAM_KEY_A8_TEXTURE 0x2 @@ -77,6 +77,8 @@ namespace uirenderer { #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 +#define PROGRAM_HAS_GAMMA_CORRECTION 40 + /////////////////////////////////////////////////////////////////////////////// // Types /////////////////////////////////////////////////////////////////////////////// @@ -146,6 +148,9 @@ struct ProgramDescription { bool isPoint; float pointSize; + bool hasGammaCorrection; + float gamma; + /** * Resets this description. All fields are reset back to the default * values they hold after building a new instance. @@ -180,6 +185,9 @@ struct ProgramDescription { isPoint = false; pointSize = 0.0f; + + hasGammaCorrection = false; + gamma = 2.2f; } /** @@ -246,6 +254,7 @@ struct ProgramDescription { if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; + if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION; return key; } @@ -261,7 +270,7 @@ struct ProgramDescription { } private: - inline uint32_t getEnumForWrap(GLenum wrap) const { + static inline uint32_t getEnumForWrap(GLenum wrap) { switch (wrap) { case GL_CLAMP_TO_EDGE: return 0; diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index a7f1277..70bd1a8 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -65,25 +65,19 @@ const char* gVS_Header_Varyings_HasTexture = const char* gVS_Header_Varyings_IsAA = "varying float widthProportion;\n" "varying float lengthProportion;\n"; -const char* gVS_Header_Varyings_HasBitmap[2] = { - // Default precision - "varying vec2 outBitmapTexCoords;\n", - // High precision - "varying highp vec2 outBitmapTexCoords;\n" -}; -const char* gVS_Header_Varyings_PointHasBitmap[2] = { - // Default precision - "varying vec2 outPointBitmapTexCoords;\n", - // High precision - "varying highp vec2 outPointBitmapTexCoords;\n" -}; +const char* gVS_Header_Varyings_HasBitmap = + "varying highp vec2 outBitmapTexCoords;\n"; +const char* gVS_Header_Varyings_PointHasBitmap = + "varying highp vec2 outPointBitmapTexCoords;\n"; +// TODO: These values are used to sample from textures, +// they may need to be highp const char* gVS_Header_Varyings_HasGradient[3] = { // Linear - "varying vec2 linear;\n", + "varying highp vec2 linear;\n", // Circular - "varying vec2 circular;\n", + "varying highp vec2 circular;\n", // Sweep - "varying vec2 sweep;\n" + "varying highp vec2 sweep;\n" }; const char* gVS_Main = "\nvoid main(void) {\n"; @@ -159,12 +153,15 @@ const char* gFS_Uniforms_ColorOp[4] = { // PorterDuff "uniform vec4 colorBlend;\n" }; +const char* gFS_Uniforms_Gamma = + "uniform float gamma;\n"; + const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; const char* gFS_Main_PointBitmapTexCoords = - " vec2 outBitmapTexCoords = outPointBitmapTexCoords + " + " highp vec2 outBitmapTexCoords = outPointBitmapTexCoords + " "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n"; // Fast cases @@ -184,10 +181,18 @@ const char* gFS_Fast_SingleA8Texture = "\nvoid main(void) {\n" " gl_FragColor = texture2D(sampler, outTexCoords);\n" "}\n\n"; +const char* gFS_Fast_SingleA8Texture_ApplyGamma = + "\nvoid main(void) {\n" + " gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(sampler, outTexCoords).a, gamma));\n" + "}\n\n"; const char* gFS_Fast_SingleModulateA8Texture = "\nvoid main(void) {\n" " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n" "}\n\n"; +const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma = + "\nvoid main(void) {\n" + " gl_FragColor = color * pow(texture2D(sampler, outTexCoords).a, gamma);\n" + "}\n\n"; const char* gFS_Fast_SingleGradient = "\nvoid main(void) {\n" " gl_FragColor = texture2D(gradientSampler, linear);\n" @@ -202,6 +207,8 @@ const char* gFS_Main_FetchColor = " fragColor = color;\n"; const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n"; +const char* gFS_Main_ModulateColor_ApplyGamma = + " fragColor *= pow(color.a, gamma);\n"; const char* gFS_Main_AccountForAA = " if (widthProportion < boundaryWidth) {\n" " fragColor *= (widthProportion * inverseBoundaryWidth);\n" @@ -229,10 +236,10 @@ const char* gFS_Main_FetchGradient[3] = { // Linear " vec4 gradientColor = texture2D(gradientSampler, linear);\n", // Circular - " float index = length(circular);\n" + " highp float index = length(circular);\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", // Sweep - " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" + " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n" }; const char* gFS_Main_FetchBitmap = @@ -426,10 +433,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0; shader.append(description.isPoint ? - gVS_Header_Varyings_PointHasBitmap[index] : - gVS_Header_Varyings_HasBitmap[index]); + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Begin the shader @@ -488,10 +494,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0; shader.append(description.isPoint ? - gVS_Header_Varyings_PointHasBitmap[index] : - gVS_Header_Varyings_HasBitmap[index]); + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Uniforms @@ -517,6 +522,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasBitmap && description.isPoint) { shader.append(gFS_Header_Uniforms_PointHasBitmap); } + if (description.hasGammaCorrection) { + shader.append(gFS_Uniforms_Gamma); + } // Optimization for common cases if (!description.isAA && !blendFramebuffer && @@ -544,9 +552,17 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti fast = true; } else if (singleA8Texture) { if (!description.modulate) { - shader.append(gFS_Fast_SingleA8Texture); + if (description.hasGammaCorrection) { + shader.append(gFS_Fast_SingleA8Texture_ApplyGamma); + } else { + shader.append(gFS_Fast_SingleA8Texture); + } } else { - shader.append(gFS_Fast_SingleModulateA8Texture); + if (description.hasGammaCorrection) { + shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma); + } else { + shader.append(gFS_Fast_SingleModulateA8Texture); + } } fast = true; } else if (singleGradient) { @@ -643,7 +659,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } } if (description.modulate && applyModulate) { - shader.append(gFS_Main_ModulateColor); + if (description.hasGammaCorrection) { + shader.append(gFS_Main_ModulateColor_ApplyGamma); + } else { + shader.append(gFS_Main_ModulateColor); + } } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); @@ -676,13 +696,13 @@ void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode:: } void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) { - shader.append("\nvec2 wrap(vec2 texCoords) {\n"); + shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n"); if (wrapS == GL_MIRRORED_REPEAT) { - shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n"); + shader.append(" highp float xMod2 = mod(texCoords.x, 2.0);\n"); shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n"); } if (wrapT == GL_MIRRORED_REPEAT) { - shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n"); + shader.append(" highp float yMod2 = mod(texCoords.y, 2.0);\n"); shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n"); } shader.append(" return vec2("); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7854729..3f3b39a 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -73,13 +73,30 @@ enum DebugLevel { #define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width" #define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height" -// Gamma (>= 1.0, <= 10.0) -#define PROPERTY_TEXT_GAMMA "ro.text_gamma" -#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold" -#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold" +// Indicates whether gamma correction should be applied in the shaders +// or in lookup tables. Accepted values: +// +// - "lookup3", correction based on lookup tables. Gamma correction +// is different for black and white text (see thresholds below) +// +// - "lookup", correction based on a single lookup table +// +// - "shader3", correction applied by a GLSL shader. Gamma correction +// is different for black and white text (see thresholds below) +// +// - "shader", correction applied by a GLSL shader +// +// See PROPERTY_TEXT_GAMMA, PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD and +// PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD for more control. +#define PROPERTY_TEXT_GAMMA_METHOD "hwui.text_gamma_correction" +#define DEFAULT_TEXT_GAMMA_METHOD "lookup" -// TODO: This should be set by a system property -#define PANEL_BIT_DEPTH 20 +// Gamma (>= 1.0, <= 10.0) +#define PROPERTY_TEXT_GAMMA "hwui.text_gamma" +// Luminance threshold below which black gamma correction is applied. Range: [0..255] +#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "hwui.text_gamma.black_threshold" +// Lumincance threshold above which white gamma correction is applied. Range: [0..255] +#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold" // Converts a number of mega-bytes into bytes #define MB(s) s * 1024 * 1024 diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 2ca4f50..80f39ff 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -125,11 +125,11 @@ public: return intersect(r.left, r.top, r.right, r.bottom); } - bool contains(float l, float t, float r, float b) { + inline bool contains(float l, float t, float r, float b) { return l >= left && t >= top && r <= right && b <= bottom; } - bool contains(const Rect& r) { + inline bool contains(const Rect& r) { return contains(r.left, r.top, r.right, r.bottom); } diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index cf5f822..2153a8b 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -48,7 +48,8 @@ ResourceCache::~ResourceCache() { void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { Mutex::Autolock _l(mLock); - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ssize_t index = mCache->indexOfKey(resource); + ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL || mCache->size() == 0) { ref = new ResourceReference(resourceType); mCache->add(resource, ref); @@ -78,7 +79,8 @@ void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { void ResourceCache::decrementRefcount(void* resource) { Mutex::Autolock _l(mLock); - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ssize_t index = mCache->indexOfKey(resource); + ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { // Should not get here - shouldn't get a call to decrement if we're not yet tracking it return; @@ -111,12 +113,13 @@ void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { void ResourceCache::recycle(SkBitmap* resource) { Mutex::Autolock _l(mLock); - if (mCache->indexOfKey(resource) < 0) { + ssize_t index = mCache->indexOfKey(resource); + if (index < 0) { // not tracking this resource; just recycle the pixel data resource->setPixels(NULL, NULL); return; } - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ResourceReference* ref = mCache->valueAt(index); if (ref == NULL) { // Should not get here - shouldn't get a call to recycle if we're not yet tracking it return; @@ -129,7 +132,8 @@ void ResourceCache::recycle(SkBitmap* resource) { void ResourceCache::destructor(SkPath* resource) { Mutex::Autolock _l(mLock); - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ssize_t index = mCache->indexOfKey(resource); + ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { @@ -146,7 +150,8 @@ void ResourceCache::destructor(SkPath* resource) { void ResourceCache::destructor(SkBitmap* resource) { Mutex::Autolock _l(mLock); - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ssize_t index = mCache->indexOfKey(resource); + ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { @@ -163,7 +168,8 @@ void ResourceCache::destructor(SkBitmap* resource) { void ResourceCache::destructor(SkiaShader* resource) { Mutex::Autolock _l(mLock); - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ssize_t index = mCache->indexOfKey(resource); + ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it delete resource; @@ -177,7 +183,8 @@ void ResourceCache::destructor(SkiaShader* resource) { void ResourceCache::destructor(SkiaColorFilter* resource) { Mutex::Autolock _l(mLock); - ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; + ssize_t index = mCache->indexOfKey(resource); + ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it delete resource; diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index bef1373..93aa8a5 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -102,13 +102,13 @@ void TextDropShadowCache::clear() { } ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len, - int numGlyphs, uint32_t radius) { - ShadowText entry(paint, radius, len, text); + int numGlyphs, uint32_t radius, const float* positions) { + ShadowText entry(paint, radius, len, text, positions); ShadowTexture* texture = mCache.get(entry); if (!texture) { FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(paint, text, 0, - len, numGlyphs, radius); + len, numGlyphs, radius, positions); texture = new ShadowTexture; texture->left = shadow.penX; diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index e2bdde1..bae0c49 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -35,8 +35,9 @@ struct ShadowText { ShadowText(): radius(0), len(0), textSize(0.0f), typeface(NULL) { } - ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText): - radius(radius), len(len) { + ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText, + const float* positions): + radius(radius), len(len), positions(positions) { // TODO: Propagate this through the API, we should not cast here text = (const char16_t*) srcText; @@ -66,11 +67,18 @@ struct ShadowText { uint32_t italicStyle; uint32_t scaleX; const char16_t* text; + const float* positions; String16 str; + Vector<float> positionsCopy; void copyTextLocally() { str.setTo((const char16_t*) text, len >> 1); text = str.string(); + if (positions != NULL) { + positionsCopy.clear(); + positionsCopy.appendArray(positions, len); + positions = positionsCopy.array(); + } } bool operator<(const ShadowText& rhs) const { @@ -81,7 +89,12 @@ struct ShadowText { LTE_INT(flags) { LTE_INT(italicStyle) { LTE_INT(scaleX) { - return memcmp(text, rhs.text, len) < 0; + int cmp = memcmp(text, rhs.text, len); + if (cmp < 0) return true; + if (cmp == 0 && rhs.positions != NULL) { + if (positions == NULL) return true; + return memcmp(positions, rhs.positions, len << 2) < 0; + } } } } @@ -117,7 +130,7 @@ public: void operator()(ShadowText& text, ShadowTexture*& texture); ShadowTexture* get(SkPaint* paint, const char* text, uint32_t len, - int numGlyphs, uint32_t radius); + int numGlyphs, uint32_t radius, const float* positions); /** * Clears the cache. This causes all textures to be deleted. |