diff options
author | Romain Guy <romainguy@google.com> | 2010-08-02 18:50:22 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2010-08-02 18:50:56 -0700 |
commit | db1938e0e6ef816e228c815adccebd5cb05f2aa8 (patch) | |
tree | d40e91a873bca6750083fdb1713a12b469ebad4d | |
parent | 16f8c620abd0ea07e704b6997a66a45ad3590dea (diff) | |
download | frameworks_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
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); |