diff options
author | Mathias Agopian <mathias@google.com> | 2013-09-01 21:36:12 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2013-09-04 22:11:15 -0700 |
commit | ff2ed70fa30f04b90dd1a2c06ec2319e157152d7 (patch) | |
tree | ce07917c9844239d37b000afd2518b08028ed8be /services/surfaceflinger/RenderEngine | |
parent | 1d4d8f94e2989b7c8667602304df9059d2701653 (diff) | |
download | frameworks_native-ff2ed70fa30f04b90dd1a2c06ec2319e157152d7.zip frameworks_native-ff2ed70fa30f04b90dd1a2c06ec2319e157152d7.tar.gz frameworks_native-ff2ed70fa30f04b90dd1a2c06ec2319e157152d7.tar.bz2 |
color blindness enhancement
This is an attempt at improving the experience of
users with color vision impairement.
At this time this feature can only be enabled for
debugging:
adb shell service call SurfaceFlinger 1014 i32 PARAM
with PARAM:
0 : disabled
1 : protanomaly/protanopia simulation
2 : deuteranomaly/deuteranopia simulation
3 : tritanopia/tritanomaly simulation
11, 12, 13: same as above w/ attempted correction/enhancement
The enhancement algorithm tries to spread the "error"
such that tones that would otherwise appear similar can be
distinguished.
Bug: 9465644
Change-Id: I860f7eed0cb81f54ef9cf24ad78155b6395ade48
Diffstat (limited to 'services/surfaceflinger/RenderEngine')
13 files changed, 173 insertions, 23 deletions
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index b0325c6..1adcd1f 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -29,9 +29,10 @@ namespace android { Description::Description() : mUniformsDirty(true) { mPlaneAlpha = 1.0f; - mPremultipliedAlpha = true; + mPremultipliedAlpha = false; mOpaque = true; mTextureEnabled = false; + mColorMatrixEnabled = false; memset(mColor, 0, sizeof(mColor)); } @@ -81,4 +82,11 @@ void Description::setProjectionMatrix(const mat4& mtx) { mUniformsDirty = true; } +void Description::setColorMatrix(const mat4& mtx) { + const mat4 identity; + mColorMatrix = mtx; + mColorMatrixEnabled = (mtx != identity); +} + + } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 0230762..43b835f 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -51,6 +51,9 @@ class Description { // projection matrix mat4 mProjectionMatrix; + bool mColorMatrixEnabled; + mat4 mColorMatrix; + public: Description(); ~Description(); @@ -62,6 +65,7 @@ public: void disableTexture(); void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); void setProjectionMatrix(const mat4& mtx); + void setColorMatrix(const mat4& mtx); private: bool mUniformsDirty; diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp index d0ae253..1cd8cb3 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -237,6 +237,14 @@ void GLES11RenderEngine::drawMesh(const Mesh& mesh) { } } +void GLES11RenderEngine::beginGroup(const mat4& colorTransform) { + // doesn't do anything in GLES 1.1 +} + +void GLES11RenderEngine::endGroup() { + // doesn't do anything in GLES 1.1 +} + void GLES11RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index 1de0443..cd53aab 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -60,6 +60,9 @@ protected: virtual void drawMesh(const Mesh& mesh); + virtual void beginGroup(const mat4& colorTransform); + virtual void endGroup(); + virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 9754758..7112ca8 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -35,7 +35,8 @@ namespace android { // --------------------------------------------------------------------------- -GLES20RenderEngine::GLES20RenderEngine() { +GLES20RenderEngine::GLES20RenderEngine() : + mVpWidth(0), mVpHeight(0) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -58,6 +59,8 @@ GLES20RenderEngine::GLES20RenderEngine() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); + + //mColorBlindnessCorrection = M; } GLES20RenderEngine::~GLES20RenderEngine() { @@ -82,6 +85,8 @@ void GLES20RenderEngine::setViewportAndProjection( glViewport(0, 0, vpw, vph); mState.setProjectionMatrix(m); + mVpWidth = vpw; + mVpHeight = vph; } void GLES20RenderEngine::setupLayerBlending( @@ -156,8 +161,7 @@ void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, // create a Framebuffer Object to render into glGenFramebuffers(1, &name); glBindFramebuffer(GL_FRAMEBUFFER, name); - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); *status = glCheckFramebufferStatus(GL_FRAMEBUFFER); *texName = tname; @@ -205,6 +209,78 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { } } +void GLES20RenderEngine::beginGroup(const mat4& colorTransform) { + + GLuint tname, name; + // create the texture + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + // create a Framebuffer Object to render into + glGenFramebuffers(1, &name); + glBindFramebuffer(GL_FRAMEBUFFER, name); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + + Group group; + group.texture = tname; + group.fbo = name; + group.width = mVpWidth; + group.height = mVpHeight; + group.colorTransform = colorTransform; + + mGroupStack.push(group); +} + +void GLES20RenderEngine::endGroup() { + + const Group group(mGroupStack.top()); + mGroupStack.pop(); + + // activate the previous render target + GLuint fbo = 0; + if (!mGroupStack.isEmpty()) { + fbo = mGroupStack.top().fbo; + } + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // set our state + Texture texture(Texture::TEXTURE_2D, group.texture); + texture.setDimensions(group.width, group.height); + glBindTexture(GL_TEXTURE_2D, group.texture); + + mState.setPlaneAlpha(1.0f); + mState.setPremultipliedAlpha(true); + mState.setOpaque(false); + mState.setTexture(texture); + mState.setColorMatrix(group.colorTransform); + glDisable(GL_BLEND); + + Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2); + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); + Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>()); + position[0] = vec2(0, 0); + position[1] = vec2(group.width, 0); + position[2] = vec2(group.width, group.height); + position[3] = vec2(0, group.height); + texCoord[0] = vec2(0, 0); + texCoord[1] = vec2(1, 0); + texCoord[2] = vec2(1, 1); + texCoord[3] = vec2(0, 1); + drawMesh(mesh); + + // reset color matrix + mState.setColorMatrix(mat4()); + + // free our fbo and texture + glDeleteFramebuffers(1, &group.fbo); + glDeleteTextures(1, &group.texture); +} + void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index eb8f31a..8b67fcc 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -39,8 +39,19 @@ class GLES20RenderEngine : public RenderEngine { GLuint mProtectedTexName; GLint mMaxViewportDims[2]; GLint mMaxTextureSize; + GLuint mVpWidth; + GLuint mVpHeight; + + struct Group { + GLuint texture; + GLuint fbo; + GLuint width; + GLuint height; + mat4 colorTransform; + }; Description mState; + Vector<Group> mGroupStack; virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status); @@ -64,6 +75,9 @@ protected: virtual void drawMesh(const Mesh& mesh); + virtual void beginGroup(const mat4& colorTransform); + virtual void endGroup(); + virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/Mesh.h index 160d765..b6d42b0 100644 --- a/services/surfaceflinger/RenderEngine/Mesh.h +++ b/services/surfaceflinger/RenderEngine/Mesh.h @@ -33,32 +33,28 @@ public: ~Mesh(); /* - * VertexArray handles the stride automatically. It also provides - * a convenient way to set position and texture coordinates by using - * the usual x,y,z,w or s,t,r,q names. + * VertexArray handles the stride automatically. */ + template <typename TYPE> class VertexArray { friend class Mesh; float* mData; size_t mStride; VertexArray(float* data, size_t stride) : mData(data), mStride(stride) { } public: - struct vertexData { - operator float*() { return reinterpret_cast<float*>(this); } - union { - struct { float x, y, z, w; }; - struct { float s, t, r, q; }; - }; - }; - vertexData& operator[](size_t index) { - return *reinterpret_cast<vertexData*>(&mData[index*mStride]); } - - vertexData const& operator[](size_t index) const { - return *reinterpret_cast<vertexData const*>(&mData[index*mStride]); } + TYPE& operator[](size_t index) { + return *reinterpret_cast<TYPE*>(&mData[index*mStride]); + } + TYPE const& operator[](size_t index) const { + return *reinterpret_cast<TYPE const*>(&mData[index*mStride]); + } }; - VertexArray getPositionArray() { return VertexArray(getPositions(), mStride); } - VertexArray getTexCoordArray() { return VertexArray(getTexCoords(), mStride); } + template <typename TYPE> + VertexArray<TYPE> getPositionArray() { return VertexArray<TYPE>(getPositions(), mStride); } + + template <typename TYPE> + VertexArray<TYPE> getTexCoordArray() { return VertexArray<TYPE>(getTexCoords(), mStride); } Primitive getPrimitive() const; diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp index ece0905..4a7fb58 100644 --- a/services/surfaceflinger/RenderEngine/Program.cpp +++ b/services/surfaceflinger/RenderEngine/Program.cpp @@ -58,6 +58,7 @@ Program::Program(const ProgramCache::Key& needs, const char* vertex, const char* mFragmentShader = fragmentId; mInitialized = true; + mColorMatrixLoc = glGetUniformLocation(programId, "colorMatrix"); mProjectionMatrixLoc = glGetUniformLocation(programId, "projection"); mTextureMatrixLoc = glGetUniformLocation(programId, "texture"); mSamplerLoc = glGetUniformLocation(programId, "sampler"); @@ -137,6 +138,9 @@ void Program::setUniforms(const Description& desc) { if (mColorLoc >= 0) { glUniform4fv(mColorLoc, 1, desc.mColor); } + if (mColorMatrixLoc >= 0) { + glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray()); + } // these uniforms are always present glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray()); } diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h index 91bb3db..36bd120 100644 --- a/services/surfaceflinger/RenderEngine/Program.h +++ b/services/surfaceflinger/RenderEngine/Program.h @@ -70,6 +70,9 @@ private: /* location of the projection matrix uniform */ GLint mProjectionMatrixLoc; + /* location of the color matrix uniform */ + GLint mColorMatrixLoc; + /* location of the texture matrix uniform */ GLint mTextureMatrixLoc; diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 62d2eab..09b0ddc 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -96,7 +96,9 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) { .set(Key::BLEND_MASK, description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) .set(Key::OPACITY_MASK, - description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); + description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) + .set(Key::COLOR_MATRIX_MASK, + description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF); return needs; } @@ -139,6 +141,9 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { if (needs.hasPlaneAlpha()) { fs << "uniform float alphaPlane;"; } + if (needs.hasColorMatrix()) { + fs << "uniform mat4 colorMatrix;"; + } fs << "void main(void) {" << indent; if (needs.isTexturing()) { fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; @@ -157,6 +162,21 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { fs << "gl_FragColor.a *= alphaPlane;"; } } + + if (needs.hasColorMatrix()) { + if (!needs.isOpaque() && needs.isPremultiplied()) { + // un-premultiply if needed before linearization + fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;"; + } + fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));"; + fs << "gl_FragColor = colorMatrix*gl_FragColor;"; + fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));"; + if (!needs.isOpaque() && needs.isPremultiplied()) { + // and re-premultiply if needed after gamma correction + fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;"; + } + } + fs << dedent << "}"; return fs.getString(); } diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h index fcbeffd..e8b9dcd 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.h +++ b/services/surfaceflinger/RenderEngine/ProgramCache.h @@ -65,6 +65,10 @@ public: TEXTURE_EXT = 0x00000008, TEXTURE_2D = 0x00000010, TEXTURE_MASK = 0x00000018, + + COLOR_MATRIX_OFF = 0x00000000, + COLOR_MATRIX_ON = 0x00000020, + COLOR_MATRIX_MASK = 0x00000020, }; inline Key() : mKey(0) { } @@ -90,6 +94,9 @@ public: inline bool hasPlaneAlpha() const { return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE; } + inline bool hasColorMatrix() const { + return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; + } // this is the definition of a friend function -- not a method of class Needs friend inline int strictly_order_type(const Key& lhs, const Key& rhs) { diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 2abda82..46f628d 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -149,7 +149,7 @@ void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, size_t c; Rect const* r = region.getArray(&c); Mesh mesh(Mesh::TRIANGLES, c*6, 2); - Mesh::VertexArray position(mesh.getPositionArray()); + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); for (size_t i=0 ; i<c ; i++, r++) { position[i*6 + 0].x = r->left; position[i*6 + 0].y = height - r->top; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index bc88b69..5f331d4 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -23,6 +23,7 @@ #include <EGL/egl.h> #include <EGL/eglext.h> +#include <ui/mat4.h> // --------------------------------------------------------------------------- namespace android { @@ -95,6 +96,12 @@ public: // drawing virtual void drawMesh(const Mesh& mesh) = 0; + // grouping + // creates a color-transform group, everything drawn in the group will be + // transformed by the given color transform when endGroup() is called. + virtual void beginGroup(const mat4& colorTransform) = 0; + virtual void endGroup() = 0; + // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; |