Loading libs/hwui/OpenGLRenderer.cpp +12 −65 Original line number Diff line number Diff line Loading @@ -1703,11 +1703,6 @@ void OpenGLRenderer::setupDrawAA() { mDescription.isAA = true; } void OpenGLRenderer::setupDrawPoint(float pointSize) { mDescription.isPoint = true; mDescription.pointSize = pointSize; } void OpenGLRenderer::setupDrawColor(int color, int alpha) { mColorA = alpha / 255.0f; mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; Loading Loading @@ -1822,11 +1817,6 @@ void OpenGLRenderer::setupDrawModelView(float left, float top, float right, floa } } void OpenGLRenderer::setupDrawPointUniforms() { int slot = mCaches.currentProgram->getUniform("pointSize"); glUniform1f(slot, mDescription.pointSize); } void OpenGLRenderer::setupDrawColorUniforms() { if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) { mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); Loading Loading @@ -2409,7 +2399,7 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint, bool useOffset) { if (!vertexBuffer.getSize()) { if (!vertexBuffer.getVertexCount()) { // no vertices to draw return DrawGlInfo::kStatusDone; } Loading Loading @@ -2447,7 +2437,7 @@ status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPa glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords); } glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize()); glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount()); if (isAA) { glDisableVertexAttribArray(alphaSlot); Loading Loading @@ -2510,65 +2500,22 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; // TODO: The paint's cap style defines whether the points are square or circular // TODO: Handle AA for round points // A stroke width of 0 has a special meaning in Skia: // it draws an unscaled 1px point float strokeWidth = paint->getStrokeWidth(); const bool isHairLine = paint->getStrokeWidth() == 0.0f; if (isHairLine) { // Now that we know it's hairline, we can set the effective width, to be used later strokeWidth = 1.0f; } const float halfWidth = strokeWidth / 2; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); if (mSnapshot->isIgnored() || count < 2) return DrawGlInfo::kStatusDone; int verticesCount = count >> 1; int generatedVerticesCount = 0; count &= ~0x1; // round down to nearest two TextureVertex pointsData[verticesCount]; TextureVertex* vertex = &pointsData[0]; // TODO: We should optimize this method to not generate vertices for points // that lie outside of the clip. mCaches.enableScissor(); setupDraw(); setupDrawNoTexture(); setupDrawPoint(strokeWidth); setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); setupDrawBlending(mode); setupDrawProgram(); setupDrawModelViewIdentity(true); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawPointUniforms(); setupDrawShaderIdentityUniforms(); setupDrawMesh(vertex); for (int i = 0; i < count; i += 2) { TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); generatedVerticesCount++; float left = points[i] - halfWidth; float right = points[i] + halfWidth; float top = points[i + 1] - halfWidth; float bottom = points [i + 1] + halfWidth; VertexBuffer buffer; SkRect bounds; PathTessellator::tessellatePoints(points, count, paint, mSnapshot->transform, bounds, buffer); dirtyLayer(left, top, right, bottom, currentTransform()); if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) { return DrawGlInfo::kStatusDone; } glDrawArrays(GL_POINTS, 0, generatedVerticesCount); dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform()); return DrawGlInfo::kStatusDrew; bool useOffset = !paint->isAntiAlias(); return drawVertexBuffer(buffer, paint, useOffset); } status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { Loading libs/hwui/OpenGLRenderer.h +0 −2 Original line number Diff line number Diff line Loading @@ -927,7 +927,6 @@ private: void setupDrawWithExternalTexture(); void setupDrawNoTexture(); void setupDrawAA(); void setupDrawPoint(float pointSize); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); Loading @@ -945,7 +944,6 @@ private: bool ignoreTransform = false, bool ignoreModelView = false); void setupDrawModelViewTranslate(float left, float top, float right, float bottom, bool ignoreTransform = false); void setupDrawPointUniforms(); void setupDrawColorUniforms(); void setupDrawPureColorUniforms(); void setupDrawShaderIdentityUniforms(); Loading libs/hwui/PathTessellator.cpp +101 −44 Original line number Diff line number Diff line Loading @@ -66,11 +66,11 @@ void PathTessellator::expandBoundsForStroke(SkRect& bounds, const SkPaint* paint } } inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { inline static void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); } inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { inline static void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); } Loading @@ -84,7 +84,7 @@ inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { * * NOTE: assumes angles between normals 90 degrees or less */ inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { inline static vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); } Loading Loading @@ -224,6 +224,20 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector<Ver DEBUG_DUMP_BUFFER(); } static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center, const vec2& normal, Vertex* buffer, int& currentIndex, bool begin) { vec2 strokeOffset = normal; paintInfo.scaleOffsetForStrokeWidth(strokeOffset); vec2 referencePoint(center.position[0], center.position[1]); if (paintInfo.cap == SkPaint::kSquare_Cap) { referencePoint += vec2(-strokeOffset.y, strokeOffset.x) * (begin ? -1 : 1); } Vertex::set(&buffer[currentIndex++], referencePoint + strokeOffset); Vertex::set(&buffer[currentIndex++], referencePoint - strokeOffset); } /** * Fills a vertexBuffer with non-alpha vertices similar to getStrokeVerticesFromPerimeter, except: * Loading @@ -235,19 +249,17 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, VertexBuffer& vertexBuffer) { const int extra = paintInfo.capExtraDivisions(); const int allocSize = (vertices.size() + extra) * 2; Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize); const int lastIndex = vertices.size() - 1; if (extra > 0) { // tessellate both round caps const int last = vertices.size() - 1; float beginTheta = atan2( - (vertices[0].position[0] - vertices[1].position[0]), vertices[0].position[1] - vertices[1].position[1]); float endTheta = atan2( - (vertices[last].position[0] - vertices[last - 1].position[0]), vertices[last].position[1] - vertices[last - 1].position[1]); - (vertices[lastIndex].position[0] - vertices[lastIndex - 1].position[0]), vertices[lastIndex].position[1] - vertices[lastIndex - 1].position[1]); const float dTheta = PI / (extra + 1); const float radialScale = 2.0f / (1 + cos(dTheta)); Loading @@ -270,49 +282,38 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, vec2 endRadialOffset(cos(endTheta), sin(endTheta)); paintInfo.scaleOffsetForStrokeWidth(endRadialOffset); Vertex::set(&buffer[allocSize - 1 - capOffset], vertices[last].position[0] + endRadialOffset.x, vertices[last].position[1] + endRadialOffset.y); vertices[lastIndex].position[0] + endRadialOffset.x, vertices[lastIndex].position[1] + endRadialOffset.y); } } int currentIndex = extra; const Vertex* current = &(vertices[0]); vec2 lastNormal; for (unsigned int i = 0; i < vertices.size() - 1; i++) { const Vertex* last = &(vertices[0]); const Vertex* current = &(vertices[1]); vec2 lastNormal(current->position[1] - last->position[1], last->position[0] - current->position[0]); lastNormal.normalize(); storeBeginEnd(paintInfo, vertices[0], lastNormal, buffer, currentIndex, true); for (unsigned int i = 1; i < vertices.size() - 1; i++) { const Vertex* next = &(vertices[i + 1]); vec2 nextNormal(next->position[1] - current->position[1], current->position[0] - next->position[0]); nextNormal.normalize(); vec2 totalOffset; if (i == 0) { totalOffset = nextNormal; } else { totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); } paintInfo.scaleOffsetForStrokeWidth(totalOffset); Vertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, current->position[1] + totalOffset.y); vec2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal); paintInfo.scaleOffsetForStrokeWidth(strokeOffset); Vertex::set(&buffer[currentIndex++], current->position[0] - totalOffset.x, current->position[1] - totalOffset.y); vec2 center(current->position[0], current->position[1]); Vertex::set(&buffer[currentIndex++], center + strokeOffset); Vertex::set(&buffer[currentIndex++], center - strokeOffset); current = next; lastNormal = nextNormal; } vec2 totalOffset = lastNormal; paintInfo.scaleOffsetForStrokeWidth(totalOffset); Vertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, current->position[1] + totalOffset.y); Vertex::set(&buffer[currentIndex++], current->position[0] - totalOffset.x, current->position[1] - totalOffset.y); storeBeginEnd(paintInfo, vertices[lastIndex], lastNormal, buffer, currentIndex, false); DEBUG_DUMP_BUFFER(); } Loading Loading @@ -389,7 +390,7 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Ver * For explanation of constants and general methodoloyg, see comments for * getStrokeVerticesFromUnclosedVerticesAA() below. */ inline void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, AlphaVertex* buffer, bool isFirst, vec2 normal, int offset) { const int extra = paintInfo.capExtraDivisions(); const int extraOffset = (extra + 1) / 2; Loading Loading @@ -772,11 +773,67 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint, } } static void expandRectToCoverVertex(SkRect& rect, float x, float y) { rect.fLeft = fminf(rect.fLeft, x); rect.fTop = fminf(rect.fTop, y); rect.fRight = fmaxf(rect.fRight, x); rect.fBottom = fmaxf(rect.fBottom, y); } static void expandRectToCoverVertex(SkRect& rect, const Vertex& vertex) { rect.fLeft = fminf(rect.fLeft, vertex.position[0]); rect.fTop = fminf(rect.fTop, vertex.position[1]); rect.fRight = fmaxf(rect.fRight, vertex.position[0]); rect.fBottom = fmaxf(rect.fBottom, vertex.position[1]); expandRectToCoverVertex(rect, vertex.position[0], vertex.position[1]); } template <class TYPE> static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer, const float* points, int count, SkRect& bounds) { bounds.set(points[0], points[1], points[0], points[1]); int numPoints = count / 2; int verticesPerPoint = srcBuffer.getVertexCount(); dstBuffer.alloc<TYPE>(numPoints * verticesPerPoint + (numPoints - 1) * 2); for (int i = 0; i < count; i += 2) { expandRectToCoverVertex(bounds, points[i + 0], points[i + 1]); dstBuffer.copyInto<TYPE>(srcBuffer, points[i + 0], points[i + 1]); } dstBuffer.createDegenerateSeparators<TYPE>(verticesPerPoint); } void PathTessellator::tessellatePoints(const float* points, int count, SkPaint* paint, const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer) { const PaintInfo paintInfo(paint, transform); // determine point shape SkPath path; float radius = paintInfo.halfStrokeWidth; if (radius == 0.0f) radius = 0.25f; if (paintInfo.cap == SkPaint::kRound_Cap) { path.addCircle(0, 0, radius); } else { path.addRect(-radius, -radius, radius, radius); } // calculate outline Vector<Vertex> outlineVertices; approximatePathOutlineVertices(path, true, paintInfo.inverseScaleX * paintInfo.inverseScaleX, paintInfo.inverseScaleY * paintInfo.inverseScaleY, outlineVertices); if (!outlineVertices.size()) return; // tessellate, then duplicate outline across points int numPoints = count / 2; VertexBuffer tempBuffer; if (!paintInfo.isAA) { getFillVerticesFromPerimeter(outlineVertices, tempBuffer); instanceVertices<Vertex>(tempBuffer, vertexBuffer, points, count, bounds); } else { getFillVerticesFromPerimeterAA(paintInfo, outlineVertices, tempBuffer); instanceVertices<AlphaVertex>(tempBuffer, vertexBuffer, points, count, bounds); } expandBoundsForStroke(bounds, paint, true); // force-expand bounds to incorporate stroke } void PathTessellator::tessellateLines(const float* points, int count, SkPaint* paint, Loading libs/hwui/PathTessellator.h +25 −10 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ class VertexBuffer { public: VertexBuffer(): mBuffer(0), mSize(0), mVertexCount(0), mCleanupMethod(NULL) {} Loading @@ -44,30 +44,42 @@ public: multiple regions within a single VertexBuffer, such as with PathTessellator::tesselateLines() */ template <class TYPE> TYPE* alloc(int size) { if (mSize) { TYPE* alloc(int vertexCount) { if (mVertexCount) { TYPE* reallocBuffer = (TYPE*)mReallocBuffer; // already have allocated the buffer, re-allocate space within if (mReallocBuffer != mBuffer) { // not first re-allocation, leave space for degenerate triangles to separate strips reallocBuffer += 2; } mReallocBuffer = reallocBuffer + size; mReallocBuffer = reallocBuffer + vertexCount; return reallocBuffer; } mSize = size; mReallocBuffer = mBuffer = (void*)new TYPE[size]; mVertexCount = vertexCount; mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount]; mCleanupMethod = &(cleanup<TYPE>); return (TYPE*)mBuffer; } void* getBuffer() const { return mBuffer; } unsigned int getSize() const { return mSize; } template <class TYPE> void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) { int verticesToCopy = srcBuffer.getVertexCount(); TYPE* dst = alloc<TYPE>(verticesToCopy); TYPE* src = (TYPE*)srcBuffer.getBuffer(); for (int i = 0; i < verticesToCopy; i++) { TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset); } } void* getBuffer() const { return mBuffer; } // shouldn't be const, since not a const ptr? unsigned int getVertexCount() const { return mVertexCount; } template <class TYPE> void createDegenerateSeparators(int allocSize) { TYPE* end = (TYPE*)mBuffer + mSize; TYPE* end = (TYPE*)mBuffer + mVertexCount; for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) { memcpy(degen, degen - 1, sizeof(TYPE)); memcpy(degen + 1, degen + 2, sizeof(TYPE)); Loading @@ -81,7 +93,7 @@ private: } void* mBuffer; unsigned int mSize; unsigned int mVertexCount; void* mReallocBuffer; // used for multi-allocation Loading @@ -95,6 +107,9 @@ public: static void tessellatePath(const SkPath& path, const SkPaint* paint, const mat4 *transform, VertexBuffer& vertexBuffer); static void tessellatePoints(const float* points, int count, SkPaint* paint, const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer); static void tessellateLines(const float* points, int count, SkPaint* paint, const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer); Loading libs/hwui/Program.h +9 −18 Original line number Diff line number Diff line Loading @@ -68,24 +68,22 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPS_SHIFT 9 #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type #define PROGRAM_MODULATE_SHIFT 35 #define PROGRAM_IS_POINT_SHIFT 36 #define PROGRAM_HAS_AA_SHIFT 36 #define PROGRAM_HAS_AA_SHIFT 37 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 37 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 38 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 #define PROGRAM_HAS_GAMMA_CORRECTION 39 #define PROGRAM_HAS_GAMMA_CORRECTION 40 #define PROGRAM_IS_SIMPLE_GRADIENT 40 #define PROGRAM_IS_SIMPLE_GRADIENT 41 #define PROGRAM_HAS_COLORS 41 #define PROGRAM_HAS_COLORS 42 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 43 #define PROGRAM_EMULATE_STENCIL 44 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 42 #define PROGRAM_EMULATE_STENCIL 43 /////////////////////////////////////////////////////////////////////////////// // Types Loading Loading @@ -157,9 +155,6 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; bool isPoint; float pointSize; bool hasGammaCorrection; float gamma; Loading Loading @@ -201,9 +196,6 @@ struct ProgramDescription { framebufferMode = SkXfermode::kClear_Mode; swapSrcDst = false; isPoint = false; pointSize = 0.0f; hasGammaCorrection = false; gamma = 2.2f; Loading Loading @@ -269,7 +261,6 @@ struct ProgramDescription { key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; Loading Loading
libs/hwui/OpenGLRenderer.cpp +12 −65 Original line number Diff line number Diff line Loading @@ -1703,11 +1703,6 @@ void OpenGLRenderer::setupDrawAA() { mDescription.isAA = true; } void OpenGLRenderer::setupDrawPoint(float pointSize) { mDescription.isPoint = true; mDescription.pointSize = pointSize; } void OpenGLRenderer::setupDrawColor(int color, int alpha) { mColorA = alpha / 255.0f; mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; Loading Loading @@ -1822,11 +1817,6 @@ void OpenGLRenderer::setupDrawModelView(float left, float top, float right, floa } } void OpenGLRenderer::setupDrawPointUniforms() { int slot = mCaches.currentProgram->getUniform("pointSize"); glUniform1f(slot, mDescription.pointSize); } void OpenGLRenderer::setupDrawColorUniforms() { if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) { mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); Loading Loading @@ -2409,7 +2399,7 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint, bool useOffset) { if (!vertexBuffer.getSize()) { if (!vertexBuffer.getVertexCount()) { // no vertices to draw return DrawGlInfo::kStatusDone; } Loading Loading @@ -2447,7 +2437,7 @@ status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPa glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords); } glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize()); glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount()); if (isAA) { glDisableVertexAttribArray(alphaSlot); Loading Loading @@ -2510,65 +2500,22 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; // TODO: The paint's cap style defines whether the points are square or circular // TODO: Handle AA for round points // A stroke width of 0 has a special meaning in Skia: // it draws an unscaled 1px point float strokeWidth = paint->getStrokeWidth(); const bool isHairLine = paint->getStrokeWidth() == 0.0f; if (isHairLine) { // Now that we know it's hairline, we can set the effective width, to be used later strokeWidth = 1.0f; } const float halfWidth = strokeWidth / 2; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); if (mSnapshot->isIgnored() || count < 2) return DrawGlInfo::kStatusDone; int verticesCount = count >> 1; int generatedVerticesCount = 0; count &= ~0x1; // round down to nearest two TextureVertex pointsData[verticesCount]; TextureVertex* vertex = &pointsData[0]; // TODO: We should optimize this method to not generate vertices for points // that lie outside of the clip. mCaches.enableScissor(); setupDraw(); setupDrawNoTexture(); setupDrawPoint(strokeWidth); setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); setupDrawBlending(mode); setupDrawProgram(); setupDrawModelViewIdentity(true); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawPointUniforms(); setupDrawShaderIdentityUniforms(); setupDrawMesh(vertex); for (int i = 0; i < count; i += 2) { TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); generatedVerticesCount++; float left = points[i] - halfWidth; float right = points[i] + halfWidth; float top = points[i + 1] - halfWidth; float bottom = points [i + 1] + halfWidth; VertexBuffer buffer; SkRect bounds; PathTessellator::tessellatePoints(points, count, paint, mSnapshot->transform, bounds, buffer); dirtyLayer(left, top, right, bottom, currentTransform()); if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) { return DrawGlInfo::kStatusDone; } glDrawArrays(GL_POINTS, 0, generatedVerticesCount); dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform()); return DrawGlInfo::kStatusDrew; bool useOffset = !paint->isAntiAlias(); return drawVertexBuffer(buffer, paint, useOffset); } status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { Loading
libs/hwui/OpenGLRenderer.h +0 −2 Original line number Diff line number Diff line Loading @@ -927,7 +927,6 @@ private: void setupDrawWithExternalTexture(); void setupDrawNoTexture(); void setupDrawAA(); void setupDrawPoint(float pointSize); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); Loading @@ -945,7 +944,6 @@ private: bool ignoreTransform = false, bool ignoreModelView = false); void setupDrawModelViewTranslate(float left, float top, float right, float bottom, bool ignoreTransform = false); void setupDrawPointUniforms(); void setupDrawColorUniforms(); void setupDrawPureColorUniforms(); void setupDrawShaderIdentityUniforms(); Loading
libs/hwui/PathTessellator.cpp +101 −44 Original line number Diff line number Diff line Loading @@ -66,11 +66,11 @@ void PathTessellator::expandBoundsForStroke(SkRect& bounds, const SkPaint* paint } } inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { inline static void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); } inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { inline static void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); } Loading @@ -84,7 +84,7 @@ inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { * * NOTE: assumes angles between normals 90 degrees or less */ inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { inline static vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); } Loading Loading @@ -224,6 +224,20 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector<Ver DEBUG_DUMP_BUFFER(); } static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center, const vec2& normal, Vertex* buffer, int& currentIndex, bool begin) { vec2 strokeOffset = normal; paintInfo.scaleOffsetForStrokeWidth(strokeOffset); vec2 referencePoint(center.position[0], center.position[1]); if (paintInfo.cap == SkPaint::kSquare_Cap) { referencePoint += vec2(-strokeOffset.y, strokeOffset.x) * (begin ? -1 : 1); } Vertex::set(&buffer[currentIndex++], referencePoint + strokeOffset); Vertex::set(&buffer[currentIndex++], referencePoint - strokeOffset); } /** * Fills a vertexBuffer with non-alpha vertices similar to getStrokeVerticesFromPerimeter, except: * Loading @@ -235,19 +249,17 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, VertexBuffer& vertexBuffer) { const int extra = paintInfo.capExtraDivisions(); const int allocSize = (vertices.size() + extra) * 2; Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize); const int lastIndex = vertices.size() - 1; if (extra > 0) { // tessellate both round caps const int last = vertices.size() - 1; float beginTheta = atan2( - (vertices[0].position[0] - vertices[1].position[0]), vertices[0].position[1] - vertices[1].position[1]); float endTheta = atan2( - (vertices[last].position[0] - vertices[last - 1].position[0]), vertices[last].position[1] - vertices[last - 1].position[1]); - (vertices[lastIndex].position[0] - vertices[lastIndex - 1].position[0]), vertices[lastIndex].position[1] - vertices[lastIndex - 1].position[1]); const float dTheta = PI / (extra + 1); const float radialScale = 2.0f / (1 + cos(dTheta)); Loading @@ -270,49 +282,38 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, vec2 endRadialOffset(cos(endTheta), sin(endTheta)); paintInfo.scaleOffsetForStrokeWidth(endRadialOffset); Vertex::set(&buffer[allocSize - 1 - capOffset], vertices[last].position[0] + endRadialOffset.x, vertices[last].position[1] + endRadialOffset.y); vertices[lastIndex].position[0] + endRadialOffset.x, vertices[lastIndex].position[1] + endRadialOffset.y); } } int currentIndex = extra; const Vertex* current = &(vertices[0]); vec2 lastNormal; for (unsigned int i = 0; i < vertices.size() - 1; i++) { const Vertex* last = &(vertices[0]); const Vertex* current = &(vertices[1]); vec2 lastNormal(current->position[1] - last->position[1], last->position[0] - current->position[0]); lastNormal.normalize(); storeBeginEnd(paintInfo, vertices[0], lastNormal, buffer, currentIndex, true); for (unsigned int i = 1; i < vertices.size() - 1; i++) { const Vertex* next = &(vertices[i + 1]); vec2 nextNormal(next->position[1] - current->position[1], current->position[0] - next->position[0]); nextNormal.normalize(); vec2 totalOffset; if (i == 0) { totalOffset = nextNormal; } else { totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); } paintInfo.scaleOffsetForStrokeWidth(totalOffset); Vertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, current->position[1] + totalOffset.y); vec2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal); paintInfo.scaleOffsetForStrokeWidth(strokeOffset); Vertex::set(&buffer[currentIndex++], current->position[0] - totalOffset.x, current->position[1] - totalOffset.y); vec2 center(current->position[0], current->position[1]); Vertex::set(&buffer[currentIndex++], center + strokeOffset); Vertex::set(&buffer[currentIndex++], center - strokeOffset); current = next; lastNormal = nextNormal; } vec2 totalOffset = lastNormal; paintInfo.scaleOffsetForStrokeWidth(totalOffset); Vertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, current->position[1] + totalOffset.y); Vertex::set(&buffer[currentIndex++], current->position[0] - totalOffset.x, current->position[1] - totalOffset.y); storeBeginEnd(paintInfo, vertices[lastIndex], lastNormal, buffer, currentIndex, false); DEBUG_DUMP_BUFFER(); } Loading Loading @@ -389,7 +390,7 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Ver * For explanation of constants and general methodoloyg, see comments for * getStrokeVerticesFromUnclosedVerticesAA() below. */ inline void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, inline static void storeCapAA(const PaintInfo& paintInfo, const Vector<Vertex>& vertices, AlphaVertex* buffer, bool isFirst, vec2 normal, int offset) { const int extra = paintInfo.capExtraDivisions(); const int extraOffset = (extra + 1) / 2; Loading Loading @@ -772,11 +773,67 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint, } } static void expandRectToCoverVertex(SkRect& rect, float x, float y) { rect.fLeft = fminf(rect.fLeft, x); rect.fTop = fminf(rect.fTop, y); rect.fRight = fmaxf(rect.fRight, x); rect.fBottom = fmaxf(rect.fBottom, y); } static void expandRectToCoverVertex(SkRect& rect, const Vertex& vertex) { rect.fLeft = fminf(rect.fLeft, vertex.position[0]); rect.fTop = fminf(rect.fTop, vertex.position[1]); rect.fRight = fmaxf(rect.fRight, vertex.position[0]); rect.fBottom = fmaxf(rect.fBottom, vertex.position[1]); expandRectToCoverVertex(rect, vertex.position[0], vertex.position[1]); } template <class TYPE> static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer, const float* points, int count, SkRect& bounds) { bounds.set(points[0], points[1], points[0], points[1]); int numPoints = count / 2; int verticesPerPoint = srcBuffer.getVertexCount(); dstBuffer.alloc<TYPE>(numPoints * verticesPerPoint + (numPoints - 1) * 2); for (int i = 0; i < count; i += 2) { expandRectToCoverVertex(bounds, points[i + 0], points[i + 1]); dstBuffer.copyInto<TYPE>(srcBuffer, points[i + 0], points[i + 1]); } dstBuffer.createDegenerateSeparators<TYPE>(verticesPerPoint); } void PathTessellator::tessellatePoints(const float* points, int count, SkPaint* paint, const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer) { const PaintInfo paintInfo(paint, transform); // determine point shape SkPath path; float radius = paintInfo.halfStrokeWidth; if (radius == 0.0f) radius = 0.25f; if (paintInfo.cap == SkPaint::kRound_Cap) { path.addCircle(0, 0, radius); } else { path.addRect(-radius, -radius, radius, radius); } // calculate outline Vector<Vertex> outlineVertices; approximatePathOutlineVertices(path, true, paintInfo.inverseScaleX * paintInfo.inverseScaleX, paintInfo.inverseScaleY * paintInfo.inverseScaleY, outlineVertices); if (!outlineVertices.size()) return; // tessellate, then duplicate outline across points int numPoints = count / 2; VertexBuffer tempBuffer; if (!paintInfo.isAA) { getFillVerticesFromPerimeter(outlineVertices, tempBuffer); instanceVertices<Vertex>(tempBuffer, vertexBuffer, points, count, bounds); } else { getFillVerticesFromPerimeterAA(paintInfo, outlineVertices, tempBuffer); instanceVertices<AlphaVertex>(tempBuffer, vertexBuffer, points, count, bounds); } expandBoundsForStroke(bounds, paint, true); // force-expand bounds to incorporate stroke } void PathTessellator::tessellateLines(const float* points, int count, SkPaint* paint, Loading
libs/hwui/PathTessellator.h +25 −10 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ class VertexBuffer { public: VertexBuffer(): mBuffer(0), mSize(0), mVertexCount(0), mCleanupMethod(NULL) {} Loading @@ -44,30 +44,42 @@ public: multiple regions within a single VertexBuffer, such as with PathTessellator::tesselateLines() */ template <class TYPE> TYPE* alloc(int size) { if (mSize) { TYPE* alloc(int vertexCount) { if (mVertexCount) { TYPE* reallocBuffer = (TYPE*)mReallocBuffer; // already have allocated the buffer, re-allocate space within if (mReallocBuffer != mBuffer) { // not first re-allocation, leave space for degenerate triangles to separate strips reallocBuffer += 2; } mReallocBuffer = reallocBuffer + size; mReallocBuffer = reallocBuffer + vertexCount; return reallocBuffer; } mSize = size; mReallocBuffer = mBuffer = (void*)new TYPE[size]; mVertexCount = vertexCount; mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount]; mCleanupMethod = &(cleanup<TYPE>); return (TYPE*)mBuffer; } void* getBuffer() const { return mBuffer; } unsigned int getSize() const { return mSize; } template <class TYPE> void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) { int verticesToCopy = srcBuffer.getVertexCount(); TYPE* dst = alloc<TYPE>(verticesToCopy); TYPE* src = (TYPE*)srcBuffer.getBuffer(); for (int i = 0; i < verticesToCopy; i++) { TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset); } } void* getBuffer() const { return mBuffer; } // shouldn't be const, since not a const ptr? unsigned int getVertexCount() const { return mVertexCount; } template <class TYPE> void createDegenerateSeparators(int allocSize) { TYPE* end = (TYPE*)mBuffer + mSize; TYPE* end = (TYPE*)mBuffer + mVertexCount; for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) { memcpy(degen, degen - 1, sizeof(TYPE)); memcpy(degen + 1, degen + 2, sizeof(TYPE)); Loading @@ -81,7 +93,7 @@ private: } void* mBuffer; unsigned int mSize; unsigned int mVertexCount; void* mReallocBuffer; // used for multi-allocation Loading @@ -95,6 +107,9 @@ public: static void tessellatePath(const SkPath& path, const SkPaint* paint, const mat4 *transform, VertexBuffer& vertexBuffer); static void tessellatePoints(const float* points, int count, SkPaint* paint, const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer); static void tessellateLines(const float* points, int count, SkPaint* paint, const mat4* transform, SkRect& bounds, VertexBuffer& vertexBuffer); Loading
libs/hwui/Program.h +9 −18 Original line number Diff line number Diff line Loading @@ -68,24 +68,22 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPS_SHIFT 9 #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type #define PROGRAM_MODULATE_SHIFT 35 #define PROGRAM_IS_POINT_SHIFT 36 #define PROGRAM_HAS_AA_SHIFT 36 #define PROGRAM_HAS_AA_SHIFT 37 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 37 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 38 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 #define PROGRAM_HAS_GAMMA_CORRECTION 39 #define PROGRAM_HAS_GAMMA_CORRECTION 40 #define PROGRAM_IS_SIMPLE_GRADIENT 40 #define PROGRAM_IS_SIMPLE_GRADIENT 41 #define PROGRAM_HAS_COLORS 41 #define PROGRAM_HAS_COLORS 42 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 43 #define PROGRAM_EMULATE_STENCIL 44 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 42 #define PROGRAM_EMULATE_STENCIL 43 /////////////////////////////////////////////////////////////////////////////// // Types Loading Loading @@ -157,9 +155,6 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; bool isPoint; float pointSize; bool hasGammaCorrection; float gamma; Loading Loading @@ -201,9 +196,6 @@ struct ProgramDescription { framebufferMode = SkXfermode::kClear_Mode; swapSrcDst = false; isPoint = false; pointSize = 0.0f; hasGammaCorrection = false; gamma = 2.2f; Loading Loading @@ -269,7 +261,6 @@ struct ProgramDescription { key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; Loading