Loading libs/hwui/Caches.h +3 −0 Original line number Diff line number Diff line Loading @@ -60,7 +60,10 @@ static const TextureVertex gMeshVertices[] = { FV(1.0f, 1.0f, 1.0f, 1.0f) }; static const GLsizei gMeshStride = sizeof(TextureVertex); static const GLsizei gVertexStride = sizeof(Vertex); static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex); static const GLsizei gMeshTextureOffset = 2 * sizeof(float); static const GLsizei gVertexAlphaOffset = 2 * sizeof(float); static const GLsizei gMeshCount = 4; /////////////////////////////////////////////////////////////////////////////// Loading libs/hwui/OpenGLRenderer.cpp +205 −84 Original line number Diff line number Diff line Loading @@ -882,6 +882,10 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { mDescription.hasAlpha8Texture = isAlpha8; } void OpenGLRenderer::setupDrawAALine() { mDescription.hasWidth = true; } void OpenGLRenderer::setupDrawPoint(float pointSize) { mDescription.isPoint = true; mDescription.pointSize = pointSize; Loading @@ -893,6 +897,7 @@ void OpenGLRenderer::setupDrawColor(int color) { void OpenGLRenderer::setupDrawColor(int color, int alpha) { mColorA = alpha / 255.0f; // BUG on this next line? a is alpha divided by 255 *twice* const float a = mColorA / 255.0f; mColorR = a * ((color >> 16) & 0xFF); mColorG = a * ((color >> 8) & 0xFF); Loading Loading @@ -1060,6 +1065,37 @@ void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint v } } void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { mCaches.unbindMeshBuffer(); glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gVertexStride, vertices); } /** * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an * outer boundary that fades out to 0. The variables set in the shader define the width of the * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment * shader where the fragment is in relation to the line width overall; this value is then used * to compute the proper color, based on whether the fragment lies in the fading AA region of * the line. */ void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) { mCaches.unbindMeshBuffer(); glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gAlphaVertexStride, vertices); int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance"); glEnableVertexAttribArray(distanceSlot); glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords); int widthSlot = mCaches.currentProgram->getUniform("width"); int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth"); float boundaryWidth = (1 - strokeWidth) / 2; glUniform1f(widthSlot, strokeWidth); glUniform1f(boundaryWidthSlot, boundaryWidth); glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth)); } void OpenGLRenderer::finishDrawTexture() { glDisableVertexAttribArray(mTexCoordsSlot); } Loading Loading @@ -1350,46 +1386,55 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); const float strokeWidth = paint->getStrokeWidth() * 0.5f; // A stroke width of 0 has a special meaningin Skia: // it draws an unscaled 1px wide line const bool isHairLine = paint->getStrokeWidth() == 0.0f; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); int verticesCount = count >> 2; int generatedVerticesCount = 0; if (!isHairLine) { // TODO: AA needs more vertices verticesCount *= 6; void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline, float strokeWidth) { int verticesCount = count; if (count > 4) { // Polyline: account for extra vertices needed for continous tri-strip verticesCount += (count -4); } if (isAA) { // Expand boundary to enable AA calculations on the quad border strokeWidth += .5f; } Vertex lines[verticesCount]; Vertex* vertices = &lines[0]; AlphaVertex wLines[verticesCount]; AlphaVertex* aaVertices = &wLines[0]; if (!isAA) { setupDrawVertices(vertices); } else { // TODO: AA will be different verticesCount *= 2; void *alphaCoords = ((void*) aaVertices) + gVertexAlphaOffset; // innerProportion is the ratio of the inner (non-AA) port of the line to the total // AA stroke width (the base stroke width expanded by a half pixel on either side). // This value is used in the fragment shader to determine how to fill fragments. float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f); setupDrawAALine((void*) aaVertices, (void*) alphaCoords, innerProportion); } TextureVertex lines[verticesCount]; TextureVertex* vertex = &lines[0]; setupDraw(); setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); setupDrawBlending(mode); setupDrawProgram(); setupDrawModelViewIdentity(); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderIdentityUniforms(); setupDrawMesh(vertex); if (!isHairLine) { // TODO: Handle the AA case int generatedVerticesCount = 0; AlphaVertex *prevAAVertex = NULL; Vertex *prevVertex = NULL; float inverseScaleX, inverseScaleY; if (isHairline) { // The quad that we use for AA hairlines needs to account for scaling because the line // should always be one pixel wide regardless of scale. inverseScaleX = 1.0f; inverseScaleY = 1.0f; if (!mSnapshot->transform->isPureTranslate()) { Matrix4 *mat = mSnapshot->transform; float m00 = mat->data[Matrix4::kScaleX]; float m01 = mat->data[Matrix4::kSkewY]; float m02 = mat->data[2]; float m10 = mat->data[Matrix4::kSkewX]; float m11 = mat->data[Matrix4::kScaleX]; float m12 = mat->data[6]; float scaleX = sqrt(m00*m00 + m01*m01); float scaleY = sqrt(m10*m10 + m11*m11); inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0; inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; } } for (int i = 0; i < count; i += 4) { // a = start point, b = end point vec2 a(points[i], points[i + 1]); Loading @@ -1401,6 +1446,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // Find the normal to the line vec2 n = (b - a).copyNormalized() * strokeWidth; if (isHairline) { float wideningFactor; if (fabs(n.x) >= fabs(n.y)) { wideningFactor = fabs(1.0f / n.x); } else { wideningFactor = fabs(1.0f / n.y); } n.x *= inverseScaleX; n.y *= inverseScaleY; n *= wideningFactor; } float x = n.x; n.x = -n.y; n.y = x; Loading @@ -1421,36 +1477,100 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // by using only 4 vertices and the correct indices // Also we should probably used non textured vertices // when line AA is disabled to save on bandwidth TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); generatedVerticesCount += 6; if (!isAA) { if (prevVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge // between the previous line and the new one. This is necessary because // we are creating a single triangle_strip which will contain // potentially discontinuous line segments. Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]); Vertex::set(vertices++, p1.x, p1.y); generatedVerticesCount += 2; } Vertex::set(vertices++, p1.x, p1.y); Vertex::set(vertices++, p2.x, p2.y); Vertex::set(vertices++, p4.x, p4.y); Vertex::set(vertices++, p3.x, p3.y); prevVertex = vertices - 1; generatedVerticesCount += 4; } else { if (prevAAVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge // between the previous line and the new one. This is necessary because // we are creating a single triangle_strip which will contain // potentially discontinuous line segments. AlphaVertex::set(aaVertices++,prevAAVertex->position[0], prevAAVertex->position[1], prevAAVertex->alpha); AlphaVertex::set(aaVertices++, p4.x, p4.y, 1); generatedVerticesCount += 2; } AlphaVertex::set(aaVertices++, p4.x, p4.y, 1); AlphaVertex::set(aaVertices++, p1.x, p1.y, 1); AlphaVertex::set(aaVertices++, p3.x, p3.y, 0); AlphaVertex::set(aaVertices++, p2.x, p2.y, 0); prevAAVertex = aaVertices - 1; generatedVerticesCount += 4; } dirtyLayer(left, top, right, bottom, *mSnapshot->transform); } } if (generatedVerticesCount > 0) { // GL_LINE does not give the result we want to match Skia glDrawArrays(GL_TRIANGLES, 0, generatedVerticesCount); glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount); } } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); const float strokeWidth = paint->getStrokeWidth() * 0.5f; // A stroke width of 0 has a special meaning in Skia: // it draws a line 1 px wide regardless of current transform bool isHairLine = paint->getStrokeWidth() == 0.0f; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); int generatedVerticesCount = 0; setupDraw(); if (isAA) { setupDrawAALine(); } setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); if (isAA) { setupDrawBlending(true, mode); } else { // TODO: Handle the AA case for (int i = 0; i < count; i += 4) { TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); setupDrawBlending(mode); } setupDrawProgram(); setupDrawModelViewIdentity(); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderIdentityUniforms(); generatedVerticesCount += 2; if (!isHairLine) { drawLinesAsQuads(points, count, isAA, isHairLine, strokeWidth); } else { if (isAA) { drawLinesAsQuads(points, count, isAA, isHairLine, .5f); } else { int verticesCount = count >> 1; Vertex lines[verticesCount]; Vertex* vertices = &lines[0]; setupDrawVertices(vertices); for (int i = 0; i < count; i += 4) { const float left = fmin(points[i], points[i + 2]); const float right = fmax(points[i], points[i + 2]); const float top = fmin(points[i + 1], points[i + 3]); const float bottom = fmax(points[i + 1], points[i + 3]); Vertex::set(vertices++, points[i], points[i + 1]); Vertex::set(vertices++, points[i + 2], points[i + 3]); generatedVerticesCount += 2; dirtyLayer(left, top, right == left ? left + 1 : right, bottom == top ? top + 1 : bottom, *mSnapshot->transform); Loading @@ -1460,6 +1580,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { glDrawArrays(GL_LINES, 0, generatedVerticesCount); } } } void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; Loading libs/hwui/OpenGLRenderer.h +16 −0 Original line number Diff line number Diff line Loading @@ -282,6 +282,19 @@ private: void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint); /** * Draws a line as a quad. Called by drawLines() for all cases except hairline without AA. * * @param points The vertices of the lines. Every four entries specifies the x/y points * of a single line segment. * @param count The number of entries in the points array. * @param isAA Whether the line is anti-aliased * @param isHairline Whether the line has strokeWidth==0, which results in the line being * one pixel wide on the display regardless of scale. */ void drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline, float strokeWidth); /** * Draws a textured rectangle with the specified texture. The specified coordinates * are transformed by the current snapshot's transform matrix. Loading Loading @@ -425,6 +438,7 @@ private: * Various methods to setup OpenGL rendering. */ void setupDrawWithTexture(bool isAlpha8 = false); void setupDrawAALine(); void setupDrawPoint(float pointSize); void setupDrawColor(int color); void setupDrawColor(int color, int alpha); Loading Loading @@ -453,6 +467,8 @@ private: void setupDrawSimpleMesh(); void setupDrawTexture(GLuint texture); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void setupDrawVertices(GLvoid* vertices); void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth); void finishDrawTexture(); void drawRegionRects(const Region& region); Loading libs/hwui/ProgramCache.cpp +36 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,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_Distance = "attribute float vtxDistance;\n"; const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; const char* gVS_Header_Uniforms_IsPoint = Loading @@ -56,6 +58,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_HasWidth = "varying float distance;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; const char* gVS_Header_Varyings_PointHasBitmap = Loading Loading @@ -88,6 +92,8 @@ const char* gVS_Main_Position = " gl_Position = transform * position;\n"; const char* gVS_Main_PointSize = " gl_PointSize = pointSize;\n"; const char* gVS_Main_Width = " distance = vtxDistance;\n"; const char* gVS_Footer = "}\n\n"; Loading @@ -101,6 +107,10 @@ const char* gFS_Header = "precision mediump float;\n\n"; const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; const char* gFS_Uniforms_Width = "uniform float width;\n" "uniform float boundaryWidth;\n" "uniform float inverseBoundaryWidth;\n"; const char* gFS_Header_Uniforms_PointHasBitmap = "uniform vec2 textureDimension;\n" "uniform float pointSize;\n"; Loading Loading @@ -169,6 +179,12 @@ const char* gFS_Fast_SingleModulateGradient = // General case const char* gFS_Main_FetchColor = " fragColor = color;\n"; const char* gFS_Main_AccountForWidth = " if (distance < boundaryWidth) {\n" " fragColor *= (distance * inverseBoundaryWidth);\n" " } else if (distance > (1.0 - boundaryWidth)) {\n" " fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n" " }\n"; const char* gFS_Main_FetchTexture[2] = { // Don't modulate " fragColor = texture2D(sampler, outTexCoords);\n", Loading Loading @@ -354,6 +370,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture) { shader.append(gVS_Header_Attributes_TexCoords); } if (description.hasWidth) { shader.append(gVS_Header_Attributes_Distance); } // Uniforms shader.append(gVS_Header_Uniforms); if (description.hasGradient) { Loading @@ -369,6 +388,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasWidth) { shader.append(gVS_Header_Varyings_HasWidth); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } Loading @@ -383,6 +405,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture) { shader.append(gVS_Main_OutTexCoords); } if (description.hasWidth) { shader.append(gVS_Main_Width); } if (description.hasGradient) { shader.append(gVS_Main_OutGradient[description.gradientType]); } Loading Loading @@ -420,6 +445,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasWidth) { shader.append(gVS_Header_Varyings_HasWidth); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } Loading @@ -441,6 +469,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } if (description.hasWidth) { shader.append(gFS_Uniforms_Width); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } Loading @@ -449,8 +480,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Optimization for common cases if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { if (!description.hasWidth && !blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; Loading Loading @@ -534,6 +565,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchColor); } } if (description.hasWidth) { shader.append(gFS_Main_AccountForWidth); } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); } Loading libs/hwui/ProgramCache.h +6 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ namespace uirenderer { #define PROGRAM_KEY_COLOR_BLEND 0x80 #define PROGRAM_KEY_BITMAP_NPOT 0x100 #define PROGRAM_KEY_SWAP_SRC_DST 0x2000 #define PROGRAM_KEY_VERTEX_WIDTH 0x4000 #define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600 #define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800 Loading Loading @@ -119,6 +120,8 @@ struct ProgramDescription { bool hasBitmap; bool isBitmapNpot; bool hasWidth; bool hasGradient; Gradient gradientType; Loading Loading @@ -148,6 +151,8 @@ struct ProgramDescription { hasTexture = false; hasAlpha8Texture = false; hasWidth = false; modulate = false; hasBitmap = false; Loading Loading @@ -200,6 +205,7 @@ struct ProgramDescription { programid key() const { programid key = 0; if (hasTexture) key |= PROGRAM_KEY_TEXTURE; if (hasWidth) key |= PROGRAM_KEY_VERTEX_WIDTH; if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE; if (hasBitmap) { key |= PROGRAM_KEY_BITMAP; Loading Loading
libs/hwui/Caches.h +3 −0 Original line number Diff line number Diff line Loading @@ -60,7 +60,10 @@ static const TextureVertex gMeshVertices[] = { FV(1.0f, 1.0f, 1.0f, 1.0f) }; static const GLsizei gMeshStride = sizeof(TextureVertex); static const GLsizei gVertexStride = sizeof(Vertex); static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex); static const GLsizei gMeshTextureOffset = 2 * sizeof(float); static const GLsizei gVertexAlphaOffset = 2 * sizeof(float); static const GLsizei gMeshCount = 4; /////////////////////////////////////////////////////////////////////////////// Loading
libs/hwui/OpenGLRenderer.cpp +205 −84 Original line number Diff line number Diff line Loading @@ -882,6 +882,10 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { mDescription.hasAlpha8Texture = isAlpha8; } void OpenGLRenderer::setupDrawAALine() { mDescription.hasWidth = true; } void OpenGLRenderer::setupDrawPoint(float pointSize) { mDescription.isPoint = true; mDescription.pointSize = pointSize; Loading @@ -893,6 +897,7 @@ void OpenGLRenderer::setupDrawColor(int color) { void OpenGLRenderer::setupDrawColor(int color, int alpha) { mColorA = alpha / 255.0f; // BUG on this next line? a is alpha divided by 255 *twice* const float a = mColorA / 255.0f; mColorR = a * ((color >> 16) & 0xFF); mColorG = a * ((color >> 8) & 0xFF); Loading Loading @@ -1060,6 +1065,37 @@ void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint v } } void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { mCaches.unbindMeshBuffer(); glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gVertexStride, vertices); } /** * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an * outer boundary that fades out to 0. The variables set in the shader define the width of the * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment * shader where the fragment is in relation to the line width overall; this value is then used * to compute the proper color, based on whether the fragment lies in the fading AA region of * the line. */ void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) { mCaches.unbindMeshBuffer(); glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gAlphaVertexStride, vertices); int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance"); glEnableVertexAttribArray(distanceSlot); glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords); int widthSlot = mCaches.currentProgram->getUniform("width"); int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth"); float boundaryWidth = (1 - strokeWidth) / 2; glUniform1f(widthSlot, strokeWidth); glUniform1f(boundaryWidthSlot, boundaryWidth); glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth)); } void OpenGLRenderer::finishDrawTexture() { glDisableVertexAttribArray(mTexCoordsSlot); } Loading Loading @@ -1350,46 +1386,55 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); const float strokeWidth = paint->getStrokeWidth() * 0.5f; // A stroke width of 0 has a special meaningin Skia: // it draws an unscaled 1px wide line const bool isHairLine = paint->getStrokeWidth() == 0.0f; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); int verticesCount = count >> 2; int generatedVerticesCount = 0; if (!isHairLine) { // TODO: AA needs more vertices verticesCount *= 6; void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline, float strokeWidth) { int verticesCount = count; if (count > 4) { // Polyline: account for extra vertices needed for continous tri-strip verticesCount += (count -4); } if (isAA) { // Expand boundary to enable AA calculations on the quad border strokeWidth += .5f; } Vertex lines[verticesCount]; Vertex* vertices = &lines[0]; AlphaVertex wLines[verticesCount]; AlphaVertex* aaVertices = &wLines[0]; if (!isAA) { setupDrawVertices(vertices); } else { // TODO: AA will be different verticesCount *= 2; void *alphaCoords = ((void*) aaVertices) + gVertexAlphaOffset; // innerProportion is the ratio of the inner (non-AA) port of the line to the total // AA stroke width (the base stroke width expanded by a half pixel on either side). // This value is used in the fragment shader to determine how to fill fragments. float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f); setupDrawAALine((void*) aaVertices, (void*) alphaCoords, innerProportion); } TextureVertex lines[verticesCount]; TextureVertex* vertex = &lines[0]; setupDraw(); setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); setupDrawBlending(mode); setupDrawProgram(); setupDrawModelViewIdentity(); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderIdentityUniforms(); setupDrawMesh(vertex); if (!isHairLine) { // TODO: Handle the AA case int generatedVerticesCount = 0; AlphaVertex *prevAAVertex = NULL; Vertex *prevVertex = NULL; float inverseScaleX, inverseScaleY; if (isHairline) { // The quad that we use for AA hairlines needs to account for scaling because the line // should always be one pixel wide regardless of scale. inverseScaleX = 1.0f; inverseScaleY = 1.0f; if (!mSnapshot->transform->isPureTranslate()) { Matrix4 *mat = mSnapshot->transform; float m00 = mat->data[Matrix4::kScaleX]; float m01 = mat->data[Matrix4::kSkewY]; float m02 = mat->data[2]; float m10 = mat->data[Matrix4::kSkewX]; float m11 = mat->data[Matrix4::kScaleX]; float m12 = mat->data[6]; float scaleX = sqrt(m00*m00 + m01*m01); float scaleY = sqrt(m10*m10 + m11*m11); inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0; inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; } } for (int i = 0; i < count; i += 4) { // a = start point, b = end point vec2 a(points[i], points[i + 1]); Loading @@ -1401,6 +1446,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // Find the normal to the line vec2 n = (b - a).copyNormalized() * strokeWidth; if (isHairline) { float wideningFactor; if (fabs(n.x) >= fabs(n.y)) { wideningFactor = fabs(1.0f / n.x); } else { wideningFactor = fabs(1.0f / n.y); } n.x *= inverseScaleX; n.y *= inverseScaleY; n *= wideningFactor; } float x = n.x; n.x = -n.y; n.y = x; Loading @@ -1421,36 +1477,100 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // by using only 4 vertices and the correct indices // Also we should probably used non textured vertices // when line AA is disabled to save on bandwidth TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); generatedVerticesCount += 6; if (!isAA) { if (prevVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge // between the previous line and the new one. This is necessary because // we are creating a single triangle_strip which will contain // potentially discontinuous line segments. Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]); Vertex::set(vertices++, p1.x, p1.y); generatedVerticesCount += 2; } Vertex::set(vertices++, p1.x, p1.y); Vertex::set(vertices++, p2.x, p2.y); Vertex::set(vertices++, p4.x, p4.y); Vertex::set(vertices++, p3.x, p3.y); prevVertex = vertices - 1; generatedVerticesCount += 4; } else { if (prevAAVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge // between the previous line and the new one. This is necessary because // we are creating a single triangle_strip which will contain // potentially discontinuous line segments. AlphaVertex::set(aaVertices++,prevAAVertex->position[0], prevAAVertex->position[1], prevAAVertex->alpha); AlphaVertex::set(aaVertices++, p4.x, p4.y, 1); generatedVerticesCount += 2; } AlphaVertex::set(aaVertices++, p4.x, p4.y, 1); AlphaVertex::set(aaVertices++, p1.x, p1.y, 1); AlphaVertex::set(aaVertices++, p3.x, p3.y, 0); AlphaVertex::set(aaVertices++, p2.x, p2.y, 0); prevAAVertex = aaVertices - 1; generatedVerticesCount += 4; } dirtyLayer(left, top, right, bottom, *mSnapshot->transform); } } if (generatedVerticesCount > 0) { // GL_LINE does not give the result we want to match Skia glDrawArrays(GL_TRIANGLES, 0, generatedVerticesCount); glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount); } } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); const float strokeWidth = paint->getStrokeWidth() * 0.5f; // A stroke width of 0 has a special meaning in Skia: // it draws a line 1 px wide regardless of current transform bool isHairLine = paint->getStrokeWidth() == 0.0f; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); int generatedVerticesCount = 0; setupDraw(); if (isAA) { setupDrawAALine(); } setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); if (isAA) { setupDrawBlending(true, mode); } else { // TODO: Handle the AA case for (int i = 0; i < count; i += 4) { TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); setupDrawBlending(mode); } setupDrawProgram(); setupDrawModelViewIdentity(); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderIdentityUniforms(); generatedVerticesCount += 2; if (!isHairLine) { drawLinesAsQuads(points, count, isAA, isHairLine, strokeWidth); } else { if (isAA) { drawLinesAsQuads(points, count, isAA, isHairLine, .5f); } else { int verticesCount = count >> 1; Vertex lines[verticesCount]; Vertex* vertices = &lines[0]; setupDrawVertices(vertices); for (int i = 0; i < count; i += 4) { const float left = fmin(points[i], points[i + 2]); const float right = fmax(points[i], points[i + 2]); const float top = fmin(points[i + 1], points[i + 3]); const float bottom = fmax(points[i + 1], points[i + 3]); Vertex::set(vertices++, points[i], points[i + 1]); Vertex::set(vertices++, points[i + 2], points[i + 3]); generatedVerticesCount += 2; dirtyLayer(left, top, right == left ? left + 1 : right, bottom == top ? top + 1 : bottom, *mSnapshot->transform); Loading @@ -1460,6 +1580,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { glDrawArrays(GL_LINES, 0, generatedVerticesCount); } } } void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; Loading
libs/hwui/OpenGLRenderer.h +16 −0 Original line number Diff line number Diff line Loading @@ -282,6 +282,19 @@ private: void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint); /** * Draws a line as a quad. Called by drawLines() for all cases except hairline without AA. * * @param points The vertices of the lines. Every four entries specifies the x/y points * of a single line segment. * @param count The number of entries in the points array. * @param isAA Whether the line is anti-aliased * @param isHairline Whether the line has strokeWidth==0, which results in the line being * one pixel wide on the display regardless of scale. */ void drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline, float strokeWidth); /** * Draws a textured rectangle with the specified texture. The specified coordinates * are transformed by the current snapshot's transform matrix. Loading Loading @@ -425,6 +438,7 @@ private: * Various methods to setup OpenGL rendering. */ void setupDrawWithTexture(bool isAlpha8 = false); void setupDrawAALine(); void setupDrawPoint(float pointSize); void setupDrawColor(int color); void setupDrawColor(int color, int alpha); Loading Loading @@ -453,6 +467,8 @@ private: void setupDrawSimpleMesh(); void setupDrawTexture(GLuint texture); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void setupDrawVertices(GLvoid* vertices); void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth); void finishDrawTexture(); void drawRegionRects(const Region& region); Loading
libs/hwui/ProgramCache.cpp +36 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,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_Distance = "attribute float vtxDistance;\n"; const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; const char* gVS_Header_Uniforms_IsPoint = Loading @@ -56,6 +58,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_HasWidth = "varying float distance;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; const char* gVS_Header_Varyings_PointHasBitmap = Loading Loading @@ -88,6 +92,8 @@ const char* gVS_Main_Position = " gl_Position = transform * position;\n"; const char* gVS_Main_PointSize = " gl_PointSize = pointSize;\n"; const char* gVS_Main_Width = " distance = vtxDistance;\n"; const char* gVS_Footer = "}\n\n"; Loading @@ -101,6 +107,10 @@ const char* gFS_Header = "precision mediump float;\n\n"; const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; const char* gFS_Uniforms_Width = "uniform float width;\n" "uniform float boundaryWidth;\n" "uniform float inverseBoundaryWidth;\n"; const char* gFS_Header_Uniforms_PointHasBitmap = "uniform vec2 textureDimension;\n" "uniform float pointSize;\n"; Loading Loading @@ -169,6 +179,12 @@ const char* gFS_Fast_SingleModulateGradient = // General case const char* gFS_Main_FetchColor = " fragColor = color;\n"; const char* gFS_Main_AccountForWidth = " if (distance < boundaryWidth) {\n" " fragColor *= (distance * inverseBoundaryWidth);\n" " } else if (distance > (1.0 - boundaryWidth)) {\n" " fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n" " }\n"; const char* gFS_Main_FetchTexture[2] = { // Don't modulate " fragColor = texture2D(sampler, outTexCoords);\n", Loading Loading @@ -354,6 +370,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture) { shader.append(gVS_Header_Attributes_TexCoords); } if (description.hasWidth) { shader.append(gVS_Header_Attributes_Distance); } // Uniforms shader.append(gVS_Header_Uniforms); if (description.hasGradient) { Loading @@ -369,6 +388,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasWidth) { shader.append(gVS_Header_Varyings_HasWidth); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } Loading @@ -383,6 +405,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture) { shader.append(gVS_Main_OutTexCoords); } if (description.hasWidth) { shader.append(gVS_Main_Width); } if (description.hasGradient) { shader.append(gVS_Main_OutGradient[description.gradientType]); } Loading Loading @@ -420,6 +445,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasWidth) { shader.append(gVS_Header_Varyings_HasWidth); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } Loading @@ -441,6 +469,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } if (description.hasWidth) { shader.append(gFS_Uniforms_Width); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } Loading @@ -449,8 +480,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Optimization for common cases if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { if (!description.hasWidth && !blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; Loading Loading @@ -534,6 +565,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchColor); } } if (description.hasWidth) { shader.append(gFS_Main_AccountForWidth); } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); } Loading
libs/hwui/ProgramCache.h +6 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ namespace uirenderer { #define PROGRAM_KEY_COLOR_BLEND 0x80 #define PROGRAM_KEY_BITMAP_NPOT 0x100 #define PROGRAM_KEY_SWAP_SRC_DST 0x2000 #define PROGRAM_KEY_VERTEX_WIDTH 0x4000 #define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600 #define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800 Loading Loading @@ -119,6 +120,8 @@ struct ProgramDescription { bool hasBitmap; bool isBitmapNpot; bool hasWidth; bool hasGradient; Gradient gradientType; Loading Loading @@ -148,6 +151,8 @@ struct ProgramDescription { hasTexture = false; hasAlpha8Texture = false; hasWidth = false; modulate = false; hasBitmap = false; Loading Loading @@ -200,6 +205,7 @@ struct ProgramDescription { programid key() const { programid key = 0; if (hasTexture) key |= PROGRAM_KEY_TEXTURE; if (hasWidth) key |= PROGRAM_KEY_VERTEX_WIDTH; if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE; if (hasBitmap) { key |= PROGRAM_KEY_BITMAP; Loading