From ff316ec7a76e52572a2e89b691e6b3bba0cafba3 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Wed, 13 Feb 2013 18:39:43 -0800 Subject: [PATCH] Implement support for drawBitmapMesh's colors array Change-Id: I3d901f6267c2918771ac30ff55c8d80c3ab5b725 --- core/java/android/view/GLES20Canvas.java | 6 +- libs/hwui/Caches.cpp | 9 +- libs/hwui/Caches.h | 5 +- libs/hwui/OpenGLRenderer.cpp | 86 +++++++++++++++---- libs/hwui/OpenGLRenderer.h | 2 + libs/hwui/Program.h | 8 ++ libs/hwui/ProgramCache.cpp | 25 +++++- libs/hwui/Vertex.h | 20 ++++- .../android/test/hwui/BitmapMeshActivity.java | 2 +- 9 files changed, 136 insertions(+), 27 deletions(-) diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 80c9324aae996..b45fbabfec704 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -901,9 +901,9 @@ class GLES20Canvas extends HardwareCanvas { final int count = (meshWidth + 1) * (meshHeight + 1); checkRange(verts.length, vertOffset, count * 2); - // TODO: Colors are ignored for now - colors = null; - colorOffset = 0; + if (colors != null) { + checkRange(colors.length, colorOffset, count); + } int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; try { diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 74201d1fda586..88f1d83bf84de 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -365,11 +365,12 @@ void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei str } } -void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices) { - if (force || vertices != mCurrentTexCoordsPointer) { +void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) { + if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) { GLuint slot = currentProgram->texCoords; - glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices); + glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices); mCurrentTexCoordsPointer = vertices; + mCurrentTexCoordsStride = stride; } } @@ -390,7 +391,7 @@ void Caches::enableTexCoordsVertexArray() { } } -void Caches::disbaleTexCoordsVertexArray() { +void Caches::disableTexCoordsVertexArray() { if (mTexCoordsArrayEnabled) { glDisableVertexAttribArray(Program::kBindingTexCoords); mTexCoordsArrayEnabled = false; diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index d70c0e3fe77a6..0ca2ffd40a802 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -183,7 +183,7 @@ public: * Binds an attrib to the specified float vertex pointer. * Assumes a stride of gMeshStride and a size of 2. */ - void bindTexCoordsVertexPointer(bool force, GLvoid* vertices); + void bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride = gMeshStride); /** * Resets the vertex pointers. @@ -192,7 +192,7 @@ public: void resetTexCoordsVertexPointer(); void enableTexCoordsVertexArray(); - void disbaleTexCoordsVertexArray(); + void disableTexCoordsVertexArray(); /** * Activate the specified texture unit. The texture unit must @@ -299,6 +299,7 @@ private: void* mCurrentPositionPointer; GLsizei mCurrentPositionStride; void* mCurrentTexCoordsPointer; + GLsizei mCurrentTexCoordsStride; bool mTexCoordsArrayEnabled; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 2431e54cde8f8..f0d25e1e18abe 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -317,7 +317,7 @@ void OpenGLRenderer::interrupt() { mCaches.unbindMeshBuffer(); mCaches.unbindIndicesBuffer(); mCaches.resetVertexPointers(); - mCaches.disbaleTexCoordsVertexArray(); + mCaches.disableTexCoordsVertexArray(); debugOverdraw(false, false); } @@ -1469,12 +1469,18 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { mDescription.hasAlpha8Texture = isAlpha8; } +void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) { + mDescription.hasTexture = true; + mDescription.hasColors = true; + mDescription.hasAlpha8Texture = isAlpha8; +} + void OpenGLRenderer::setupDrawWithExternalTexture() { mDescription.hasExternalTexture = true; } void OpenGLRenderer::setupDrawNoTexture() { - mCaches.disbaleTexCoordsVertexArray(); + mCaches.disableTexCoordsVertexArray(); } void OpenGLRenderer::setupDrawAA() { @@ -1682,6 +1688,23 @@ void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint v mCaches.unbindIndicesBuffer(); } +void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors) { + bool force = mCaches.unbindMeshBuffer(); + GLsizei stride = sizeof(ColorTextureVertex); + + mCaches.bindPositionVertexPointer(force, vertices, stride); + if (mCaches.currentProgram->texCoords >= 0) { + mCaches.bindTexCoordsVertexPointer(force, texCoords, stride); + } + int slot = mCaches.currentProgram->getAttrib("colors"); + if (slot >= 0) { + glEnableVertexAttribArray(slot); + glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors); + } + + mCaches.unbindIndicesBuffer(); +} + void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) { bool force = mCaches.unbindMeshBuffer(); mCaches.bindPositionVertexPointer(force, vertices); @@ -1833,9 +1856,16 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes const uint32_t count = meshWidth * meshHeight * 6; - // TODO: Support the colors array - TextureVertex mesh[count]; - TextureVertex* vertex = mesh; + ColorTextureVertex mesh[count]; + ColorTextureVertex* vertex = mesh; + + bool cleanupColors = false; + if (!colors) { + uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1); + colors = new int[colorsCount]; + memset(colors, 0xff, colorsCount * sizeof(int)); + cleanupColors = true; + } for (int32_t y = 0; y < meshHeight; y++) { for (int32_t x = 0; x < meshWidth; x++) { @@ -1855,13 +1885,13 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes int dx = i + (meshWidth + 1) * 2 + 2; int dy = dx + 1; - TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2); - TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1); - TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); + ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); + ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]); + ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2); - TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); - TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2); + ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); + ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); + ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]); left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx]))); top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy]))); @@ -1871,12 +1901,16 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes } if (quickReject(left, top, right, bottom)) { + if (cleanupColors) delete[] colors; return DrawGlInfo::kStatusDone; } mCaches.activeTexture(0); Texture* texture = mCaches.textureCache.get(bitmap); - if (!texture) return DrawGlInfo::kStatusDone; + if (!texture) { + if (cleanupColors) delete[] colors; + return DrawGlInfo::kStatusDone; + } const AutoTexture autoCleanup(texture); texture->setWrap(GL_CLAMP_TO_EDGE, true); @@ -1886,13 +1920,35 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); + float a = alpha / 255.0f; + if (hasLayer()) { dirtyLayer(left, top, right, bottom, *mSnapshot->transform); } - drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f, - mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0], - GL_TRIANGLES, count, false, false, 0, false, false); + setupDraw(); + setupDrawWithTextureAndColor(); + setupDrawColor(a, a, a, a); + setupDrawColorFilter(); + setupDrawBlending(true, mode, false); + setupDrawProgram(); + setupDrawDirtyRegionsDisabled(); + setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false); + setupDrawTexture(texture->id); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0], &mesh[0].color[0]); + + glDrawArrays(GL_TRIANGLES, 0, count); + + finishDrawTexture(); + + int slot = mCaches.currentProgram->getAttrib("colors"); + if (slot >= 0) { + glDisableVertexAttribArray(slot); + } + + if (cleanupColors) delete[] colors; return DrawGlInfo::kStatusDrew; } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 0ad81c1f64e6a..ad80d36cbaa2f 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -777,6 +777,7 @@ private: * Various methods to setup OpenGL rendering. */ void setupDrawWithTexture(bool isAlpha8 = false); + void setupDrawWithTextureAndColor(bool isAlpha8 = false); void setupDrawWithExternalTexture(); void setupDrawNoTexture(); void setupDrawAA(); @@ -811,6 +812,7 @@ private: void setupDrawTextureTransformUniforms(mat4& transform); void setupDrawTextGammaUniforms(); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); + void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors); void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords); void setupDrawVertices(GLvoid* vertices); void finishDrawTexture(); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index b1df98057b385..7b67b3c3ffc3c 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -81,6 +81,8 @@ namespace uirenderer { #define PROGRAM_IS_SIMPLE_GRADIENT 41 +#define PROGRAM_HAS_COLORS 42 + /////////////////////////////////////////////////////////////////////////////// // Types /////////////////////////////////////////////////////////////////////////////// @@ -120,6 +122,9 @@ struct ProgramDescription { bool hasExternalTexture; bool hasTextureTransform; + // Color attribute + bool hasColors; + // Modulate, this should only be set when setColor() return true bool modulate; @@ -164,6 +169,8 @@ struct ProgramDescription { hasExternalTexture = false; hasTextureTransform = false; + hasColors = false; + isAA = false; modulate = false; @@ -259,6 +266,7 @@ struct ProgramDescription { if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION; if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT; + if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS; return key; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index fb00335ebd499..74d598d5311e9 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -40,6 +40,8 @@ const char* gVS_Header_Attributes = "attribute vec4 position;\n"; const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; +const char* gVS_Header_Attributes_Colors = + "attribute vec4 colors;\n"; const char* gVS_Header_Attributes_AAVertexShapeParameters = "attribute float vtxAlpha;\n"; const char* gVS_Header_Uniforms_TextureTransform = @@ -65,6 +67,8 @@ const char* gVS_Header_Uniforms_HasBitmap = "uniform mediump vec2 textureDimension;\n"; const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; +const char* gVS_Header_Varyings_HasColors = + "varying vec4 outColors;\n"; const char* gVS_Header_Varyings_IsAAVertexShape = "varying float alpha;\n"; const char* gVS_Header_Varyings_HasBitmap = @@ -94,6 +98,8 @@ const char* gVS_Main = "\nvoid main(void) {\n"; const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n"; +const char* gVS_Main_OutColors = + " outColors = colors;\n"; const char* gVS_Main_OutTransformedTexCoords = " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n"; const char* gVS_Main_OutGradient[6] = { @@ -325,6 +331,8 @@ const char* gFS_Main_BitmapShader_Modulate[6] = { }; const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n"; +const char* gFS_Main_FragColor_HasColors = + " gl_FragColor *= outColors;\n"; const char* gFS_Main_FragColor_Blend = " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n"; const char* gFS_Main_FragColor_Blend_Swap = @@ -459,6 +467,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.isAA) { shader.append(gVS_Header_Attributes_AAVertexShapeParameters); } + if (description.hasColors) { + shader.append(gVS_Header_Attributes_Colors); + } // Uniforms shader.append(gVS_Header_Uniforms); if (description.hasTextureTransform) { @@ -480,6 +491,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.isAA) { shader.append(gVS_Header_Varyings_IsAAVertexShape); } + if (description.hasColors) { + shader.append(gVS_Header_Varyings_HasColors); + } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); } @@ -499,6 +513,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.isAA) { shader.append(gVS_Main_AAVertexShape); } + if (description.hasColors) { + shader.append(gVS_Main_OutColors); + } if (description.hasBitmap) { shader.append(description.isPoint ? gVS_Main_OutPointBitmapTexCoords : @@ -549,6 +566,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.isAA) { shader.append(gVS_Header_Varyings_IsAAVertexShape); } + if (description.hasColors) { + shader.append(gVS_Header_Varyings_HasColors); + } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); } @@ -583,7 +603,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Optimization for common cases - if (!description.isAA && !blendFramebuffer && + if (!description.isAA && !blendFramebuffer && !description.hasColors && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; @@ -729,6 +749,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); } + if (description.hasColors) { + shader.append(gFS_Main_FragColor_HasColors); + } } // End the shader shader.append(gFS_Footer); diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index c120428e16d0f..523120e358ba6 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -33,7 +33,7 @@ struct Vertex { }; // struct Vertex /** - * Simple structure to describe a vertex with a position and a texture. + * Simple structure to describe a vertex with a position and texture UV. */ struct TextureVertex { float position[2]; @@ -52,6 +52,24 @@ struct TextureVertex { } }; // struct TextureVertex +/** + * Simple structure to describe a vertex with a position, texture UV and ARGB color. + */ +struct ColorTextureVertex : TextureVertex { + float color[4]; + + static inline void set(ColorTextureVertex* vertex, float x, float y, + float u, float v, int color) { + TextureVertex::set(vertex, x, y, u, v); + + const float a = ((color >> 24) & 0xff) / 255.0f; + vertex[0].color[0] = a * ((color >> 16) & 0xff) / 255.0f; + vertex[0].color[1] = a * ((color >> 8) & 0xff) / 255.0f; + vertex[0].color[2] = a * ((color ) & 0xff) / 255.0f; + vertex[0].color[3] = a; + } +}; // struct ColorTextureVertex + /** * Simple structure to describe a vertex with a position and an alpha value. */ diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java index 854dd69a86468..69d34a590a468 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java @@ -54,7 +54,7 @@ public class BitmapMeshActivity extends Activity { 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, }; - + mColors = new int[] { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000, 0xff0000ff, 0xffff0000, 0xff00ff00, 0xff00ff00,