summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2010-08-02 18:50:22 -0700
committerRomain Guy <romainguy@google.com>2010-08-02 18:50:56 -0700
commitdb1938e0e6ef816e228c815adccebd5cb05f2aa8 (patch)
treed40e91a873bca6750083fdb1713a12b469ebad4d
parent16f8c620abd0ea07e704b6997a66a45ad3590dea (diff)
downloadframeworks_base-db1938e0e6ef816e228c815adccebd5cb05f2aa8.zip
frameworks_base-db1938e0e6ef816e228c815adccebd5cb05f2aa8.tar.gz
frameworks_base-db1938e0e6ef816e228c815adccebd5cb05f2aa8.tar.bz2
Add support for ColorFilters.
Color filters are fully supported and can be used with shaders. Change-Id: Id90ccf1c81cb462f2431f366f3f8f710d7971e04
-rw-r--r--core/java/android/view/GLES20Canvas.java60
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp65
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp14
-rw-r--r--graphics/java/android/graphics/ColorFilter.java16
-rw-r--r--graphics/java/android/graphics/ColorMatrixColorFilter.java6
-rw-r--r--graphics/java/android/graphics/LightingColorFilter.java2
-rw-r--r--graphics/java/android/graphics/PorterDuffColorFilter.java8
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/Extensions.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp39
-rw-r--r--libs/hwui/OpenGLRenderer.h7
-rw-r--r--libs/hwui/ProgramCache.cpp37
-rw-r--r--libs/hwui/ProgramCache.h4
-rw-r--r--libs/hwui/SkiaColorFilter.cpp102
-rw-r--r--libs/hwui/SkiaColorFilter.h118
-rw-r--r--libs/hwui/SkiaShader.h6
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/google/android/test/hwui/ColorFiltersActivity.java97
-rw-r--r--tests/HwAccelerationTest/src/com/google/android/test/hwui/MoreShadersActivity.java7
19 files changed, 537 insertions, 63 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 21e6793..63a0c4c 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.ColorFilter;
import android.graphics.DrawFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -376,9 +377,11 @@ class GLES20Canvas extends Canvas {
@Override
public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
// Shaders are ignored when drawing patches
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top,
dst.right, dst.bottom, nativePaint);
+ if (hasColorFilter) nResetModifiers(mRenderer);
}
private native void nDrawPatch(int renderer, int bitmap, byte[] chunks, float left, float top,
@@ -387,8 +390,10 @@ class GLES20Canvas extends Canvas {
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
// Shaders are ignored when drawing bitmaps
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
+ if (hasColorFilter) nResetModifiers(mRenderer);
}
private native void nDrawBitmap(int renderer, int bitmap, float left, float top, int paint);
@@ -396,8 +401,10 @@ class GLES20Canvas extends Canvas {
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
// Shaders are ignored when drawing bitmaps
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
+ if (hasColorFilter) nResetModifiers(mRenderer);
}
private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint);
@@ -405,6 +412,7 @@ class GLES20Canvas extends Canvas {
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
// Shaders are ignored when drawing bitmaps
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
int left, top, right, bottom;
@@ -421,14 +429,17 @@ class GLES20Canvas extends Canvas {
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+ if (hasColorFilter) nResetModifiers(mRenderer);
}
@Override
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
// Shaders are ignored when drawing bitmaps
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+ if (hasColorFilter) nResetModifiers(mRenderer);
}
private native void nDrawBitmap(int renderer, int bitmap,
@@ -439,11 +450,13 @@ class GLES20Canvas extends Canvas {
public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
int width, int height, boolean hasAlpha, Paint paint) {
// Shaders are ignored when drawing bitmaps
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
b.recycle();
+ if (hasColorFilter) nResetModifiers(mRenderer);
}
@Override
@@ -556,9 +569,9 @@ class GLES20Canvas extends Canvas {
@Override
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
- boolean hasShader = setupShader(paint);
+ boolean hasModifier = setupModifiers(paint);
nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
- if (hasShader) nResetShader(mRenderer);
+ if (hasModifier) nResetModifiers(mRenderer);
}
private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
@@ -589,9 +602,9 @@ class GLES20Canvas extends Canvas {
if ((index | count | (index + count) | (text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
- boolean hasShader = setupShader(paint);
+ boolean hasModifier = setupModifiers(paint);
nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
- if (hasShader) nResetShader(mRenderer);
+ if (hasModifier) nResetModifiers(mRenderer);
}
private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
@@ -599,7 +612,7 @@ class GLES20Canvas extends Canvas {
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
- boolean hasShader = setupShader(paint);
+ boolean hasModifier = setupModifiers(paint);
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
@@ -613,7 +626,7 @@ class GLES20Canvas extends Canvas {
nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
- if (hasShader) nResetShader(mRenderer);
+ if (hasModifier) nResetModifiers(mRenderer);
}
@Override
@@ -621,9 +634,9 @@ class GLES20Canvas extends Canvas {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
- boolean hasShader = setupShader(paint);
+ boolean hasModifier = setupModifiers(paint);
nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
- if (hasShader) nResetShader(mRenderer);
+ if (hasModifier) nResetModifiers(mRenderer);
}
private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
@@ -631,9 +644,9 @@ class GLES20Canvas extends Canvas {
@Override
public void drawText(String text, float x, float y, Paint paint) {
- boolean hasShader = setupShader(paint);
+ boolean hasModifier = setupModifiers(paint);
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, paint.mNativePaint);
- if (hasShader) nResetShader(mRenderer);
+ if (hasModifier) nResetModifiers(mRenderer);
}
@Override
@@ -666,15 +679,34 @@ class GLES20Canvas extends Canvas {
// TODO: Implement
}
- private boolean setupShader(Paint paint) {
+ private boolean setupModifiers(Paint paint) {
+ boolean hasModifier = false;
+
final Shader shader = paint.getShader();
if (shader != null) {
nSetupShader(mRenderer, shader.native_shader);
+ hasModifier = true;
+ }
+
+ final ColorFilter filter = paint.getColorFilter();
+ if (filter != null) {
+ nSetupColorFilter(mRenderer, filter.nativeColorFilter);
+ hasModifier = true;
+ }
+
+ return hasModifier;
+ }
+
+ private boolean setupColorFilter(Paint paint) {
+ final ColorFilter filter = paint.getColorFilter();
+ if (filter != null) {
+ nSetupColorFilter(mRenderer, filter.nativeColorFilter);
return true;
}
- return false;
+ return false;
}
-
+
private native void nSetupShader(int renderer, int shader);
- private native void nResetShader(int renderer);
+ private native void nSetupColorFilter(int renderer, int colorFilter);
+ private native void nResetModifiers(int renderer);
}
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index ebfb209..848234f 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -23,28 +23,38 @@
#include "SkColorMatrixFilter.h"
#include "SkPorterDuff.h"
+#include <SkiaColorFilter.h>
+
namespace android {
+using namespace uirenderer;
+
class SkColorFilterGlue {
public:
-
- static void finalizer(JNIEnv* env, jobject clazz, SkColorFilter* obj) {
+ static void finalizer(JNIEnv* env, jobject clazz, SkColorFilter* obj, SkiaColorFilter* f) {
+ delete f;
obj->safeUnref();
}
- static SkColorFilter* CreatePorterDuffFilter(JNIEnv* env, jobject,
- jint srcColor, SkPorterDuff::Mode mode) {
- return SkColorFilter::CreateModeFilter(srcColor,
- SkPorterDuff::ToXfermodeMode(mode));
+ static SkColorFilter* CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
+ SkPorterDuff::Mode mode) {
+ return SkColorFilter::CreateModeFilter(srcColor, SkPorterDuff::ToXfermodeMode(mode));
}
- static SkColorFilter* CreateLightingFilter(JNIEnv* env, jobject,
- jint mul, jint add) {
+ static SkiaColorFilter* glCreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
+ SkPorterDuff::Mode mode) {
+ return new SkiaBlendFilter(srcColor, SkPorterDuff::ToXfermodeMode(mode));
+ }
+
+ static SkColorFilter* CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
return SkColorFilter::CreateLightingFilter(mul, add);
}
- static SkColorFilter* CreateColorMatrixFilter(JNIEnv* env, jobject,
- jfloatArray jarray) {
+ static SkiaColorFilter* glCreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
+ return new SkiaLightingFilter(mul, add);
+ }
+
+ static SkColorFilter* CreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) {
AutoJavaFloatArray autoArray(env, jarray, 20);
const float* src = autoArray.ptr();
@@ -58,26 +68,44 @@ public:
return new SkColorMatrixFilter(src);
#endif
}
-
+
+ static SkiaColorFilter* glCreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) {
+ AutoJavaFloatArray autoArray(env, jarray, 20);
+ const float* src = autoArray.ptr();
+
+ float* colorMatrix = new float[16];
+ memcpy(colorMatrix, src, 4 * sizeof(float));
+ memcpy(&colorMatrix[4], &src[5], 4 * sizeof(float));
+ memcpy(&colorMatrix[8], &src[10], 4 * sizeof(float));
+ memcpy(&colorMatrix[12], &src[15], 4 * sizeof(float));
+
+ float* colorVector = new float[4];
+ colorVector[0] = src[4];
+ colorVector[1] = src[9];
+ colorVector[2] = src[14];
+ colorVector[3] = src[19];
+
+ return new SkiaColorMatrixFilter(colorMatrix, colorVector);
+ }
};
static JNINativeMethod colorfilter_methods[] = {
- {"finalizer", "(I)V", (void*) SkColorFilterGlue::finalizer}
+ {"finalizer", "(II)V", (void*) SkColorFilterGlue::finalizer}
};
static JNINativeMethod porterduff_methods[] = {
- {"native_CreatePorterDuffFilter","(II)I",
- (void*) SkColorFilterGlue::CreatePorterDuffFilter}
+ { "native_CreatePorterDuffFilter", "(II)I", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
+ { "nCreatePorterDuffFilter", "(II)I", (void*) SkColorFilterGlue::glCreatePorterDuffFilter }
};
static JNINativeMethod lighting_methods[] = {
- {"native_CreateLightingFilter","(II)I",
- (void*) SkColorFilterGlue::CreateLightingFilter}
+ { "native_CreateLightingFilter", "(II)I", (void*) SkColorFilterGlue::CreateLightingFilter },
+ { "nCreateLightingFilter", "(II)I", (void*) SkColorFilterGlue::glCreateLightingFilter },
};
static JNINativeMethod colormatrix_methods[] = {
- {"nativeColorMatrixFilter","([F)I",
- (void*) SkColorFilterGlue::CreateColorMatrixFilter}
+ { "nativeColorMatrixFilter", "([F)I", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
+ { "nColorMatrixFilter", "([F)I", (void*) SkColorFilterGlue::glCreateColorMatrixFilter }
};
#define REG(env, name, array) \
@@ -85,7 +113,6 @@ static JNINativeMethod colormatrix_methods[] = {
SK_ARRAY_COUNT(array)); \
if (result < 0) return result
-
int register_android_graphics_ColorFilter(JNIEnv* env) {
int result;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index ece9636..142e194 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -31,6 +31,7 @@
#include <OpenGLRenderer.h>
#include <SkiaShader.h>
+#include <SkiaColorFilter.h>
#include <Rect.h>
#include <ui/Rect.h>
@@ -228,12 +229,13 @@ static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas,
}
// ----------------------------------------------------------------------------
-// Shaders
+// Shaders and color filters
// ----------------------------------------------------------------------------
-static void android_view_GLES20Canvas_resetShader(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject canvas,
OpenGLRenderer* renderer) {
renderer->resetShader();
+ renderer->resetColorFilter();
}
static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject canvas,
@@ -241,6 +243,11 @@ static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject canvas,
renderer->setupShader(shader);
}
+static void android_view_GLES20Canvas_setupColorFilter(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, SkiaColorFilter* filter) {
+ renderer->setupColorFilter(filter);
+}
+
// ----------------------------------------------------------------------------
// Text
// ----------------------------------------------------------------------------
@@ -311,8 +318,9 @@ static JNINativeMethod gMethods[] = {
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor },
{ "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect },
- { "nResetShader", "(I)V", (void*) android_view_GLES20Canvas_resetShader },
+ { "nResetModifiers", "(I)V", (void*) android_view_GLES20Canvas_resetModifiers },
{ "nSetupShader", "(II)V", (void*) android_view_GLES20Canvas_setupShader },
+ { "nSetupColorFilter", "(II)V", (void*) android_view_GLES20Canvas_setupColorFilter },
{ "nDrawText", "(I[CIIFFII)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "nDrawText", "(ILjava/lang/String;IIFFII)V",
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index 76f2c7f..e5cf830 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -23,12 +23,20 @@ package android.graphics;
public class ColorFilter {
+ int native_instance;
+
+ /**
+ * @hide
+ */
+ public int nativeColorFilter;
protected void finalize() throws Throwable {
- finalizer(native_instance);
+ try {
+ super.finalize();
+ } finally {
+ finalizer(native_instance, nativeColorFilter);
+ }
}
- private static native void finalizer(int native_instance);
-
- int native_instance;
+ private static native void finalizer(int native_instance, int nativeColorFilter);
}
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 5d73cff..245c615 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -25,7 +25,9 @@ public class ColorMatrixColorFilter extends ColorFilter {
* is constructed will not be reflected in the filter.
*/
public ColorMatrixColorFilter(ColorMatrix matrix) {
- native_instance = nativeColorMatrixFilter(matrix.getArray());
+ final float[] colorMatrix = matrix.getArray();
+ native_instance = nativeColorMatrixFilter(colorMatrix);
+ nativeColorFilter = nColorMatrixFilter(colorMatrix);
}
/**
@@ -40,7 +42,9 @@ public class ColorMatrixColorFilter extends ColorFilter {
throw new ArrayIndexOutOfBoundsException();
}
native_instance = nativeColorMatrixFilter(array);
+ nativeColorFilter = nColorMatrixFilter(array);
}
private static native int nativeColorMatrixFilter(float[] array);
+ private static native int nColorMatrixFilter(float[] array);
}
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index 5562389..715ce86 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -30,7 +30,9 @@ public class LightingColorFilter extends ColorFilter {
*/
public LightingColorFilter(int mul, int add) {
native_instance = native_CreateLightingFilter(mul, add);
+ nativeColorFilter = nCreateLightingFilter(mul, add);
}
private static native int native_CreateLightingFilter(int mul, int add);
+ private static native int nCreateLightingFilter(int mul, int add);
}
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 06724bd..b02dab1 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -25,10 +25,10 @@ public class PorterDuffColorFilter extends ColorFilter {
* @param mode The porter-duff mode that is applied
*/
public PorterDuffColorFilter(int srcColor, PorterDuff.Mode mode) {
- native_instance = native_CreatePorterDuffFilter(srcColor,
- mode.nativeInt);
+ native_instance = native_CreatePorterDuffFilter(srcColor, mode.nativeInt);
+ nativeColorFilter = nCreatePorterDuffFilter(srcColor, mode.nativeInt);
}
- private static native int native_CreatePorterDuffFilter(int srcColor,
- int porterDuffMode);
+ private static native int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode);
+ private static native int nCreatePorterDuffFilter(int srcColor, int porterDuffMode);
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index fe1b524..8f28612 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \
PatchCache.cpp \
Program.cpp \
ProgramCache.cpp \
+ SkiaColorFilter.cpp \
SkiaShader.cpp \
TextureCache.cpp
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 99b34dd..7778290 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-
#ifndef ANDROID_UI_EXTENSIONS_H
#define ANDROID_UI_EXTENSIONS_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 187e9d8..d694039 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -132,6 +132,7 @@ OpenGLRenderer::OpenGLRenderer():
mCurrentProgram = NULL;
mShader = NULL;
+ mColorFilter = NULL;
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
@@ -460,7 +461,6 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
const float u2 = srcRight / width;
const float v2 = srcBottom / height;
- // TODO: Do this in the shader
resetDrawTextureTexCoords(u1, v1, u2, v2);
drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
@@ -552,6 +552,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
mModelView.loadIdentity();
GLuint textureUnit = 0;
+ // Needs to be set prior to calling FontRenderer::getTexture()
+ glActiveTexture(gTextureUnits[textureUnit]);
ProgramDescription description;
description.hasTexture = true;
@@ -559,10 +561,14 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
if (mShader) {
mShader->describe(description, mExtensions);
}
+ if (mColorFilter) {
+ mColorFilter->describe(description, mExtensions);
+ }
useProgram(mProgramCache.get(description));
mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ // Text is always blended, no need to check the shader
chooseBlending(true, mode);
bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
glUniform1i(mCurrentProgram->getUniform("sampler"), textureUnit);
@@ -578,6 +584,9 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
if (mShader) {
mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
}
+ if (mColorFilter) {
+ mColorFilter->setupProgram(mCurrentProgram);
+ }
// TODO: Implement scale properly
const Rect& clip = mSnapshot->getLocalClip();
@@ -604,6 +613,18 @@ void OpenGLRenderer::setupShader(SkiaShader* shader) {
}
///////////////////////////////////////////////////////////////////////////////
+// Color filters
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::resetColorFilter() {
+ mColorFilter = NULL;
+}
+
+void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
+ mColorFilter = filter;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Drawing implementation
///////////////////////////////////////////////////////////////////////////////
@@ -631,6 +652,9 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
if (mShader) {
mShader->describe(description, mExtensions);
}
+ if (mColorFilter) {
+ mColorFilter->describe(description, mExtensions);
+ }
// Build and use the appropriate shader
useProgram(mProgramCache.get(description));
@@ -654,6 +678,9 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
if (mShader) {
mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
}
+ if (mColorFilter) {
+ mColorFilter->setupProgram(mCurrentProgram);
+ }
// Draw the mesh
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -680,6 +707,9 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
ProgramDescription description;
description.hasTexture = true;
+ if (mColorFilter) {
+ mColorFilter->describe(description, mExtensions);
+ }
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
@@ -703,6 +733,11 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
gMeshStride, vertices);
glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
+ // Color filter
+ if (mColorFilter) {
+ mColorFilter->setupProgram(mCurrentProgram);
+ }
+
if (!indices) {
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
} else {
@@ -712,8 +747,6 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
}
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
- // In theory we should not blend if the mode is Src, but it's rare enough
- // that it's not worth it
blend = blend || mode != SkXfermode::kSrcOver_Mode;
if (blend) {
if (!mBlend) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index dc0f50f..d2a291f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -43,6 +43,7 @@
#include "FontRenderer.h"
#include "ProgramCache.h"
#include "SkiaShader.h"
+#include "SkiaColorFilter.h"
namespace android {
namespace uirenderer {
@@ -95,6 +96,9 @@ public:
void resetShader();
void setupShader(SkiaShader* shader);
+ void resetColorFilter();
+ void setupColorFilter(SkiaColorFilter* filter);
+
void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
private:
@@ -281,6 +285,9 @@ private:
Program* mCurrentProgram;
SkiaShader* mShader;
+ // Color filters
+ SkiaColorFilter* mColorFilter;
+
// Used to draw textured quads
TextureVertex mMeshVertices[4];
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 23923f6..3205258 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -27,8 +27,6 @@ namespace uirenderer {
// Vertex shaders snippets
///////////////////////////////////////////////////////////////////////////////
-// TODO: Implement BitmapShader, implement repeat/mirror for npot
-
const char* gVS_Header_Attributes =
"attribute vec4 position;\n";
const char* gVS_Header_Attributes_TexCoords =
@@ -85,10 +83,10 @@ const char* gFS_Uniforms_ColorOp[4] = {
"uniform mat4 colorMatrix;\n"
"uniform vec4 colorMatrixVector;\n",
// Lighting
- "uniform float lightingMul;\n"
- "uniform float lightingAdd;\n",
+ "uniform vec4 lightingMul;\n"
+ "uniform vec4 lightingAdd;\n",
// PorterDuff
- "uniform vec4 colorBLend;\n"
+ "uniform vec4 colorBlend;\n"
};
const char* gFS_Main =
"\nvoid main(void) {\n"
@@ -121,11 +119,14 @@ const char* gFS_Main_ApplyColorOp[4] = {
// None
"",
// Matrix
+ // TODO: Fix premultiplied alpha computations for color matrix
" fragColor *= colorMatrix;\n"
- " fragColor += colorMatrixVector;\n",
+ " fragColor += colorMatrixVector;\n"
+ " fragColor.rgb *= fragColor.a;\n",
// Lighting
- " fragColor *= lightingMul;\n"
- " fragColor += lightingAdd;\n",
+ " float lightingAlpha = fragColor.a;\n"
+ " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
+ " fragColor.a = lightingAlpha;\n",
// PorterDuff
" fragColor = blendColors(colorBlend, fragColor);\n"
};
@@ -345,7 +346,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
// End the shader
shader.append(gFS_Footer);
- PROGRAM_LOGD("*** Generated fragment shader:\n\n%s", shader.string());
+ if (DEBUG_PROGRAM_CACHE) {
+ PROGRAM_LOGD("*** Generated fragment shader:\n\n");
+ printLongString(shader);
+ }
+
return shader;
}
@@ -391,5 +396,19 @@ void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wra
shader.append("}\n");
}
+void ProgramCache::printLongString(const String8& shader) const {
+ ssize_t index = 0;
+ ssize_t lastIndex = 0;
+ const char* str = shader.string();
+ while ((index = shader.find("\n", index)) > -1) {
+ String8 line(str, index - lastIndex);
+ if (line.length() == 0) line.append("\n");
+ PROGRAM_LOGD("%s", line.string());
+ index++;
+ str += (index - lastIndex);
+ lastIndex = index;
+ }
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index d60f6ce..a1a4a0e 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -35,7 +35,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Debug
-#define DEBUG_PROGRAM_CACHE 1
+#define DEBUG_PROGRAM_CACHE 0
// Debug
#if DEBUG_PROGRAM_CACHE
@@ -180,6 +180,8 @@ private:
void generatePorterDuffBlend(String8& shader, const char* name, SkXfermode::Mode mode);
void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
+ void printLongString(const String8& shader) const;
+
KeyedVector<programid, Program*> mCache;
}; // class ProgramCache
diff --git a/libs/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp
new file mode 100644
index 0000000..fe57ae7
--- /dev/null
+++ b/libs/hwui/SkiaColorFilter.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkiaColorFilter.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Base color filter
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaColorFilter::SkiaColorFilter(Type type, bool blend): mType(type), mBlend(blend) {
+}
+
+SkiaColorFilter::~SkiaColorFilter() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Color matrix filter
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaColorMatrixFilter::SkiaColorMatrixFilter(float* matrix, float* vector):
+ SkiaColorFilter(kColorMatrix, true), mMatrix(matrix), mVector(vector) {
+}
+
+SkiaColorMatrixFilter::~SkiaColorMatrixFilter() {
+ delete[] mMatrix;
+ delete[] mVector;
+}
+
+void SkiaColorMatrixFilter::describe(ProgramDescription& description,
+ const Extensions& extensions) {
+ description.colorOp = ProgramDescription::kColorMatrix;
+}
+
+void SkiaColorMatrixFilter::setupProgram(Program* program) {
+ glUniformMatrix4fv(program->getUniform("colorMatrix"), 1, GL_FALSE, &mMatrix[0]);
+ glUniform4fv(program->getUniform("colorMatrixVector"), 1, mVector);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Lighting color filter
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaLightingFilter::SkiaLightingFilter(int multiply, int add):
+ SkiaColorFilter(kLighting, true) {
+ mMulR = ((multiply >> 16) & 0xFF) / 255.0f;
+ mMulG = ((multiply >> 8) & 0xFF) / 255.0f;
+ mMulB = ((multiply ) & 0xFF) / 255.0f;
+
+ mAddR = ((add >> 16) & 0xFF) / 255.0f;
+ mAddG = ((add >> 8) & 0xFF) / 255.0f;
+ mAddB = ((add ) & 0xFF) / 255.0f;
+}
+
+void SkiaLightingFilter::describe(ProgramDescription& description, const Extensions& extensions) {
+ description.colorOp = ProgramDescription::kColorLighting;
+}
+
+void SkiaLightingFilter::setupProgram(Program* program) {
+ glUniform4f(program->getUniform("lightingMul"), mMulR, mMulG, mMulB, 1.0f);
+ glUniform4f(program->getUniform("lightingAdd"), mAddR, mAddG, mAddB, 0.0f);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Blend color filter
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaBlendFilter::SkiaBlendFilter(int color, SkXfermode::Mode mode):
+ SkiaColorFilter(kBlend, true), mMode(mode) {
+ const int alpha = (color >> 24) & 0xFF;
+ mA = alpha / 255.0f;
+ mR = mA * ((color >> 16) & 0xFF) / 255.0f;
+ mG = mA * ((color >> 8) & 0xFF) / 255.0f;
+ mB = mA * ((color ) & 0xFF) / 255.0f;
+}
+
+void SkiaBlendFilter::describe(ProgramDescription& description, const Extensions& extensions) {
+ description.colorOp = ProgramDescription::kColorBlend;
+ description.colorMode = mMode;
+}
+
+void SkiaBlendFilter::setupProgram(Program* program) {
+ glUniform4f(program->getUniform("colorBlend"), mR, mG, mB, mA);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
new file mode 100644
index 0000000..865b6f0
--- /dev/null
+++ b/libs/hwui/SkiaColorFilter.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_SKIA_COLOR_FILTER_H
+#define ANDROID_UI_SKIA_COLOR_FILTER_H
+
+#include <GLES2/gl2.h>
+
+#include "ProgramCache.h"
+#include "Extensions.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Base color filter
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Represents a Skia color filter. A color filter modifies a ProgramDescription
+ * and sets uniforms on the resulting shaders.
+ */
+struct SkiaColorFilter {
+ /**
+ * Type of Skia color filter in use.
+ */
+ enum Type {
+ kNone,
+ kColorMatrix,
+ kLighting,
+ kBlend,
+ };
+
+ SkiaColorFilter(Type type, bool blend);
+ virtual ~SkiaColorFilter();
+
+ virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
+ virtual void setupProgram(Program* program) = 0;
+
+ inline bool blend() const {
+ return mBlend;
+ }
+
+ Type type() const {
+ return mType;
+ }
+
+protected:
+ Type mType;
+ bool mBlend;
+}; // struct SkiaColorFilter
+
+///////////////////////////////////////////////////////////////////////////////
+// Implementations
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A color filter that multiplies the source color with a matrix and adds a vector.
+ */
+struct SkiaColorMatrixFilter: public SkiaColorFilter {
+ SkiaColorMatrixFilter(float* matrix, float* vector);
+ ~SkiaColorMatrixFilter();
+
+ void describe(ProgramDescription& description, const Extensions& extensions);
+ void setupProgram(Program* program);
+
+private:
+ float* mMatrix;
+ float* mVector;
+}; // struct SkiaColorMatrixFilter
+
+/**
+ * A color filters that multiplies the source color with a fixed value and adds
+ * another fixed value. Ignores the alpha channel of both arguments.
+ */
+struct SkiaLightingFilter: public SkiaColorFilter {
+ SkiaLightingFilter(int multiply, int add);
+
+ void describe(ProgramDescription& description, const Extensions& extensions);
+ void setupProgram(Program* program);
+
+private:
+ GLfloat mMulR, mMulG, mMulB;
+ GLfloat mAddR, mAddG, mAddB;
+}; // struct SkiaLightingFilter
+
+/**
+ * A color filters that blends the source color with a specified destination color
+ * and PorterDuff blending mode.
+ */
+struct SkiaBlendFilter: public SkiaColorFilter {
+ SkiaBlendFilter(int color, SkXfermode::Mode mode);
+
+ void describe(ProgramDescription& description, const Extensions& extensions);
+ void setupProgram(Program* program);
+
+private:
+ SkXfermode::Mode mMode;
+ GLfloat mR, mG, mB, mA;
+}; // struct SkiaBlendFilter
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_SKIA_COLOR_FILTER_H
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index b5e6aeb..c19eac3 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef SKIA_SHADER_H
-#define SKIA_SHADER_H
+#ifndef ANDROID_UI_SKIA_SHADER_H
+#define ANDROID_UI_SKIA_SHADER_H
#include <SkShader.h>
#include <SkXfermode.h>
@@ -160,4 +160,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // SKIA_SHADER_H
+#endif // ANDROID_UI_SKIA_SHADER_H
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index f917dd5..b615657 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -133,6 +133,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="ColorFiltersActivity"
+ android:label="_ColorFilters">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ColorFiltersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ColorFiltersActivity.java
new file mode 100644
index 0000000..49e1eaa
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ColorFiltersActivity.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.LightingColorFilter;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ColorFiltersActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final BitmapsView view = new BitmapsView(this);
+ setContentView(view);
+ }
+
+ static class BitmapsView extends View {
+ private final Bitmap mBitmap1;
+ private final Bitmap mBitmap2;
+ private final Paint mColorMatrixPaint;
+ private final Paint mLightingPaint;
+ private final Paint mBlendPaint;
+
+ BitmapsView(Context c) {
+ super(c);
+
+ mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+ mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2);
+
+ mColorMatrixPaint = new Paint();
+ final ColorMatrix colorMatrix = new ColorMatrix();
+ colorMatrix.setSaturation(0);
+ mColorMatrixPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
+
+ mLightingPaint = new Paint();
+ mLightingPaint.setColorFilter(new LightingColorFilter(0x0060ffff, 0x00101030));
+
+ mBlendPaint = new Paint();
+ mBlendPaint.setColorFilter(new PorterDuffColorFilter(0x7f990040,
+ PorterDuff.Mode.SRC_OVER));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.drawARGB(255, 255, 255, 255);
+
+ canvas.save();
+ canvas.translate(120.0f, 50.0f);
+ canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mColorMatrixPaint);
+
+ canvas.translate(0.0f, 50.0f + mBitmap1.getHeight());
+ canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mLightingPaint);
+
+ canvas.translate(0.0f, 50.0f + mBitmap1.getHeight());
+ canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBlendPaint);
+ canvas.restore();
+
+ canvas.save();
+ canvas.translate(120.0f + mBitmap1.getWidth() + 120.0f, 50.0f);
+ canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mColorMatrixPaint);
+
+ canvas.translate(0.0f, 50.0f + mBitmap2.getHeight());
+ canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mLightingPaint);
+
+ canvas.translate(0.0f, 50.0f + mBitmap2.getHeight());
+ canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBlendPaint);
+ canvas.restore();
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/MoreShadersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/MoreShadersActivity.java
index cbf34a0..f43eeba 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/MoreShadersActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/MoreShadersActivity.java
@@ -23,7 +23,9 @@ import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.ComposeShader;
+import android.graphics.LightingColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -54,6 +56,7 @@ public class MoreShadersActivity extends Activity {
private ComposeShader mCompose2Shader;
private Paint mLargePaint;
private BitmapShader mScaled2Shader;
+ private ColorFilter mColorFilter;
ShadersView(Context c) {
super(c);
@@ -87,6 +90,8 @@ public class MoreShadersActivity extends Activity {
mCompose2Shader = new ComposeShader(mHorGradient, mScaledShader,
PorterDuff.Mode.SRC_OUT);
+ mColorFilter = new LightingColorFilter(0x0060ffff, 0x00101030);
+
mLargePaint = new Paint();
mLargePaint.setAntiAlias(true);
mLargePaint.setTextSize(36.0f);
@@ -122,7 +127,9 @@ public class MoreShadersActivity extends Activity {
canvas.drawText("OpenGL rendering", 0.0f, 60.0f, mLargePaint);
mLargePaint.setShader(mCompose2Shader);
+ mLargePaint.setColorFilter(mColorFilter);
canvas.drawText("OpenGL rendering", 0.0f, 100.0f, mLargePaint);
+ mLargePaint.setColorFilter(null);
canvas.translate(0.0f, 40.0f + mDrawHeight);
mLargePaint.setShader(mVertGradient);