Loading libs/hwui/Caches.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -294,7 +294,7 @@ private: GLuint mCurrentBuffer; GLuint mCurrentBuffer; GLuint mCurrentIndicesBuffer; GLuint mCurrentIndicesBuffer; void* mCurrentPositionPointer; void* mCurrentPositionPointer; GLuint mCurrentPositionStride; GLsizei mCurrentPositionStride; void* mCurrentTexCoordsPointer; void* mCurrentTexCoordsPointer; bool mTexCoordsArrayEnabled; bool mTexCoordsArrayEnabled; Loading libs/hwui/PathRenderer.cpp +53 −28 Original line number Original line Diff line number Diff line Loading @@ -57,24 +57,34 @@ void computeInverseScales(const mat4 *transform, float &inverseScaleX, float& in float m11 = transform->data[Matrix4::kScaleY]; float m11 = transform->data[Matrix4::kScaleY]; float scaleX = sqrt(m00 * m00 + m01 * m01); float scaleX = sqrt(m00 * m00 + m01 * m01); float scaleY = sqrt(m10 * m10 + m11 * m11); float scaleY = sqrt(m10 * m10 + m11 * m11); inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 0; inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f; inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 0; inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f; } else { } else { inverseScaleX = 1.0f; inverseScaleX = 1.0f; inverseScaleY = 1.0f; inverseScaleY = 1.0f; } } } } inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { { Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); } } inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { { AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); } } /** * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices * will be offset by 1.0 * * Note that we can't add and normalize the two vectors, that would result in a rectangle having an * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1) */ inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); } void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) { void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) { Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size()); Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size()); Loading Loading @@ -108,9 +118,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS current->position[0] - next->position[0]); current->position[0] - next->position[0]); nextNormal.normalize(); nextNormal.normalize(); // offset each point by its normal, out and in, by appropriate stroke offset vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); vec2 totalOffset = (lastNormal + nextNormal); totalOffset.normalize(); if (halfStrokeWidth == 0.0f) { if (halfStrokeWidth == 0.0f) { // hairline - compensate for scale // hairline - compensate for scale totalOffset.x *= 0.5f * inverseScaleX; totalOffset.x *= 0.5f * inverseScaleX; Loading Loading @@ -155,12 +163,11 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe current->position[0] - next->position[0]); current->position[0] - next->position[0]); nextNormal.normalize(); nextNormal.normalize(); // AA point offset from original point is that point's normal, such that // AA point offset from original point is that point's normal, such that each side is offset // each side is offset by .5 pixels // by .5 pixels vec2 totalOffset = (lastNormal + nextNormal); vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); totalOffset.normalize(); totalOffset.x *= 0.5f * inverseScaleX; totalOffset.x *= inverseScaleX * 0.5f; totalOffset.y *= 0.5f * inverseScaleY; totalOffset.y *= inverseScaleY * 0.5f; AlphaVertex::set(&buffer[currentIndex++], AlphaVertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, current->position[0] + totalOffset.x, Loading Loading @@ -204,6 +211,15 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8); AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8); // avoid lines smaller than hairline since they break triangle based sampling. instead reducing // alpha value (TODO: support different X/Y scale) float maxAlpha = 1.0f; if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY && halfStrokeWidth * inverseScaleX < 1.0f) { maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX; halfStrokeWidth = 0.0f; } int offset = 2 * perimeter.size() + 3; int offset = 2 * perimeter.size() + 3; int currentAAOuterIndex = 0; int currentAAOuterIndex = 0; int currentStrokeIndex = offset; int currentStrokeIndex = offset; Loading @@ -220,13 +236,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal current->position[0] - next->position[0]); current->position[0] - next->position[0]); nextNormal.normalize(); nextNormal.normalize(); vec2 pointNormal = (lastNormal + nextNormal); vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); pointNormal.normalize(); vec2 AAOffset = totalOffset; vec2 AAOffset = pointNormal * 0.5f; AAOffset.x *= 0.5f * inverseScaleX; AAOffset.x *= inverseScaleX; AAOffset.y *= 0.5f * inverseScaleY; AAOffset.y *= inverseScaleY; vec2 innerOffset = pointNormal; vec2 innerOffset = totalOffset; if (halfStrokeWidth == 0.0f) { if (halfStrokeWidth == 0.0f) { // hairline! - compensate for scale // hairline! - compensate for scale innerOffset.x *= 0.5f * inverseScaleX; innerOffset.x *= 0.5f * inverseScaleX; Loading @@ -244,27 +259,26 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal AlphaVertex::set(&buffer[currentAAOuterIndex++], AlphaVertex::set(&buffer[currentAAOuterIndex++], current->position[0] + innerOffset.x, current->position[0] + innerOffset.x, current->position[1] + innerOffset.y, current->position[1] + innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentStrokeIndex++], AlphaVertex::set(&buffer[currentStrokeIndex++], current->position[0] + innerOffset.x, current->position[0] + innerOffset.x, current->position[1] + innerOffset.y, current->position[1] + innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentStrokeIndex++], AlphaVertex::set(&buffer[currentStrokeIndex++], current->position[0] - innerOffset.x, current->position[0] - innerOffset.x, current->position[1] - innerOffset.y, current->position[1] - innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentAAInnerIndex++], AlphaVertex::set(&buffer[currentAAInnerIndex++], current->position[0] - innerOffset.x, current->position[0] - innerOffset.x, current->position[1] - innerOffset.y, current->position[1] - innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentAAInnerIndex++], AlphaVertex::set(&buffer[currentAAInnerIndex++], current->position[0] - outerOffset.x, current->position[0] - outerOffset.x, current->position[1] - outerOffset.y, current->position[1] - outerOffset.y, 0.0f); 0.0f); // TODO: current = next, copy last normal instead of recalculate last = current; last = current; current = next; current = next; lastNormal = nextNormal; lastNormal = nextNormal; Loading Loading @@ -295,8 +309,19 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, computeInverseScales(transform, inverseScaleX, inverseScaleY); computeInverseScales(transform, inverseScaleX, inverseScaleY); Vector<Vertex> tempVertices; Vector<Vertex> tempVertices; convexPathPerimeterVertices(path, inverseScaleX * inverseScaleX, inverseScaleY * inverseScaleY, float threshInvScaleX = inverseScaleX; tempVertices); float threshInvScaleY = inverseScaleY; if (style == SkPaint::kStroke_Style) { // alter the bezier recursion threshold values we calculate in order to compensate for // expansion done after the path vertices are found SkRect bounds = path.getBounds(); if (!bounds.isEmpty()) { threshInvScaleX *= bounds.width() / (bounds.width() + paint->getStrokeWidth()); threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth()); } } convexPathPerimeterVertices(path, threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY, tempVertices); #if VERTEX_DEBUG #if VERTEX_DEBUG for (unsigned int i = 0; i < tempVertices.size(); i++) { for (unsigned int i = 0; i < tempVertices.size(); i++) { Loading Loading
libs/hwui/Caches.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -294,7 +294,7 @@ private: GLuint mCurrentBuffer; GLuint mCurrentBuffer; GLuint mCurrentIndicesBuffer; GLuint mCurrentIndicesBuffer; void* mCurrentPositionPointer; void* mCurrentPositionPointer; GLuint mCurrentPositionStride; GLsizei mCurrentPositionStride; void* mCurrentTexCoordsPointer; void* mCurrentTexCoordsPointer; bool mTexCoordsArrayEnabled; bool mTexCoordsArrayEnabled; Loading
libs/hwui/PathRenderer.cpp +53 −28 Original line number Original line Diff line number Diff line Loading @@ -57,24 +57,34 @@ void computeInverseScales(const mat4 *transform, float &inverseScaleX, float& in float m11 = transform->data[Matrix4::kScaleY]; float m11 = transform->data[Matrix4::kScaleY]; float scaleX = sqrt(m00 * m00 + m01 * m01); float scaleX = sqrt(m00 * m00 + m01 * m01); float scaleY = sqrt(m10 * m10 + m11 * m11); float scaleY = sqrt(m10 * m10 + m11 * m11); inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 0; inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f; inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 0; inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f; } else { } else { inverseScaleX = 1.0f; inverseScaleX = 1.0f; inverseScaleY = 1.0f; inverseScaleY = 1.0f; } } } } inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { { Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); } } inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { { AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); } } /** * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices * will be offset by 1.0 * * Note that we can't add and normalize the two vectors, that would result in a rectangle having an * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1) */ inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); } void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) { void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) { Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size()); Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size()); Loading Loading @@ -108,9 +118,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS current->position[0] - next->position[0]); current->position[0] - next->position[0]); nextNormal.normalize(); nextNormal.normalize(); // offset each point by its normal, out and in, by appropriate stroke offset vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); vec2 totalOffset = (lastNormal + nextNormal); totalOffset.normalize(); if (halfStrokeWidth == 0.0f) { if (halfStrokeWidth == 0.0f) { // hairline - compensate for scale // hairline - compensate for scale totalOffset.x *= 0.5f * inverseScaleX; totalOffset.x *= 0.5f * inverseScaleX; Loading Loading @@ -155,12 +163,11 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe current->position[0] - next->position[0]); current->position[0] - next->position[0]); nextNormal.normalize(); nextNormal.normalize(); // AA point offset from original point is that point's normal, such that // AA point offset from original point is that point's normal, such that each side is offset // each side is offset by .5 pixels // by .5 pixels vec2 totalOffset = (lastNormal + nextNormal); vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); totalOffset.normalize(); totalOffset.x *= 0.5f * inverseScaleX; totalOffset.x *= inverseScaleX * 0.5f; totalOffset.y *= 0.5f * inverseScaleY; totalOffset.y *= inverseScaleY * 0.5f; AlphaVertex::set(&buffer[currentIndex++], AlphaVertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, current->position[0] + totalOffset.x, Loading Loading @@ -204,6 +211,15 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8); AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8); // avoid lines smaller than hairline since they break triangle based sampling. instead reducing // alpha value (TODO: support different X/Y scale) float maxAlpha = 1.0f; if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY && halfStrokeWidth * inverseScaleX < 1.0f) { maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX; halfStrokeWidth = 0.0f; } int offset = 2 * perimeter.size() + 3; int offset = 2 * perimeter.size() + 3; int currentAAOuterIndex = 0; int currentAAOuterIndex = 0; int currentStrokeIndex = offset; int currentStrokeIndex = offset; Loading @@ -220,13 +236,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal current->position[0] - next->position[0]); current->position[0] - next->position[0]); nextNormal.normalize(); nextNormal.normalize(); vec2 pointNormal = (lastNormal + nextNormal); vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); pointNormal.normalize(); vec2 AAOffset = totalOffset; vec2 AAOffset = pointNormal * 0.5f; AAOffset.x *= 0.5f * inverseScaleX; AAOffset.x *= inverseScaleX; AAOffset.y *= 0.5f * inverseScaleY; AAOffset.y *= inverseScaleY; vec2 innerOffset = pointNormal; vec2 innerOffset = totalOffset; if (halfStrokeWidth == 0.0f) { if (halfStrokeWidth == 0.0f) { // hairline! - compensate for scale // hairline! - compensate for scale innerOffset.x *= 0.5f * inverseScaleX; innerOffset.x *= 0.5f * inverseScaleX; Loading @@ -244,27 +259,26 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal AlphaVertex::set(&buffer[currentAAOuterIndex++], AlphaVertex::set(&buffer[currentAAOuterIndex++], current->position[0] + innerOffset.x, current->position[0] + innerOffset.x, current->position[1] + innerOffset.y, current->position[1] + innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentStrokeIndex++], AlphaVertex::set(&buffer[currentStrokeIndex++], current->position[0] + innerOffset.x, current->position[0] + innerOffset.x, current->position[1] + innerOffset.y, current->position[1] + innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentStrokeIndex++], AlphaVertex::set(&buffer[currentStrokeIndex++], current->position[0] - innerOffset.x, current->position[0] - innerOffset.x, current->position[1] - innerOffset.y, current->position[1] - innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentAAInnerIndex++], AlphaVertex::set(&buffer[currentAAInnerIndex++], current->position[0] - innerOffset.x, current->position[0] - innerOffset.x, current->position[1] - innerOffset.y, current->position[1] - innerOffset.y, 1.0f); maxAlpha); AlphaVertex::set(&buffer[currentAAInnerIndex++], AlphaVertex::set(&buffer[currentAAInnerIndex++], current->position[0] - outerOffset.x, current->position[0] - outerOffset.x, current->position[1] - outerOffset.y, current->position[1] - outerOffset.y, 0.0f); 0.0f); // TODO: current = next, copy last normal instead of recalculate last = current; last = current; current = next; current = next; lastNormal = nextNormal; lastNormal = nextNormal; Loading Loading @@ -295,8 +309,19 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, computeInverseScales(transform, inverseScaleX, inverseScaleY); computeInverseScales(transform, inverseScaleX, inverseScaleY); Vector<Vertex> tempVertices; Vector<Vertex> tempVertices; convexPathPerimeterVertices(path, inverseScaleX * inverseScaleX, inverseScaleY * inverseScaleY, float threshInvScaleX = inverseScaleX; tempVertices); float threshInvScaleY = inverseScaleY; if (style == SkPaint::kStroke_Style) { // alter the bezier recursion threshold values we calculate in order to compensate for // expansion done after the path vertices are found SkRect bounds = path.getBounds(); if (!bounds.isEmpty()) { threshInvScaleX *= bounds.width() / (bounds.width() + paint->getStrokeWidth()); threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth()); } } convexPathPerimeterVertices(path, threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY, tempVertices); #if VERTEX_DEBUG #if VERTEX_DEBUG for (unsigned int i = 0; i < tempVertices.size(); i++) { for (unsigned int i = 0; i < tempVertices.size(); i++) { Loading