Correctly support pre-multiplied alpha, optimizations, more stuff.
Add support for the following drawing functions: - drawBitmap(int[]...) - drawPaint() Optimizes shader state changes by enabling/disabling attribute arrays only when needed. Adds quick rejects when drawing trivial shapes to avoid unnecessary OpenGL operations. Change-Id: Ic2c6c2ed1523d08a63a8c95601a1ec40b6c7fbc9
This commit is contained in:
@@ -45,6 +45,10 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
private final float[] mPoint = new float[2];
|
||||
private final float[] mLine = new float[4];
|
||||
|
||||
private final Rect mClipBounds = new Rect();
|
||||
|
||||
private DrawFilter mFilter;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
@@ -164,6 +168,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public boolean clipRect(Rect rect, Region.Op op) {
|
||||
// TODO: Implement
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -174,6 +179,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public boolean clipRect(RectF rect, Region.Op op) {
|
||||
// TODO: Implement
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -336,12 +342,14 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void setDrawFilter(DrawFilter filter) {
|
||||
throw new UnsupportedOperationException();
|
||||
// Don't crash, but ignore the draw filter
|
||||
// TODO: Implement PaintDrawFilter
|
||||
mFilter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawFilter getDrawFilter() {
|
||||
throw new UnsupportedOperationException();
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -408,7 +416,11 @@ class GLES20Canvas extends Canvas {
|
||||
@Override
|
||||
public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
|
||||
int width, int height, boolean hasAlpha, Paint paint) {
|
||||
// TODO: Implement
|
||||
final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
|
||||
final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
|
||||
b.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -420,7 +432,7 @@ class GLES20Canvas extends Canvas {
|
||||
@Override
|
||||
public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
|
||||
int vertOffset, int[] colors, int colorOffset, Paint paint) {
|
||||
throw new UnsupportedOperationException();
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -466,7 +478,9 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawPaint(Paint paint) {
|
||||
// TODO: Implement
|
||||
final Rect r = mClipBounds;
|
||||
nGetClipBounds(mRenderer, r);
|
||||
drawRect(r.left, r.top, r.right, r.bottom, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -591,6 +605,6 @@ class GLES20Canvas extends Canvas {
|
||||
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
|
||||
float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
|
||||
int indexOffset, int indexCount, Paint paint) {
|
||||
throw new UnsupportedOperationException();
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,25 @@
|
||||
|
||||
package android.graphics;
|
||||
|
||||
/**
|
||||
* Shader used to draw a bitmap as a texture. The bitmap can be repeated or
|
||||
* mirrored by setting the tiling mode.
|
||||
*/
|
||||
public class BitmapShader extends Shader {
|
||||
|
||||
// we hold on just for the GC, since our native counterpart is using it
|
||||
private Bitmap mBitmap;
|
||||
/**
|
||||
* We hold on just for the GC, since our native counterpart is using it.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Bitmap mBitmap;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int mTileX;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int mTileY;
|
||||
|
||||
/**
|
||||
* Call this to create a new shader that will draw with a bitmap.
|
||||
@@ -30,12 +45,11 @@ public class BitmapShader extends Shader {
|
||||
*/
|
||||
public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
|
||||
mBitmap = bitmap;
|
||||
native_instance = nativeCreate(bitmap.ni(),
|
||||
tileX.nativeInt, tileY.nativeInt);
|
||||
mTileX = tileX.nativeInt;
|
||||
mTileY = tileY.nativeInt;
|
||||
native_instance = nativeCreate(bitmap.ni(), mTileX, mTileY);
|
||||
}
|
||||
|
||||
private static native int nativeCreate(int native_bitmap,
|
||||
int shaderTileModeX,
|
||||
int shaderTileModeY);
|
||||
private static native int nativeCreate(int native_bitmap, int shaderTileModeX,
|
||||
int shaderTileModeY);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ OpenGLRenderer::~OpenGLRenderer() {
|
||||
|
||||
mTextureCache.clear();
|
||||
mLayerCache.clear();
|
||||
mPatchCache.clear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -242,7 +243,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
|
||||
const Rect& rect = layer->layer;
|
||||
|
||||
drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
|
||||
layer->texture, layer->alpha, layer->mode, layer->blend);
|
||||
layer->texture, layer->alpha, layer->mode, layer->blend, true);
|
||||
|
||||
LayerSize size(rect.getWidth(), rect.getHeight());
|
||||
// Failing to add the layer to the cache should happen only if the
|
||||
@@ -418,8 +419,15 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
|
||||
const float right = left + bitmap->width();
|
||||
const float bottom = top + bitmap->height();
|
||||
|
||||
if (quickReject(left, top, right, bottom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Texture* texture = mTextureCache.get(bitmap);
|
||||
drawTextureRect(left, top, left + texture->width, top + texture->height, texture, paint);
|
||||
drawTextureRect(left, top, right, bottom, texture, paint);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
|
||||
@@ -427,6 +435,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const
|
||||
const mat4 transform(*matrix);
|
||||
transform.mapRect(r);
|
||||
|
||||
if (quickReject(r.left, r.top, r.right, r.bottom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Texture* texture = mTextureCache.get(bitmap);
|
||||
drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
|
||||
}
|
||||
@@ -435,6 +447,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
|
||||
float srcLeft, float srcTop, float srcRight, float srcBottom,
|
||||
float dstLeft, float dstTop, float dstRight, float dstBottom,
|
||||
const SkPaint* paint) {
|
||||
if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Texture* texture = mTextureCache.get(bitmap);
|
||||
|
||||
const float width = texture->width;
|
||||
@@ -454,6 +470,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
|
||||
|
||||
void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
|
||||
float left, float top, float right, float bottom, const SkPaint* paint) {
|
||||
if (quickReject(left, top, right, bottom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Texture* texture = mTextureCache.get(bitmap);
|
||||
|
||||
int alpha;
|
||||
@@ -477,6 +497,10 @@ void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
|
||||
if (quickReject(left, top, right, bottom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkXfermode::Mode mode;
|
||||
|
||||
const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
|
||||
@@ -495,6 +519,10 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
|
||||
drawColorRect(left, top, right, bottom, color, mode);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Drawing implementation
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
|
||||
int color, SkXfermode::Mode mode) {
|
||||
const int alpha = (color >> 24) & 0xFF;
|
||||
@@ -503,24 +531,24 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
|
||||
const GLfloat g = ((color >> 8) & 0xFF) / 255.0f;
|
||||
const GLfloat b = ((color ) & 0xFF) / 255.0f;
|
||||
|
||||
// Pre-multiplication happens when setting the shader color
|
||||
chooseBlending(alpha < 255, mode, true);
|
||||
|
||||
mModelView.loadTranslate(left, top, 0.0f);
|
||||
mModelView.scale(right - left, bottom - top, 1.0f);
|
||||
|
||||
useShader(mDrawColorShader);
|
||||
const bool inUse = useShader(mDrawColorShader);
|
||||
mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform);
|
||||
|
||||
const GLvoid* p = &gDrawColorVertices[0].position[0];
|
||||
|
||||
glEnableVertexAttribArray(mDrawColorShader->position);
|
||||
glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawColorVertexStride, p);
|
||||
glUniform4f(mDrawColorShader->color, r, g, b, a);
|
||||
if (!inUse) {
|
||||
const GLvoid* p = &gDrawColorVertices[0].position[0];
|
||||
glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawColorVertexStride, p);
|
||||
}
|
||||
// Render using pre-multiplied alpha
|
||||
glUniform4f(mDrawColorShader->color, r * a, g * a, b * a, a);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
|
||||
|
||||
glDisableVertexAttribArray(mDrawColorShader->position);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
|
||||
@@ -529,8 +557,8 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
|
||||
SkXfermode::Mode mode;
|
||||
getAlphaAndMode(paint, &alpha, &mode);
|
||||
|
||||
drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
|
||||
isPremultiplied, &mDrawTextureVertices[0].position[0],
|
||||
drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
|
||||
texture->blend, texture->blend, &mDrawTextureVertices[0].position[0],
|
||||
&mDrawTextureVertices[0].texture[0], NULL);
|
||||
}
|
||||
|
||||
@@ -555,27 +583,24 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
|
||||
|
||||
// TODO handle tiling and filtering here
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(mDrawTextureShader->sampler, 0);
|
||||
glUniform4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha);
|
||||
if (isPremultiplied) {
|
||||
glUniform4f(mDrawTextureShader->color, alpha, alpha, alpha, alpha);
|
||||
} else {
|
||||
glUniform4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha);
|
||||
}
|
||||
|
||||
glEnableVertexAttribArray(mDrawTextureShader->position);
|
||||
glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawTextureVertexStride, vertices);
|
||||
|
||||
glEnableVertexAttribArray(mDrawTextureShader->texCoords);
|
||||
glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawTextureVertexStride, texCoords);
|
||||
|
||||
if (!indices) {
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
|
||||
} else {
|
||||
// TODO: Use triangle strip instead
|
||||
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(mDrawTextureShader->position);
|
||||
glDisableVertexAttribArray(mDrawTextureShader->texCoords);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
@@ -605,12 +630,14 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr
|
||||
mBlend = blend;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::useShader(const sp<Program>& shader) {
|
||||
bool OpenGLRenderer::useShader(const sp<Program>& shader) {
|
||||
if (!shader->isInUse()) {
|
||||
mCurrentShader->remove();
|
||||
shader->use();
|
||||
mCurrentShader = shader;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
|
||||
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
* @param isPremultiplied Indicates whether the texture has premultiplied alpha
|
||||
*/
|
||||
void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
|
||||
float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = true);
|
||||
float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = false);
|
||||
|
||||
/**
|
||||
* Draws a textured rectangle with the specified texture. The specified coordinates
|
||||
@@ -194,7 +194,7 @@ private:
|
||||
* @param isPremultiplied Indicates whether the texture has premultiplied alpha
|
||||
*/
|
||||
void drawTextureRect(float left, float top, float right, float bottom, const Texture* texture,
|
||||
const SkPaint* paint, bool isPremultiplied = true);
|
||||
const SkPaint* paint, bool isPremultiplied = false);
|
||||
|
||||
/**
|
||||
* Draws a textured mesh with the specified texture. If the indices are omitted, the
|
||||
@@ -252,8 +252,10 @@ private:
|
||||
* in use, it will not be bound again. If it is not in use, the current shader is
|
||||
* marked unused and the specified shader becomes used and becomes the new
|
||||
* current shader.
|
||||
*
|
||||
* @return true If the specified shader was already in use, false otherwise.
|
||||
*/
|
||||
inline void useShader(const sp<Program>& shader);
|
||||
inline bool useShader(const sp<Program>& shader);
|
||||
|
||||
// Dimensions of the drawing surface
|
||||
int mWidth, mHeight;
|
||||
|
||||
@@ -146,6 +146,16 @@ void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMa
|
||||
glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
|
||||
}
|
||||
|
||||
void DrawColorProgram::use() {
|
||||
Program::use();
|
||||
glEnableVertexAttribArray(position);
|
||||
}
|
||||
|
||||
void DrawColorProgram::remove() {
|
||||
Program::remove();
|
||||
glDisableVertexAttribArray(position);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Draw texture
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -156,5 +166,17 @@ DrawTextureProgram::DrawTextureProgram():
|
||||
sampler = addUniform("sampler");
|
||||
}
|
||||
|
||||
void DrawTextureProgram::use() {
|
||||
DrawColorProgram::use();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(sampler, 0);
|
||||
glEnableVertexAttribArray(texCoords);
|
||||
}
|
||||
|
||||
void DrawTextureProgram::remove() {
|
||||
DrawColorProgram::remove();
|
||||
glDisableVertexAttribArray(texCoords);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -39,18 +39,18 @@ public:
|
||||
* shaders sources.
|
||||
*/
|
||||
Program(const char* vertex, const char* fragment);
|
||||
~Program();
|
||||
virtual ~Program();
|
||||
|
||||
/**
|
||||
* Binds this program to the GL context.
|
||||
*/
|
||||
void use();
|
||||
virtual void use();
|
||||
|
||||
/**
|
||||
* Marks this program as unused. This will not unbind
|
||||
* the program from the GL context.
|
||||
*/
|
||||
void remove();
|
||||
virtual void remove();
|
||||
|
||||
/**
|
||||
* Indicates whether this program is currently in use with
|
||||
@@ -128,6 +128,17 @@ public:
|
||||
void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
|
||||
const mat4& transformMatrix);
|
||||
|
||||
/**
|
||||
* Binds this program to the GL context.
|
||||
*/
|
||||
virtual void use();
|
||||
|
||||
/**
|
||||
* Marks this program as unused. This will not unbind
|
||||
* the program from the GL context.
|
||||
*/
|
||||
virtual void remove();
|
||||
|
||||
/**
|
||||
* Name of the position attribute.
|
||||
*/
|
||||
@@ -156,6 +167,17 @@ class DrawTextureProgram: public DrawColorProgram {
|
||||
public:
|
||||
DrawTextureProgram();
|
||||
|
||||
/**
|
||||
* Binds this program to the GL context.
|
||||
*/
|
||||
virtual void use();
|
||||
|
||||
/**
|
||||
* Marks this program as unused. This will not unbind
|
||||
* the program from the GL context.
|
||||
*/
|
||||
virtual void remove();
|
||||
|
||||
/**
|
||||
* Name of the texture sampler uniform.
|
||||
*/
|
||||
|
||||
@@ -78,6 +78,15 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="QuickRejectActivity"
|
||||
android:label="_QuickReject">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class QuickRejectActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final QuickRejectView view = new QuickRejectView(this);
|
||||
setContentView(view);
|
||||
}
|
||||
|
||||
static class QuickRejectView extends View {
|
||||
private Paint mBitmapPaint;
|
||||
private final Bitmap mBitmap1;
|
||||
|
||||
QuickRejectView(Context c) {
|
||||
super(c);
|
||||
|
||||
mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
|
||||
|
||||
mBitmapPaint = new Paint();
|
||||
mBitmapPaint.setFilterBitmap(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
canvas.save();
|
||||
canvas.clipRect(0.0f, 0.0f, 40.0f, 40.0f);
|
||||
canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint);
|
||||
canvas.drawBitmap(mBitmap1, -mBitmap1.getWidth(), 0.0f, mBitmapPaint);
|
||||
canvas.drawBitmap(mBitmap1, 50.0f, 0.0f, mBitmapPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user