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

Commit b4494b03 authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

Merge "Implement support for PorterDuff's blending modes."

parents b151fe3b 026c5e16
Loading
Loading
Loading
Loading
+77 −30
Original line number Original line Diff line number Diff line
@@ -40,34 +40,42 @@ namespace uirenderer {
// Globals
// Globals
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


const SimpleVertex gDrawColorVertices[] = {
static const SimpleVertex gDrawColorVertices[] = {
        SV(0.0f, 0.0f),
        SV(0.0f, 0.0f),
        SV(1.0f, 0.0f),
        SV(1.0f, 0.0f),
        SV(0.0f, 1.0f),
        SV(0.0f, 1.0f),
        SV(1.0f, 1.0f)
        SV(1.0f, 1.0f)
};
};
const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
static const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
const GLsizei gDrawColorVertexCount = 4;
static const GLsizei gDrawColorVertexCount = 4;


TextureVertex gDrawTextureVertices[] = {
// This array is never used directly but used as a memcpy source in the
// OpenGLRenderer constructor
static const TextureVertex gDrawTextureVertices[] = {
        FV(0.0f, 0.0f, 0.0f, 1.0f),
        FV(0.0f, 0.0f, 0.0f, 1.0f),
        FV(1.0f, 0.0f, 1.0f, 1.0f),
        FV(1.0f, 0.0f, 1.0f, 1.0f),
        FV(0.0f, 1.0f, 0.0f, 0.0f),
        FV(0.0f, 1.0f, 0.0f, 0.0f),
        FV(1.0f, 1.0f, 1.0f, 0.0f)
        FV(1.0f, 1.0f, 1.0f, 0.0f)
};
};
const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
static const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
const GLsizei gDrawTextureVertexCount = 4;
static const GLsizei gDrawTextureVertexCount = 4;


static inline void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
// In this array, the index of each Blender equals the value of the first
    gDrawTextureVertices[0].texture[0] = u1;
// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
    gDrawTextureVertices[0].texture[1] = v2;
static const Blender gBlends[] = {
    gDrawTextureVertices[1].texture[0] = u2;
        { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO },
    gDrawTextureVertices[1].texture[1] = v2;
        { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO },
    gDrawTextureVertices[2].texture[0] = u1;
        { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE },
    gDrawTextureVertices[2].texture[1] = v1;
        { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
    gDrawTextureVertices[3].texture[0] = u2;
        { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
    gDrawTextureVertices[3].texture[1] = v1;
        { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
}
        { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
        { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
        { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
        { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
        { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
        { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
};


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
// Constructors/destructor
@@ -78,6 +86,8 @@ OpenGLRenderer::OpenGLRenderer() {


    mDrawColorShader = new DrawColorProgram;
    mDrawColorShader = new DrawColorProgram;
    mDrawTextureShader = new DrawTextureProgram;
    mDrawTextureShader = new DrawTextureProgram;

    memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices));
}
}


OpenGLRenderer::~OpenGLRenderer() {
OpenGLRenderer::~OpenGLRenderer() {
@@ -336,22 +346,43 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
    // TODO: Set the transfer mode
    const Rect& clip = mSnapshot->clipRect;
    const Rect& clip = mSnapshot->clipRect;
    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color);
    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode);
}
}


void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
    // TODO Support more than  just color
    SkXfermode::Mode mode;
    // TODO: Set the transfer mode

    drawColorRect(left, top, right, bottom, p->getColor());
    const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
    if (!isMode) {
        // Assume SRC_OVER
        mode = SkXfermode::kSrcOver_Mode;
    }

    // Skia draws using the color's alpha channel if < 255
    // Otherwise, it uses the paint's alpha
    int color = p->getColor();
    if (((color >> 24) & 0xFF) == 255) {
        color |= p->getAlpha() << 24;
    }

    drawColorRect(left, top, right, bottom, color, mode);
}
}


void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) {
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
    GLfloat a = ((color >> 24) & 0xFF) / 255.0f;
        int color, SkXfermode::Mode mode) {
    GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
    const int alpha = (color >> 24) & 0xFF;
    GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
    const bool blend = alpha < 255 || mode != SkXfermode::kSrcOver_Mode;
    GLfloat b = ((color      ) & 0xFF) / 255.0f;

    const GLfloat a = alpha                  / 255.0f;
    const GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
    const GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
    const GLfloat b = ((color      ) & 0xFF) / 255.0f;

    if (blend) {
        glEnable(GL_BLEND);
        glBlendFunc(gBlends[mode].src, gBlends[mode].dst);
    }


    mModelView.loadTranslate(left, top, 0.0f);
    mModelView.loadTranslate(left, top, 0.0f);
    mModelView.scale(right - left, bottom - top, 1.0f);
    mModelView.scale(right - left, bottom - top, 1.0f);
@@ -368,6 +399,10 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
    glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);


    glDisableVertexAttribArray(mDrawColorShader->position);
    glDisableVertexAttribArray(mDrawColorShader->position);

    if (blend) {
        glDisable(GL_BLEND);
    }
}
}


void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
@@ -379,6 +414,7 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b


    // TODO Correctly set the blend function, based on texture format and xfermode
    // TODO Correctly set the blend function, based on texture format and xfermode
    glEnable(GL_BLEND);
    glEnable(GL_BLEND);
    // For not pre-multiplied sources
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    glBindTexture(GL_TEXTURE_2D, texture);
    glBindTexture(GL_TEXTURE_2D, texture);
@@ -386,8 +422,8 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
    glActiveTexture(GL_TEXTURE0);
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(mDrawTextureShader->sampler, 0);
    glUniform1i(mDrawTextureShader->sampler, 0);


    const GLvoid* p = &gDrawTextureVertices[0].position[0];
    const GLvoid* p = &mDrawTextureVertices[0].position[0];
    const GLvoid* t = &gDrawTextureVertices[0].texture[0];
    const GLvoid* t = &mDrawTextureVertices[0].texture[0];


    glEnableVertexAttribArray(mDrawTextureShader->position);
    glEnableVertexAttribArray(mDrawTextureShader->position);
    glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
    glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
@@ -408,5 +444,16 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
    glDisable(GL_BLEND);
    glDisable(GL_BLEND);
}
}


void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
    mDrawTextureVertices[0].texture[0] = u1;
    mDrawTextureVertices[0].texture[1] = v2;
    mDrawTextureVertices[1].texture[0] = u2;
    mDrawTextureVertices[1].texture[1] = v2;
    mDrawTextureVertices[2].texture[0] = u1;
    mDrawTextureVertices[2].texture[1] = v1;
    mDrawTextureVertices[3].texture[0] = u2;
    mDrawTextureVertices[3].texture[1] = v1;
}

}; // namespace uirenderer
}; // namespace uirenderer
}; // namespace android
}; // namespace android
+28 −1
Original line number Original line Diff line number Diff line
@@ -53,6 +53,15 @@ struct TextureVertex {
    float texture[2];
    float texture[2];
}; // struct TextureVertex
}; // struct TextureVertex


/**
 * Structure mapping Skia xfermodes to OpenGL blending factors.
 */
struct Blender {
    SkXfermode::Mode mode;
    GLenum src;
    GLenum dst;
}; // struct Blender

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Renderer
// Renderer
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -125,8 +134,10 @@ private:
     * @param right The right coordinate of the rectangle
     * @param right The right coordinate of the rectangle
     * @param bottom The bottom coordinate of the rectangle
     * @param bottom The bottom coordinate of the rectangle
     * @param color The rectangle's ARGB color, defined as a packed 32 bits word
     * @param color The rectangle's ARGB color, defined as a packed 32 bits word
     * @param mode The Skia xfermode to use
     */
     */
    void drawColorRect(float left, float top, float right, float bottom, int color);
    void drawColorRect(float left, float top, float right, float bottom,
    		int color, SkXfermode::Mode mode);


    /**
    /**
     * Draws a textured rectangle with the specified texture. The specified coordinates
     * Draws a textured rectangle with the specified texture. The specified coordinates
@@ -142,6 +153,19 @@ private:
    void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
    void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
            float alpha);
            float alpha);


    /**
     * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
     * back to default is achieved by calling:
     *
     * resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
     *
     * @param u1 The left coordinate of the texture
     * @param v1 The bottom coordinate of the texture
     * @param u2 The right coordinate of the texture
     * @param v2 The top coordinate of the texture
     */
    void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2);

    // Dimensions of the drawing surface
    // Dimensions of the drawing surface
    int mWidth, mHeight;
    int mWidth, mHeight;


@@ -161,6 +185,9 @@ private:
    // Shaders
    // Shaders
    sp<DrawColorProgram> mDrawColorShader;
    sp<DrawColorProgram> mDrawColorShader;
    sp<DrawTextureProgram> mDrawTextureShader;
    sp<DrawTextureProgram> mDrawTextureShader;

    // Used to draw textured quads
    TextureVertex mDrawTextureVertices[4];
}; // class OpenGLRenderer
}; // class OpenGLRenderer


}; // namespace uirenderer
}; // namespace uirenderer
+13 −1
Original line number Original line Diff line number Diff line
@@ -21,7 +21,19 @@
        android:label="HwUi"
        android:label="HwUi"
        android:hardwareAccelerated="true">
        android:hardwareAccelerated="true">


        <activity android:name="HwUiActivity">
        <activity
                android:name="HwUiActivity"
                android:label="_Layers">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
                android:name="XfermodeActivity"
                android:label="_Xfermodes"
                android:theme="@android:style/Theme.Translucent">
            <intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.LAUNCHER" />
+142 −0
Original line number Original line 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.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.view.View;

import static android.graphics.PorterDuff.Mode;

@SuppressWarnings({"UnusedDeclaration"})
public class XfermodeActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(new XfermodesView(this));
    }
    
    @SuppressWarnings({"UnusedDeclaration"})
    static int dipToPx(Context c, int dip) {
        return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f);
    }

    static class XfermodesView extends View {
        private final Paint mBluePaint;
        private final Paint mRedPaint;

        XfermodesView(Context c) {
            super(c);

            mBluePaint = new Paint();
            mBluePaint.setColor(0xff0000ff);
            
            mRedPaint = new Paint();
            mRedPaint.setColor(0x7fff0000);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //canvas.drawRGB(255, 255, 255);

            canvas.translate(100.0f, 100.0f);
            
            // SRC modes
            canvas.save();

            drawRects(canvas, Mode.SRC_OVER);
            canvas.translate(0.0f, 100.0f);

            drawRects(canvas, Mode.SRC_IN);
            canvas.translate(0.0f, 100.0f);            

            drawRects(canvas, Mode.SRC_OUT);
            canvas.translate(0.0f, 100.0f);

            drawRects(canvas, Mode.SRC_ATOP);
            canvas.translate(0.0f, 100.0f);
            
            drawRects(canvas, Mode.SRC);

            canvas.restore();
            
            canvas.translate(100.0f, 0.0f);
            
            // DST modes
            canvas.save();

            drawRects(canvas, Mode.DST_OVER);
            canvas.translate(0.0f, 100.0f);

            drawRects(canvas, Mode.DST_IN);
            canvas.translate(0.0f, 100.0f);            

            drawRects(canvas, Mode.DST_OUT);
            canvas.translate(0.0f, 100.0f);

            drawRects(canvas, Mode.DST_ATOP);
            canvas.translate(0.0f, 100.0f);
            
            drawRects(canvas, Mode.DST);

            canvas.restore();
            
            canvas.translate(100.0f, 0.0f);
            
            // Other modes
            canvas.save();

            drawRects(canvas, Mode.CLEAR);
            canvas.translate(0.0f, 100.0f);

            drawRects(canvas, Mode.XOR);
            
            canvas.translate(0.0f, 100.0f);
            
            mBluePaint.setAlpha(127);
            canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint);
            
            canvas.translate(0.0f, 100.0f);
            
            mBluePaint.setAlpha(10);
            mBluePaint.setColor(0x7f0000ff);
            canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint);
            
            mBluePaint.setColor(0xff0000ff);
            mBluePaint.setAlpha(255);

            canvas.restore();
        }

        private void drawRects(Canvas canvas, PorterDuff.Mode mode) {
            canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint);

            canvas.save();
            canvas.translate(25.0f, 25.0f);
            mRedPaint.setXfermode(new PorterDuffXfermode(mode));
            canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mRedPaint);
            canvas.restore();
        }
    }
}