diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e764778ab7251..305c8c5a60e80 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -40,34 +40,42 @@ namespace uirenderer { // Globals /////////////////////////////////////////////////////////////////////////////// -const SimpleVertex gDrawColorVertices[] = { +static const SimpleVertex gDrawColorVertices[] = { SV(0.0f, 0.0f), SV(1.0f, 0.0f), SV(0.0f, 1.0f), SV(1.0f, 1.0f) }; -const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex); -const GLsizei gDrawColorVertexCount = 4; +static const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex); +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(1.0f, 0.0f, 1.0f, 1.0f), FV(0.0f, 1.0f, 0.0f, 0.0f), FV(1.0f, 1.0f, 1.0f, 0.0f) }; -const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex); -const GLsizei gDrawTextureVertexCount = 4; +static const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex); +static const GLsizei gDrawTextureVertexCount = 4; -static inline void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { - gDrawTextureVertices[0].texture[0] = u1; - gDrawTextureVertices[0].texture[1] = v2; - gDrawTextureVertices[1].texture[0] = u2; - gDrawTextureVertices[1].texture[1] = v2; - gDrawTextureVertices[2].texture[0] = u1; - gDrawTextureVertices[2].texture[1] = v1; - gDrawTextureVertices[3].texture[0] = u2; - gDrawTextureVertices[3].texture[1] = v1; -} +// In this array, the index of each Blender equals the value of the first +// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] +static const Blender gBlends[] = { + { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, + { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, + { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, + { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, + { 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 @@ -78,6 +86,8 @@ OpenGLRenderer::OpenGLRenderer() { mDrawColorShader = new DrawColorProgram; mDrawTextureShader = new DrawTextureProgram; + + memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices)); } 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) { - // TODO: Set the transfer mode 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) { - // TODO Support more than just color - // TODO: Set the transfer mode - drawColorRect(left, top, right, bottom, p->getColor()); + SkXfermode::Mode mode; + + 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) { - GLfloat a = ((color >> 24) & 0xFF) / 255.0f; - GLfloat r = ((color >> 16) & 0xFF) / 255.0f; - GLfloat g = ((color >> 8) & 0xFF) / 255.0f; - GLfloat b = ((color ) & 0xFF) / 255.0f; +void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, + int color, SkXfermode::Mode mode) { + const int alpha = (color >> 24) & 0xFF; + const bool blend = alpha < 255 || mode != SkXfermode::kSrcOver_Mode; + + 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.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); glDisableVertexAttribArray(mDrawColorShader->position); + + if (blend) { + glDisable(GL_BLEND); + } } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, @@ -379,15 +414,16 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b // TODO Correctly set the blend function, based on texture format and xfermode glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + // For not pre-multiplied sources + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, texture); glActiveTexture(GL_TEXTURE0); glUniform1i(mDrawTextureShader->sampler, 0); - const GLvoid* p = &gDrawTextureVertices[0].position[0]; - const GLvoid* t = &gDrawTextureVertices[0].texture[0]; + const GLvoid* p = &mDrawTextureVertices[0].position[0]; + const GLvoid* t = &mDrawTextureVertices[0].texture[0]; glEnableVertexAttribArray(mDrawTextureShader->position); 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); } +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 android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 1e031b8748171..85fa541faec2f 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -53,6 +53,15 @@ struct TextureVertex { float texture[2]; }; // struct TextureVertex +/** + * Structure mapping Skia xfermodes to OpenGL blending factors. + */ +struct Blender { + SkXfermode::Mode mode; + GLenum src; + GLenum dst; +}; // struct Blender + /////////////////////////////////////////////////////////////////////////////// // Renderer /////////////////////////////////////////////////////////////////////////////// @@ -125,8 +134,10 @@ private: * @param right The right 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 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 @@ -142,6 +153,19 @@ private: void drawTextureRect(float left, float top, float right, float bottom, GLuint texture, 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 int mWidth, mHeight; @@ -161,6 +185,9 @@ private: // Shaders sp mDrawColorShader; sp mDrawTextureShader; + + // Used to draw textured quads + TextureVertex mDrawTextureVertices[4]; }; // class OpenGLRenderer }; // namespace uirenderer diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 2ff0b2cc90f82..7dfa6725363be 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -21,12 +21,24 @@ android:label="HwUi" android:hardwareAccelerated="true"> - + + + + + + + + diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java new file mode 100644 index 0000000000000..440d62201f87e --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java @@ -0,0 +1,142 @@ +/* + * 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(); + } + } +}