Add support for ColorFilters.

Color filters are fully supported and can be used with shaders.

Change-Id: Id90ccf1c81cb462f2431f366f3f8f710d7971e04
This commit is contained in:
Romain Guy
2010-08-02 18:50:22 -07:00
parent 16f8c620ab
commit db1938e0e6
19 changed files with 537 additions and 63 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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",

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \
PatchCache.cpp \
Program.cpp \
ProgramCache.cpp \
SkiaColorFilter.cpp \
SkiaShader.cpp \
TextureCache.cpp

View File

@@ -14,8 +14,6 @@
* limitations under the License.
*/
#define LOG_TAG "OpenGLRenderer"
#ifndef ANDROID_UI_EXTENSIONS_H
#define ANDROID_UI_EXTENSIONS_H

View File

@@ -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();
@@ -603,6 +612,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) {

View File

@@ -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];

View File

@@ -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

View File

@@ -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

View File

@@ -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

118
libs/hwui/SkiaColorFilter.h Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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);