Merge "Add support for saveLayer()."

This commit is contained in:
Romain Guy
2010-06-28 18:54:09 -07:00
committed by Android (Google) Code Review
7 changed files with 241 additions and 56 deletions

View File

@@ -171,35 +171,7 @@ 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);
// Restore the clip from the previous snapshot
const Rect& clip = previous->getMappedClip();
glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
// 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);
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);
resetDrawTextureTexCoords(u1, v1, u2, v1);
drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
current->texture, current->alpha);
resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
glDeleteFramebuffers(1, &current->fbo);
glDeleteTextures(1, &current->texture);
composeLayer(current, previous);
}
mSnapshot = previous;
@@ -208,31 +180,81 @@ bool OpenGLRenderer::restoreSnapshot() {
return restoreClip;
}
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);
// Restore the clip from the previous snapshot
const Rect& clip = previous->getMappedClip();
glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
// 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);
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);
resetDrawTextureTexCoords(u1, v1, u2, v1);
drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
current->texture, current->alpha, current->mode, true);
resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
glDeleteFramebuffers(1, &current->fbo);
glDeleteTextures(1, &current->texture);
}
///////////////////////////////////////////////////////////////////////////////
// Layers
///////////////////////////////////////////////////////////////////////////////
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);

View File

@@ -125,6 +125,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

View File

@@ -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

View File

@@ -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" />

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -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;