diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index ca9a38e58757e..094e9ab91fa91 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1340,30 +1340,20 @@ void OpenGLRenderer::setupDrawPoint(float pointSize) { mDescription.pointSize = pointSize; } -void OpenGLRenderer::setupDrawColor(int color) { - setupDrawColor(color, (color >> 24) & 0xFF); -} - void OpenGLRenderer::setupDrawColor(int color, int alpha) { mColorA = alpha / 255.0f; - // Second divide of a by 255 is an optimization, allowing us to simply multiply - // the rgb values by a instead of also dividing by 255 - const float a = mColorA / 255.0f; - mColorR = a * ((color >> 16) & 0xFF); - mColorG = a * ((color >> 8) & 0xFF); - mColorB = a * ((color ) & 0xFF); + mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; + mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; + mColorB = mColorA * ((color ) & 0xFF) / 255.0f; mColorSet = true; mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA); } void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) { mColorA = alpha / 255.0f; - // Double-divide of a by 255 is an optimization, allowing us to simply multiply - // the rgb values by a instead of also dividing by 255 - const float a = mColorA / 255.0f; - mColorR = a * ((color >> 16) & 0xFF); - mColorG = a * ((color >> 8) & 0xFF); - mColorB = a * ((color ) & 0xFF); + mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; + mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; + mColorB = mColorA * ((color ) & 0xFF) / 255.0f; mColorSet = true; mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA); } @@ -1625,43 +1615,27 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, Sk SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); + int color = paint != NULL ? paint->getColor() : 0; + float x = left; float y = top; - GLenum filter = GL_LINEAR; + texture->setWrap(GL_CLAMP_TO_EDGE, true); + bool ignoreTransform = false; if (mSnapshot->transform->isPureTranslate()) { x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); ignoreTransform = true; - filter = GL_NEAREST; + + texture->setFilter(GL_NEAREST, true); } else { - filter = FILTER(paint); + texture->setFilter(FILTER(paint), true); } - setupDraw(); - setupDrawWithTexture(true); - if (paint) { - setupDrawAlpha8Color(paint->getColor(), alpha); - } - setupDrawColorFilter(); - setupDrawShader(); - setupDrawBlending(true, mode); - setupDrawProgram(); - setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform); - - setupDrawTexture(texture->id); - texture->setWrap(GL_CLAMP_TO_EDGE); - texture->setFilter(filter); - - setupDrawPureColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderUniforms(); - setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); - - finishDrawTexture(); + drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id, + paint != NULL, color, alpha, mode, (GLvoid*) NULL, + (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); } status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { @@ -1704,7 +1678,11 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* // to the vertex shader. The save/restore is a bit overkill. save(SkCanvas::kMatrix_SaveFlag); concatMatrix(matrix); - drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint); + if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { + drawAlphaBitmap(texture, 0.0f, 0.0f, paint); + } else { + drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint); + } restore(); return DrawGlInfo::kStatusDrew; @@ -1722,7 +1700,11 @@ status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, Texture* texture = mCaches.textureCache.getTransient(bitmap); const AutoTexture autoCleanup(texture); - drawTextureRect(left, top, right, bottom, texture, paint); + if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { + drawAlphaBitmap(texture, left, top, paint); + } else { + drawTextureRect(left, top, right, bottom, texture, paint); + } return DrawGlInfo::kStatusDrew; } @@ -1836,26 +1818,59 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, texture->setWrap(GL_CLAMP_TO_EDGE, true); - if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { - const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f); - const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f); + float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft); + float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop); - GLenum filter = GL_NEAREST; - // Enable linear filtering if the source rectangle is scaled - if (srcRight - srcLeft != dstRight - dstLeft || srcBottom - srcTop != dstBottom - dstTop) { - filter = FILTER(paint); - } + bool scaled = scaleX != 1.0f || scaleY != 1.0f; + // Apply a scale transform on the canvas only when a shader is in use + // Skia handles the ratio between the dst and src rects as a scale factor + // when a shader is set + bool useScaleTransform = mShader && scaled; + bool ignoreTransform = false; - texture->setFilter(filter, true); - drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop), - texture->id, alpha / 255.0f, mode, texture->blend, - &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], - GL_TRIANGLE_STRIP, gMeshCount, false, true); + if (CC_LIKELY(mSnapshot->transform->isPureTranslate() && !useScaleTransform)) { + float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f); + float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f); + + dstRight = x + (dstRight - dstLeft); + dstBottom = y + (dstBottom - dstTop); + + dstLeft = x; + dstTop = y; + + texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true); + ignoreTransform = true; } else { texture->setFilter(FILTER(paint), true); - drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f, - mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], - GL_TRIANGLE_STRIP, gMeshCount); + } + + if (CC_UNLIKELY(useScaleTransform)) { + save(SkCanvas::kMatrix_SaveFlag); + translate(dstLeft, dstTop); + scale(scaleX, scaleY); + + dstLeft = 0.0f; + dstTop = 0.0f; + + dstRight = srcRight - srcLeft; + dstBottom = srcBottom - srcTop; + } + + if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { + int color = paint ? paint->getColor() : 0; + drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom, + texture->id, paint != NULL, color, alpha, mode, + &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], + GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); + } else { + drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, + texture->id, alpha / 255.0f, mode, texture->blend, + &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], + GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform); + } + + if (CC_UNLIKELY(useScaleTransform)) { + restore(); } resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); @@ -3094,17 +3109,15 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b setupDrawColorFilter(); setupDrawBlending(blend, mode, swapSrcDst); setupDrawProgram(); - if (!dirty) { - setupDrawDirtyRegionsDisabled(); - } + if (!dirty) setupDrawDirtyRegionsDisabled(); if (!ignoreScale) { setupDrawModelView(left, top, right, bottom, ignoreTransform); } else { setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform); } + setupDrawTexture(texture); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); - setupDrawTexture(texture); setupDrawMesh(vertices, texCoords, vbo); glDrawArrays(drawMode, 0, elementsCount); @@ -3112,6 +3125,33 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b finishDrawTexture(); } +void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom, + GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode, + GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, + bool ignoreTransform, bool dirty) { + + setupDraw(); + setupDrawWithTexture(true); + if (hasColor) { + setupDrawAlpha8Color(color, alpha); + } + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + if (!dirty) setupDrawDirtyRegionsDisabled(); + setupDrawModelView(left, top, right, bottom, ignoreTransform); + setupDrawTexture(texture); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); + setupDrawMesh(vertices, texCoords); + + glDrawArrays(drawMode, 0, elementsCount); + + finishDrawTexture(); +} + void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description, bool swapSrcDst) { blend = blend || mode != SkXfermode::kSrcOver_Mode; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index f16558174b17b..3cafed361e66a 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -596,6 +596,11 @@ private: bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0, bool ignoreScale = false, bool dirty = true); + void drawAlpha8TextureMesh(float left, float top, float right, float bottom, + GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode, + GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, + bool ignoreTransform, bool dirty = true); + /** * Draws text underline and strike-through if needed. * @@ -700,7 +705,6 @@ private: void setupDrawAA(); void setupDrawVertexShape(); void setupDrawPoint(float pointSize); - void setupDrawColor(int color); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 9118aea1f575d..1974e0fc9f4e6 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -32,6 +32,15 @@ + + + + + + + diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/spot_mask.png b/tests/HwAccelerationTest/res/drawable-nodpi/spot_mask.png new file mode 100644 index 0000000000000..89537594e1a66 Binary files /dev/null and b/tests/HwAccelerationTest/res/drawable-nodpi/spot_mask.png differ diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java new file mode 100644 index 0000000000000..5fe512e550725 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java @@ -0,0 +1,97 @@ +/* + * 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.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class Alpha8BitmapActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(new BitmapsView(this)); + } + + static class BitmapsView extends View { + private Paint mBitmapPaint; + private final Bitmap mBitmap1; + private final float[] mVertices; + + BitmapsView(Context c) { + super(c); + + Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.spot_mask); + mBitmap1 = Bitmap.createBitmap(texture.getWidth(), texture.getHeight(), + Bitmap.Config.ALPHA_8); + Canvas canvas = new Canvas(mBitmap1); + canvas.drawBitmap(texture, 0.0f, 0.0f, null); + + texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + BitmapShader shader = new BitmapShader(texture, + Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); + + final float width = texture.getWidth() / 3.0f; + final float height = texture.getHeight() / 3.0f; + + mVertices = new float[] { + 0.0f, 0.0f, width, 0.0f, width * 2, 0.0f, width * 3, 0.0f, + 0.0f, height, width, height, width * 2, height, width * 4, height, + 0.0f, height * 2, width, height * 2, width * 2, height * 2, width * 3, height * 2, + 0.0f, height * 4, width, height * 4, width * 2, height * 4, width * 4, height * 4, + }; + + mBitmapPaint = new Paint(); + mBitmapPaint.setFilterBitmap(true); + mBitmapPaint.setShader(shader); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.drawColor(0xffffffff); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint); + + Matrix matrix = new Matrix(); + matrix.setScale(2.0f, 2.0f); + matrix.postTranslate(0.0f, mBitmap1.getHeight()); + canvas.drawBitmap(mBitmap1, matrix, mBitmapPaint); + + Rect src = new Rect(0, 0, mBitmap1.getWidth() / 2, mBitmap1.getHeight() / 2); + Rect dst = new Rect(0, mBitmap1.getHeight() * 3, mBitmap1.getWidth(), + mBitmap1.getHeight() * 4); + canvas.drawBitmap(mBitmap1, src, dst, mBitmapPaint); + + canvas.translate(0.0f, mBitmap1.getHeight() * 4); + canvas.drawBitmapMesh(mBitmap1, 3, 3, mVertices, 0, null, 0, mBitmapPaint); + + invalidate(); + } + } +}