diff options
author | Romain Guy <romainguy@google.com> | 2012-07-16 17:04:24 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2012-07-16 17:04:24 -0700 |
commit | 4121063313ac0d6f69f6253cac821d0c1c122086 (patch) | |
tree | b076706786610f6c87c275355b8853289cbfd0f7 /libs | |
parent | 157bd5749f40b0330fccf3ef159d922742103ef2 (diff) | |
download | frameworks_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.h | 3 | ||||
-rw-r--r-- | libs/hwui/GammaFontRenderer.cpp | 49 | ||||
-rw-r--r-- | libs/hwui/GammaFontRenderer.h | 14 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/Program.h | 11 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 34 |
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]); |