summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger/RenderEngine
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2013-09-01 21:36:12 -0700
committerMathias Agopian <mathias@google.com>2013-09-04 22:11:15 -0700
commitff2ed70fa30f04b90dd1a2c06ec2319e157152d7 (patch)
treece07917c9844239d37b000afd2518b08028ed8be /services/surfaceflinger/RenderEngine
parent1d4d8f94e2989b7c8667602304df9059d2701653 (diff)
downloadframeworks_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')
-rw-r--r--services/surfaceflinger/RenderEngine/Description.cpp10
-rw-r--r--services/surfaceflinger/RenderEngine/Description.h4
-rw-r--r--services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp8
-rw-r--r--services/surfaceflinger/RenderEngine/GLES11RenderEngine.h3
-rw-r--r--services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp82
-rw-r--r--services/surfaceflinger/RenderEngine/GLES20RenderEngine.h14
-rw-r--r--services/surfaceflinger/RenderEngine/Mesh.h30
-rw-r--r--services/surfaceflinger/RenderEngine/Program.cpp4
-rw-r--r--services/surfaceflinger/RenderEngine/Program.h3
-rw-r--r--services/surfaceflinger/RenderEngine/ProgramCache.cpp22
-rw-r--r--services/surfaceflinger/RenderEngine/ProgramCache.h7
-rw-r--r--services/surfaceflinger/RenderEngine/RenderEngine.cpp2
-rw-r--r--services/surfaceflinger/RenderEngine/RenderEngine.h7
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;