summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2012-07-16 17:04:24 -0700
committerRomain Guy <romainguy@google.com>2012-07-16 17:04:24 -0700
commit4121063313ac0d6f69f6253cac821d0c1c122086 (patch)
treeb076706786610f6c87c275355b8853289cbfd0f7 /libs
parent157bd5749f40b0330fccf3ef159d922742103ef2 (diff)
downloadframeworks_base-4121063313ac0d6f69f6253cac821d0c1c122086.zip
frameworks_base-4121063313ac0d6f69f6253cac821d0c1c122086.tar.gz
frameworks_base-4121063313ac0d6f69f6253cac821d0c1c122086.tar.bz2
Add shader-based text gamma correction
To enable it, the system property ro.hwui.text_gamma_shader must be set to true. For testing, DEBUG_FONT_RENDERER_FORCE_SHADER_GAMMA can be set to 1 in libhwui/Debug.h. Change-Id: If345c6b71b67ecf1ef2e8847b71f30f3ef251a27
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Debug.h3
-rw-r--r--libs/hwui/GammaFontRenderer.cpp49
-rw-r--r--libs/hwui/GammaFontRenderer.h14
-rw-r--r--libs/hwui/OpenGLRenderer.cpp16
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/Program.h11
-rw-r--r--libs/hwui/ProgramCache.cpp34
7 files changed, 117 insertions, 12 deletions
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 55a860e..13780c3 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -65,6 +65,9 @@
// Turn on to enable additional debugging in the font renderers
#define DEBUG_FONT_RENDERER 0
+// Force gamma correction in shaders
+#define DEBUG_FONT_RENDERER_FORCE_SHADER_GAMMA 0
+
// Turn on to dump display list state
#define DEBUG_DISPLAY_LIST 0
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 75d5b10..226f4bc 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -24,6 +24,18 @@ namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
+// Utils
+///////////////////////////////////////////////////////////////////////////////
+
+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
///////////////////////////////////////////////////////////////////////////////
@@ -36,7 +48,11 @@ GammaFontRenderer* GammaFontRenderer::createRenderer() {
}
}
+#if DEBUG_FONT_RENDERER_FORCE_SHADER_GAMMA
+ return new ShaderGammaFontRenderer();
+#else
return new LookupGammaFontRenderer();
+#endif
}
GammaFontRenderer::GammaFontRenderer() {
@@ -82,6 +98,29 @@ GammaFontRenderer::~GammaFontRenderer() {
ShaderGammaFontRenderer::ShaderGammaFontRenderer(): GammaFontRenderer() {
INIT_LOGD("Creating shader gamma font renderer");
+ mRenderer = NULL;
+}
+
+void ShaderGammaFontRenderer::describe(ProgramDescription& description,
+ const SkPaint* paint) const {
+ if (paint->getShader() == NULL) {
+ 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;
+ }
+ }
+}
+
+void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description,
+ Program* program) const {
+ if (description.hasGammaCorrection) {
+ glUniform1f(program->getUniform("gamma"), description.gamma);
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -164,15 +203,11 @@ FontRenderer* LookupGammaFontRenderer::getRenderer(Gamma gamma) {
FontRenderer& LookupGammaFontRenderer::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 988947a..8e1db78 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -20,6 +20,7 @@
#include <SkPaint.h>
#include "FontRenderer.h"
+#include "Program.h"
namespace android {
namespace uirenderer {
@@ -34,9 +35,11 @@ public:
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:
@@ -79,6 +82,9 @@ public:
return mRenderer->getCacheSize();
}
+ void describe(ProgramDescription& description, const SkPaint* paint) const;
+ void setupProgram(ProgramDescription& description, Program* program) const;
+
private:
ShaderGammaFontRenderer();
@@ -109,6 +115,12 @@ public:
return renderer->getCacheSize();
}
+ void describe(ProgramDescription& description, const SkPaint* paint) const {
+ }
+
+ void setupProgram(ProgramDescription& description, Program* program) const {
+ }
+
private:
LookupGammaFontRenderer();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 99016d6..64b6c17 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1174,6 +1174,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;
@@ -1301,6 +1305,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);
@@ -2302,6 +2310,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);
@@ -2314,6 +2323,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);
@@ -2387,6 +2397,8 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
if (CC_UNLIKELY(mHasShadow)) {
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);
@@ -2427,6 +2439,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);
@@ -2441,6 +2454,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);
@@ -2485,6 +2499,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);
@@ -2497,6 +2512,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);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 8bdc450..7795d08 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -572,6 +572,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,
@@ -596,6 +597,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 e9c666b..491767f 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -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..fc60279 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -159,6 +159,9 @@ 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";
@@ -184,10 +187,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 +213,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"
@@ -517,6 +530,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 +560,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 +667,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]);