Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48daa54d authored by Romain Guy's avatar Romain Guy
Browse files

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
parent a674ab74
Loading
Loading
Loading
Loading
+3 −7
Original line number Diff line number Diff line
@@ -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);
+24 −7
Original line number Diff line number Diff line
@@ -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");
}

+5 −5
Original line number Diff line number Diff line
@@ -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;
+9 −0
Original line number Diff line number Diff line
@@ -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>
+138 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }
}