summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/tests/ObbFile_test.cpp4
-rw-r--r--libs/hwui/Android.mk11
-rw-r--r--libs/hwui/Caches.cpp54
-rw-r--r--libs/hwui/Caches.h11
-rw-r--r--libs/hwui/Debug.h3
-rw-r--r--libs/hwui/DisplayListRenderer.cpp140
-rw-r--r--libs/hwui/DisplayListRenderer.h6
-rw-r--r--libs/hwui/Extensions.h9
-rw-r--r--libs/hwui/FontRenderer.cpp30
-rw-r--r--libs/hwui/FontRenderer.h9
-rw-r--r--libs/hwui/GammaFontRenderer.cpp126
-rw-r--r--libs/hwui/GammaFontRenderer.h147
-rw-r--r--libs/hwui/GradientCache.cpp11
-rw-r--r--libs/hwui/GradientCache.h4
-rw-r--r--libs/hwui/LayerRenderer.cpp7
-rw-r--r--libs/hwui/LayerRenderer.h3
-rw-r--r--libs/hwui/OpenGLRenderer.cpp279
-rw-r--r--libs/hwui/OpenGLRenderer.h94
-rw-r--r--libs/hwui/Program.h15
-rw-r--r--libs/hwui/ProgramCache.cpp80
-rw-r--r--libs/hwui/Properties.h29
-rw-r--r--libs/hwui/Rect.h4
-rw-r--r--libs/hwui/ResourceCache.cpp23
-rw-r--r--libs/hwui/TextDropShadowCache.cpp6
-rw-r--r--libs/hwui/TextDropShadowCache.h21
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.