diff options
| author | Romain Guy <romainguy@google.com> | 2010-06-28 17:42:46 -0700 |
|---|---|---|
| committer | Romain Guy <romainguy@google.com> | 2010-06-28 18:52:24 -0700 |
| commit | d55a86120dd1e8ebcc6906c9ffd463f7460348da (patch) | |
| tree | 11ee1cc35750ba27df4fdb80540c3a5752cdd500 | |
| parent | 8f704d89dc38c6e25b23721f6a784956521f283a (diff) | |
| download | frameworks_base-d55a86120dd1e8ebcc6906c9ffd463f7460348da.zip frameworks_base-d55a86120dd1e8ebcc6906c9ffd463f7460348da.tar.gz frameworks_base-d55a86120dd1e8ebcc6906c9ffd463f7460348da.tar.bz2 | |
Add support for saveLayer().
saveLayer() is affected by the paint's alpha and xfermode.
Change-Id: I28693a9337052643adccdb4889a8f228d4e17903
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 121 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 32 | ||||
| -rw-r--r-- | libs/hwui/Snapshot.h | 7 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 14 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/src/com/google/android/test/hwui/AlphaLayersActivity.java (renamed from tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java) | 2 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java | 110 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java | 5 |
7 files changed, 238 insertions, 53 deletions
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 305c8c5..aa992c4 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -171,41 +171,45 @@ bool OpenGLRenderer::restoreSnapshot() { sp<Snapshot> previous = mSnapshot->previous; if (restoreLayer) { - // Unbind current FBO and restore previous one - // Most of the time, previous->fbo will be 0 to bind the default buffer - glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); + composeLayer(current, previous); + } - // Restore the clip from the previous snapshot - const Rect& clip = previous->getMappedClip(); - glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); + mSnapshot = previous; + mSaveCount--; - // Compute the correct texture coordinates for the FBO texture - // The texture is currently as big as the window but drawn with - // a quad of the appropriate size - const Rect& layer = current->layer; - Rect texCoords(current->layer); - mSnapshot->transform.mapRect(texCoords); + return restoreClip; +} - const float u1 = texCoords.left / float(mWidth); - const float v1 = (mHeight - texCoords.top) / float(mHeight); - const float u2 = texCoords.right / float(mWidth); - const float v2 = (mHeight - texCoords.bottom) / float(mHeight); +void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { + // Unbind current FBO and restore previous one + // Most of the time, previous->fbo will be 0 to bind the default buffer + glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); - resetDrawTextureTexCoords(u1, v1, u2, v1); + // Restore the clip from the previous snapshot + const Rect& clip = previous->getMappedClip(); + glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); - drawTextureRect(layer.left, layer.top, layer.right, layer.bottom, - current->texture, current->alpha); + // Compute the correct texture coordinates for the FBO texture + // The texture is currently as big as the window but drawn with + // a quad of the appropriate size + const Rect& layer = current->layer; + Rect texCoords(current->layer); + mSnapshot->transform.mapRect(texCoords); - resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); + const float u1 = texCoords.left / float(mWidth); + const float v1 = (mHeight - texCoords.top) / float(mHeight); + const float u2 = texCoords.right / float(mWidth); + const float v2 = (mHeight - texCoords.bottom) / float(mHeight); - glDeleteFramebuffers(1, ¤t->fbo); - glDeleteTextures(1, ¤t->texture); - } + resetDrawTextureTexCoords(u1, v1, u2, v1); - mSnapshot = previous; - mSaveCount--; + drawTextureRect(layer.left, layer.top, layer.right, layer.bottom, + current->texture, current->alpha, current->mode, true); - return restoreClip; + resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); + + glDeleteFramebuffers(1, ¤t->fbo); + glDeleteTextures(1, ¤t->texture); } /////////////////////////////////////////////////////////////////////////////// @@ -214,25 +218,43 @@ bool OpenGLRenderer::restoreSnapshot() { int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, const SkPaint* p, int flags) { - // TODO Implement - return saveSnapshot(); + int count = saveSnapshot(); + + int alpha = 255; + SkXfermode::Mode mode; + + if (p) { + alpha = p->getAlpha(); + const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); + if (!isMode) { + // Assume SRC_OVER + mode = SkXfermode::kSrcOver_Mode; + } + } else { + mode = SkXfermode::kSrcOver_Mode; + } + + createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags); + + return count; } int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int flags) { int count = saveSnapshot(); + createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags); + return count; +} - mSnapshot->flags |= Snapshot::kFlagIsLayer; - mSnapshot->alpha = alpha / 255.0f; - mSnapshot->layer.set(left, top, right, bottom); - +bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, + float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { // Generate the FBO and attach the texture - glGenFramebuffers(1, &mSnapshot->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo); + glGenFramebuffers(1, &snapshot->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); // Generate the texture in which the FBO will draw - glGenTextures(1, &mSnapshot->texture); - glBindTexture(GL_TEXTURE_2D, mSnapshot->texture); + glGenTextures(1, &snapshot->texture); + glBindTexture(GL_TEXTURE_2D, snapshot->texture); // The FBO will not be scaled, so we can use lower quality filtering glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -255,17 +277,24 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot // Bind texture to FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - mSnapshot->texture, 0); + snapshot->texture, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { LOGD("Framebuffer incomplete %d", status); - glDeleteFramebuffers(1, &mSnapshot->fbo); - glDeleteTextures(1, &mSnapshot->texture); + glDeleteFramebuffers(1, &snapshot->fbo); + glDeleteTextures(1, &snapshot->texture); + + return false; } - return count; + snapshot->flags |= Snapshot::kFlagIsLayer; + snapshot->mode = mode; + snapshot->alpha = alpha / 255.0f; + snapshot->layer.set(left, top, right, bottom); + + return true; } /////////////////////////////////////////////////////////////////////////////// @@ -406,16 +435,20 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, - GLuint texture, float alpha) { + GLuint texture, float alpha, SkXfermode::Mode mode, bool isPremultiplied) { mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); - // TODO Correctly set the blend function, based on texture format and xfermode + GLenum sourceMode = gBlends[mode].src; + if (!isPremultiplied && sourceMode == GL_ONE) { + sourceMode = GL_SRC_ALPHA; + } + + // TODO: Try to disable blending when the texture is opaque and alpha == 1.0f glEnable(GL_BLEND); - // For not pre-multiplied sources - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(sourceMode, gBlends[mode].dst); glBindTexture(GL_TEXTURE_2D, texture); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 85fa541..1af73c1 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -126,6 +126,34 @@ private: void setScissorFromClip(); /** + * Compose the layer defined in the current snapshot with the layer + * defined by the previous snapshot. + * + * The current snapshot *must* be a layer (flag kFlagIsLayer set.) + * + * @param curent The current snapshot containing the layer to compose + * @param previous The previous snapshot to compose the current layer with + */ + void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); + + /** + * Creates a new layer stored in the specified snapshot. + * + * @param snapshot The snapshot associated with the new layer + * @param left The left coordinate of the layer + * @param top The top coordinate of the layer + * @param right The right coordinate of the layer + * @param bottom The bottom coordinate of the layer + * @param alpha The translucency of the layer + * @param mode The blending mode of the layer + * @param flags The layer save flags + * + * @return True if the layer was successfully created, false otherwise + */ + bool createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, + int alpha, SkXfermode::Mode mode, int flags); + + /** * Draws a colored rectangle with the specified color. The specified coordinates * are transformed by the current snapshot's transform matrix. * @@ -149,9 +177,11 @@ private: * @param bottom The bottom coordinate of the rectangle * @param texture The texture name to map onto the rectangle * @param alpha An additional translucency parameter, between 0.0f and 1.0f + * @param mode The blending mode + * @param isPremultiplied Indicates whether the texture has premultiplied alpha */ void drawTextureRect(float left, float top, float right, float bottom, GLuint texture, - float alpha); + float alpha, SkXfermode::Mode mode, bool isPremultiplied = false); /** * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 9a9be2d..ca91b34 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -20,6 +20,8 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include <SkXfermode.h> + #include <utils/RefBase.h> #include "Matrix.h" @@ -133,6 +135,11 @@ public: * Only set when the flag kFlagIsLayer is set. */ float alpha; + /** + * Blending mode of the layer. + * Only set when the flag kFlagIsLayer is set. + */ + SkXfermode::Mode mode; private: // Clipping rectangle mapped with the transform diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 7dfa672..30ac8d6 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -22,8 +22,18 @@ android:hardwareAccelerated="true"> <activity - android:name="HwUiActivity" - android:label="_Layers"> + android:name="AlphaLayersActivity" + 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="LayersActivity" + android:label="_Layers" + android:theme="@android:style/Theme.Translucent"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/AlphaLayersActivity.java index 85e3997..0217a05 100644 --- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/AlphaLayersActivity.java @@ -29,7 +29,7 @@ import android.view.animation.Animation; import android.widget.FrameLayout; @SuppressWarnings({"UnusedDeclaration"}) -public class HwUiActivity extends Activity { +public class AlphaLayersActivity extends Activity { private static final String LOG_TAG = "HwUi"; @Override diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java new file mode 100644 index 0000000..437cd1c --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java @@ -0,0 +1,110 @@ +/* + * 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; + +@SuppressWarnings({"UnusedDeclaration"}) +public class LayersActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(new LayersView(this)); + } + + static class LayersView extends View { + private Paint mLayerPaint; + private final Paint mRectPaint; + + LayersView(Context c) { + super(c); + + mLayerPaint = new Paint(); + mRectPaint = new Paint(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.translate(140.0f, 100.0f); + + //canvas.drawRGB(255, 255, 255); + + int count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xffff0000); + canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint); + + canvas.restoreToCount(count); + + canvas.translate(0.0f, 125.0f); + + count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xff00ff00); + mRectPaint.setAlpha(50); + canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint); + + canvas.restoreToCount(count); + + canvas.translate(25.0f, 125.0f); + + mRectPaint.setColor(0xff0000ff); + mRectPaint.setAlpha(255); + canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint); + + mLayerPaint.setAlpha(127); + mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); + count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xffff0000); + canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint); + + canvas.restoreToCount(count); + + canvas.translate(0.0f, 125.0f); + + mRectPaint.setColor(0xff0000ff); + mRectPaint.setAlpha(255); + canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint); + + mLayerPaint.setColor(0xffff0000); + mLayerPaint.setAlpha(127); + mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); + count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xffff0000); + canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint); + + canvas.restoreToCount(count); + + mLayerPaint = new Paint(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java index 440d622..8c81f02 100644 --- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java @@ -35,11 +35,6 @@ public class XfermodeActivity extends Activity { 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; |
