diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 49ef8dc350d50..0ad3c0b732ec5 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -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 } } diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 612b0ab717e41..37b40e7bc2a97 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -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); } - diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 117fccd3d6dbe..f7b4455967adb 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -128,6 +128,7 @@ OpenGLRenderer::~OpenGLRenderer() { mTextureCache.clear(); mLayerCache.clear(); + mPatchCache.clear(); } /////////////////////////////////////////////////////////////////////////////// @@ -242,7 +243,7 @@ void OpenGLRenderer::composeLayer(sp current, sp 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& shader) { +bool OpenGLRenderer::useShader(const sp& 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) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index afb747fd4572e..a52489f642655 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -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& shader); + inline bool useShader(const sp& shader); // Dimensions of the drawing surface int mWidth, mHeight; diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index 3b5e5da0ad189..609b28a4f3616 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -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 diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 652befe1cb306..d90bcaf382eda 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -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. */ diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index e09e70fb39dcd..f13cfafc5ff2f 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -78,6 +78,15 @@ + + + + + + + diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java new file mode 100644 index 0000000000000..fd7a1e6c74417 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java @@ -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(); + } + } +} \ No newline at end of file