Add extra blending modes.
This change adds the following blending modes for shaders and color filters: Add Multiply Screen Overlay Darken Lighten Change-Id: Iff22f5ce6041b43c71b1857d73013f5010ab3413
This commit is contained in:
@@ -331,13 +331,8 @@ static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
|
||||
static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
|
||||
SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
|
||||
SkXfermode* mode = (SkXfermode*) au.get();
|
||||
SkXfermode::Mode skiaMode;
|
||||
if (!SkXfermode::IsMode(mode, &skiaMode)) {
|
||||
skiaMode = SkXfermode::kSrcOver_Mode;
|
||||
}
|
||||
return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
|
||||
SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode);
|
||||
return new SkiaComposeShader(shaderA, shaderB, mode, shader);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
@@ -348,6 +343,7 @@ static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* s
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
SkXfermode::Mode skiaMode;
|
||||
if (!SkXfermode::IsMode(mode, &skiaMode)) {
|
||||
// TODO: Support other modes
|
||||
skiaMode = SkXfermode::kSrcOver_Mode;
|
||||
}
|
||||
return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
|
||||
|
||||
@@ -137,7 +137,7 @@ const char* gFS_Footer =
|
||||
// PorterDuff snippets
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const char* gPorterDuff[12] = {
|
||||
const char* gBlendOps[18] = {
|
||||
// Clear
|
||||
"return vec4(0.0, 0.0, 0.0, 0.0);\n",
|
||||
// Src
|
||||
@@ -161,8 +161,26 @@ const char* gPorterDuff[12] = {
|
||||
// DstAtop
|
||||
"return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
|
||||
// Xor
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, 1.0, "
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
|
||||
"src.a + dst.a - 2.0 * src.a * dst.a);\n",
|
||||
// Add
|
||||
"return min(src + dst, 1.0);\n",
|
||||
// Multiply
|
||||
"return src * dst;\n",
|
||||
// Screen
|
||||
"return src + dst - src * dst;\n",
|
||||
// Overlay
|
||||
"return clamp(vec4(mix("
|
||||
"2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
|
||||
"src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
|
||||
"step(dst.a, 2.0 * dst.rgb)), "
|
||||
"src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
|
||||
// Darken
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
|
||||
"min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
|
||||
// Lighten
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
|
||||
"max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -292,10 +310,10 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
|
||||
// Generate required functions
|
||||
if (description.hasGradient && description.hasBitmap) {
|
||||
generatePorterDuffBlend(shader, "blendShaders", description.shadersMode);
|
||||
generateBlend(shader, "blendShaders", description.shadersMode);
|
||||
}
|
||||
if (description.colorOp == ProgramDescription::kColorBlend) {
|
||||
generatePorterDuffBlend(shader, "blendColors", description.colorMode);
|
||||
generateBlend(shader, "blendColors", description.colorMode);
|
||||
}
|
||||
if (description.isBitmapNpot) {
|
||||
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
|
||||
@@ -354,13 +372,12 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
return shader;
|
||||
}
|
||||
|
||||
void ProgramCache::generatePorterDuffBlend(String8& shader, const char* name,
|
||||
SkXfermode::Mode mode) {
|
||||
void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
|
||||
shader.append("\nvec4 ");
|
||||
shader.append(name);
|
||||
shader.append("(vec4 src, vec4 dst) {\n");
|
||||
shader.append(" ");
|
||||
shader.append(gPorterDuff[mode]);
|
||||
shader.append(gBlendOps[mode]);
|
||||
shader.append("}\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace uirenderer {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Debug
|
||||
#define DEBUG_PROGRAM_CACHE 0
|
||||
#define DEBUG_PROGRAM_CACHE 1
|
||||
|
||||
// Debug
|
||||
#if DEBUG_PROGRAM_CACHE
|
||||
@@ -57,9 +57,9 @@ namespace uirenderer {
|
||||
#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
|
||||
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
|
||||
|
||||
// Support only the 12 Porter-Duff modes for now
|
||||
#define PROGRAM_MAX_XFERMODE 0xC
|
||||
#define PROGRAM_XFERMODE_SHADER_SHIFT 24
|
||||
// Encode the xfermodes on 6 bits
|
||||
#define PROGRAM_MAX_XFERMODE 0x1f
|
||||
#define PROGRAM_XFERMODE_SHADER_SHIFT 26
|
||||
#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
|
||||
|
||||
#define PROGRAM_BITMAP_WRAPS_SHIFT 9
|
||||
@@ -177,7 +177,7 @@ private:
|
||||
Program* generateProgram(const ProgramDescription& description, programid key);
|
||||
String8 generateVertexShader(const ProgramDescription& description);
|
||||
String8 generateFragmentShader(const ProgramDescription& description);
|
||||
void generatePorterDuffBlend(String8& shader, const char* name, SkXfermode::Mode mode);
|
||||
void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode);
|
||||
void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
|
||||
|
||||
void printLongString(const String8& shader) const;
|
||||
|
||||
@@ -180,5 +180,14 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="AdvancedBlendActivity"
|
||||
android:label="_AdvancedBlend">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ComposeShader;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Shader;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class AdvancedBlendActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(new ShadersView(this));
|
||||
}
|
||||
|
||||
static class ShadersView extends View {
|
||||
private BitmapShader mScaledShader;
|
||||
private int mTexWidth;
|
||||
private int mTexHeight;
|
||||
private Paint mPaint;
|
||||
private float mDrawWidth;
|
||||
private float mDrawHeight;
|
||||
private LinearGradient mHorGradient;
|
||||
private ComposeShader mComposeShader;
|
||||
private ComposeShader mCompose2Shader;
|
||||
private ComposeShader mCompose3Shader;
|
||||
private ComposeShader mCompose4Shader;
|
||||
private ComposeShader mCompose5Shader;
|
||||
private ComposeShader mCompose6Shader;
|
||||
private BitmapShader mScaled2Shader;
|
||||
|
||||
ShadersView(Context c) {
|
||||
super(c);
|
||||
|
||||
Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
|
||||
mTexWidth = texture.getWidth();
|
||||
mTexHeight = texture.getHeight();
|
||||
mDrawWidth = mTexWidth * 2.2f;
|
||||
mDrawHeight = mTexHeight * 1.2f;
|
||||
|
||||
mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR,
|
||||
Shader.TileMode.MIRROR);
|
||||
Matrix m2 = new Matrix();
|
||||
m2.setScale(0.5f, 0.5f);
|
||||
mScaledShader.setLocalMatrix(m2);
|
||||
|
||||
mScaled2Shader = new BitmapShader(texture, Shader.TileMode.MIRROR,
|
||||
Shader.TileMode.MIRROR);
|
||||
Matrix m3 = new Matrix();
|
||||
m3.setScale(0.1f, 0.1f);
|
||||
mScaled2Shader.setLocalMatrix(m3);
|
||||
|
||||
mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
|
||||
Color.BLACK, Color.WHITE, Shader.TileMode.CLAMP);
|
||||
|
||||
mComposeShader = new ComposeShader(mScaledShader, mHorGradient,
|
||||
PorterDuff.Mode.DARKEN);
|
||||
mCompose2Shader = new ComposeShader(mScaledShader, mHorGradient,
|
||||
PorterDuff.Mode.LIGHTEN);
|
||||
mCompose3Shader = new ComposeShader(mScaledShader, mHorGradient,
|
||||
PorterDuff.Mode.MULTIPLY);
|
||||
mCompose4Shader = new ComposeShader(mScaledShader, mHorGradient,
|
||||
PorterDuff.Mode.SCREEN);
|
||||
mCompose5Shader = new ComposeShader(mScaledShader, mHorGradient,
|
||||
PorterDuff.Mode.ADD);
|
||||
mCompose6Shader = new ComposeShader(mHorGradient, mScaledShader,
|
||||
PorterDuff.Mode.OVERLAY);
|
||||
|
||||
mPaint = new Paint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawRGB(255, 255, 255);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(40.0f, 40.0f);
|
||||
|
||||
mPaint.setShader(mComposeShader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mCompose2Shader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mCompose3Shader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(40.0f + mDrawWidth + 40.0f, 40.0f);
|
||||
|
||||
mPaint.setShader(mCompose4Shader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mCompose5Shader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mCompose6Shader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user