diff options
| -rw-r--r-- | libs/hwui/Android.mk | 3 | ||||
| -rw-r--r-- | libs/hwui/LayerRenderer.cpp | 9 | ||||
| -rw-r--r-- | libs/hwui/Matrix.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/Matrix.h | 8 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 233 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 30 | ||||
| -rw-r--r-- | libs/hwui/PathRenderer.cpp | 304 | ||||
| -rw-r--r-- | libs/hwui/PathRenderer.h | 111 | ||||
| -rw-r--r-- | libs/hwui/Program.h | 8 | ||||
| -rw-r--r-- | libs/hwui/ProgramCache.cpp | 74 | 
10 files changed, 581 insertions, 207 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index e032ae4296ba..549edd2bf7b3 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -21,6 +21,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)  		LayerRenderer.cpp \  		Matrix.cpp \  		OpenGLRenderer.cpp \ +		PathRenderer.cpp \  		Patch.cpp \  		PatchCache.cpp \  		PathCache.cpp \ @@ -34,7 +35,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)  		Stencil.cpp \  		TextureCache.cpp \  		TextDropShadowCache.cpp -	 +  	LOCAL_C_INCLUDES += \  		$(JNI_H_INCLUDE) \  		$(LOCAL_PATH)/../../include/utils \ diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index bb004c07f91f..799aea3755a5 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -349,7 +349,7 @@ void LayerRenderer::flushLayer(Layer* layer) {  bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {      Caches& caches = Caches::getInstance(); -    if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize && +    if (layer && bitmap->width() <= caches.maxTextureSize &&              bitmap->height() <= caches.maxTextureSize) {          GLuint fbo = caches.fboCache.get(); @@ -362,6 +362,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {          GLuint texture;          GLuint previousFbo; +        GLuint previousViewport[4];          GLenum format;          GLenum type; @@ -391,11 +392,13 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {          float alpha = layer->getAlpha();          SkXfermode::Mode mode = layer->getMode(); +        GLuint previousLayerFbo = layer->getFbo();          layer->setAlpha(255, SkXfermode::kSrc_Mode);          layer->setFbo(fbo);          glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); +        glGetIntegerv(GL_VIEWPORT, (GLint*) &previousViewport);          glBindFramebuffer(GL_FRAMEBUFFER, fbo);          glGenTextures(1, &texture); @@ -463,9 +466,11 @@ error:          glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);          layer->setAlpha(alpha, mode); -        layer->setFbo(0); +        layer->setFbo(previousLayerFbo);          glDeleteTextures(1, &texture);          caches.fboCache.put(fbo); +        glViewport(previousViewport[0], previousViewport[1], +                previousViewport[2], previousViewport[3]);          return status;      } diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index 7348f4d834dd..87add179bd69 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -55,21 +55,21 @@ void Matrix4::loadIdentity() {      mSimpleMatrix = true;  } -bool Matrix4::changesBounds() { +bool Matrix4::changesBounds() const {      return !(data[0] == 1.0f && data[1] == 0.0f && data[2] == 0.0f && data[4] == 0.0f &&               data[5] == 1.0f && data[6] == 0.0f && data[8] == 0.0f && data[9] == 0.0f &&               data[10] == 1.0f);  } -bool Matrix4::isPureTranslate() { +bool Matrix4::isPureTranslate() const {      return mSimpleMatrix && data[kScaleX] == 1.0f && data[kScaleY] == 1.0f;  } -bool Matrix4::isSimple() { +bool Matrix4::isSimple() const {      return mSimpleMatrix;  } -bool Matrix4::isIdentity() { +bool Matrix4::isIdentity() const {      return mIsIdentity;  } diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 22220a93c0ad..02b781e067cc 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -112,11 +112,11 @@ public:          multiply(u);      } -    bool isPureTranslate(); -    bool isSimple(); -    bool isIdentity(); +    bool isPureTranslate() const; +    bool isSimple() const; +    bool isIdentity() const; -    bool changesBounds(); +    bool changesBounds() const;      void copyTo(float* v) const;      void copyTo(SkMatrix& v) const; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index c475f2091c34..bdf1229b0cb5 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -33,6 +33,7 @@  #include "OpenGLRenderer.h"  #include "DisplayListRenderer.h" +#include "PathRenderer.h"  #include "Vector.h"  namespace android { @@ -540,15 +541,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,          if (p) {              alpha = p->getAlpha(); -            if (!mCaches.extensions.hasFramebufferFetch()) { -                const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); -                if (!isMode) { -                    // Assume SRC_OVER -                    mode = SkXfermode::kSrcOver_Mode; -                } -            } else { -                mode = getXfermode(p->getXfermode()); -            } +            mode = getXfermode(p->getXfermode());          } else {              mode = SkXfermode::kSrcOver_Mode;          } @@ -1260,12 +1253,12 @@ void OpenGLRenderer::setupDrawNoTexture() {      mCaches.disbaleTexCoordsVertexArray();  } -void OpenGLRenderer::setupDrawAALine() { +void OpenGLRenderer::setupDrawAA() {      mDescription.isAA = true;  } -void OpenGLRenderer::setupDrawAARect() { -    mDescription.isAARect = true; +void OpenGLRenderer::setupDrawVertexShape() { +    mDescription.isVertexShape = true;  }  void OpenGLRenderer::setupDrawPoint(float pointSize) { @@ -1872,97 +1865,48 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const   * a fragment shader to compute the translucency of the color from its position, we simply use a   * varying parameter to define how far a given pixel is into the region.   */ -void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom, -        int color, SkXfermode::Mode mode) { -    float inverseScaleX = 1.0f; -    float inverseScaleY = 1.0f; +void OpenGLRenderer::drawConvexPath(const SkPath& path, int color, SkXfermode::Mode mode, bool isAA) { +    VertexBuffer vertexBuffer; +    // TODO: try clipping large paths to viewport +    PathRenderer::convexPathFillVertices(path, mSnapshot->transform, vertexBuffer, isAA); -    // The quad that we use needs to account for scaling. -    if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) { -        Matrix4 *mat = mSnapshot->transform; -        float m00 = mat->data[Matrix4::kScaleX]; -        float m01 = mat->data[Matrix4::kSkewY]; -        float m10 = mat->data[Matrix4::kSkewX]; -        float m11 = mat->data[Matrix4::kScaleY]; -        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; -    } - -    float boundarySizeX = .5 * inverseScaleX; -    float boundarySizeY = .5 * inverseScaleY; - -    float innerLeft = left + boundarySizeX; -    float innerRight = right - boundarySizeX; -    float innerTop = top + boundarySizeY; -    float innerBottom = bottom - boundarySizeY; - -    // Adjust the rect by the AA boundary padding -    left -= boundarySizeX; -    right += boundarySizeX; -    top -= boundarySizeY; -    bottom += boundarySizeY; - -    if (!quickReject(left, top, right, bottom)) { -        setupDraw(); -        setupDrawNoTexture(); -        setupDrawAARect(); -        setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); -        setupDrawColorFilter(); -        setupDrawShader(); -        setupDrawBlending(true, mode); -        setupDrawProgram(); -        setupDrawModelViewIdentity(true); -        setupDrawColorUniforms(); -        setupDrawColorFilterUniforms(); -        setupDrawShaderIdentityUniforms(); +    setupDraw(); +    setupDrawNoTexture(); +    if (isAA) setupDrawAA(); +    setupDrawVertexShape(); +    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); +    setupDrawColorFilter(); +    setupDrawShader(); +    setupDrawBlending(isAA, mode); +    setupDrawProgram(); +    setupDrawModelViewIdentity(true); +    setupDrawColorUniforms(); +    setupDrawColorFilterUniforms(); +    setupDrawShaderIdentityUniforms(); -        AlphaVertex rects[14]; -        AlphaVertex* aVertices = &rects[0]; -        void* alphaCoords = ((GLbyte*) aVertices) + gVertexAlphaOffset; +    void* vertices = vertexBuffer.getBuffer(); +    bool force = mCaches.unbindMeshBuffer(); +    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, +                                      vertices, isAA ? gAlphaVertexStride : gVertexStride); +    mCaches.resetTexCoordsVertexPointer(); +    mCaches.unbindIndicesBuffer(); -        bool force = mCaches.unbindMeshBuffer(); -        mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, -                aVertices, gAlphaVertexStride); -        mCaches.resetTexCoordsVertexPointer(); -        mCaches.unbindIndicesBuffer(); +    int alphaSlot = -1; +    if (isAA) { +        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset; +        alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha"); -        int alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha"); +        // TODO: avoid enable/disable in back to back uses of the alpha attribute          glEnableVertexAttribArray(alphaSlot);          glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords); +    } -        // draw left -        AlphaVertex::set(aVertices++, left, bottom, 0); -        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1); -        AlphaVertex::set(aVertices++, left, top, 0); -        AlphaVertex::set(aVertices++, innerLeft, innerTop, 1); - -        // draw top -        AlphaVertex::set(aVertices++, right, top, 0); -        AlphaVertex::set(aVertices++, innerRight, innerTop, 1); - -        // draw right -        AlphaVertex::set(aVertices++, right, bottom, 0); -        AlphaVertex::set(aVertices++, innerRight, innerBottom, 1); - -        // draw bottom -        AlphaVertex::set(aVertices++, left, bottom, 0); -        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1); - -        // draw inner rect (repeating last vertex to create degenerate bridge triangles) -        // TODO: also consider drawing the inner rect without the blending-forced shader, if -        // blending is expensive. Note: can't use drawColorRect() since it doesn't use vertex -        // buffers like below, resulting in slightly different transformed coordinates. -        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1); -        AlphaVertex::set(aVertices++, innerLeft, innerTop, 1); -        AlphaVertex::set(aVertices++, innerRight, innerBottom, 1); -        AlphaVertex::set(aVertices++, innerRight, innerTop, 1); +    SkRect bounds = path.getBounds(); +    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *mSnapshot->transform); -        dirtyLayer(left, top, right, bottom, *mSnapshot->transform); - -        glDrawArrays(GL_TRIANGLE_STRIP, 0, 14); +    glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize()); +    if (isAA) {          glDisableVertexAttribArray(alphaSlot);      }  } @@ -2040,7 +1984,7 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {      setupDraw();      setupDrawNoTexture();      if (isAA) { -        setupDrawAALine(); +        setupDrawAA();      }      setupDrawColor(paint->getColor(), alpha);      setupDrawColorFilter(); @@ -2326,30 +2270,62 @@ status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* tex  }  status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, -        float rx, float ry, SkPaint* paint) { -    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; +        float rx, float ry, SkPaint* p) { +    if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) { +        return DrawGlInfo::kStatusDone; +    } -    mCaches.activeTexture(0); -    const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect( -            right - left, bottom - top, rx, ry, paint); -    return drawShape(left, top, texture, paint); +    if (p->getStyle() != SkPaint::kFill_Style) { +        mCaches.activeTexture(0); +        const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect( +                right - left, bottom - top, rx, ry, p); +        return drawShape(left, top, texture, p); +    } + +    SkPath path; +    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); +    path.addRoundRect(rect, rx, ry); +    drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias()); + +    return DrawGlInfo::kStatusDrew;  } -status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { -    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; +status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) { +    if (mSnapshot->isIgnored() || quickReject(x - radius, y - radius, x + radius, y + radius)) { +        return DrawGlInfo::kStatusDone; +    } -    mCaches.activeTexture(0); -    const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint); -    return drawShape(x - radius, y - radius, texture, paint); +    if (p->getStyle() != SkPaint::kFill_Style) { +        mCaches.activeTexture(0); +        const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, p); +        return drawShape(x - radius, y - radius, texture, p); +    } + +    SkPath path; +    path.addCircle(x, y, radius); +    drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias()); + +    return DrawGlInfo::kStatusDrew;  }  status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom, -        SkPaint* paint) { -    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; +        SkPaint* p) { +    if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) { +        return DrawGlInfo::kStatusDone; +    } -    mCaches.activeTexture(0); -    const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint); -    return drawShape(left, top, texture, paint); +    if (p->getStyle() != SkPaint::kFill_Style) { +        mCaches.activeTexture(0); +        const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, p); +        return drawShape(left, top, texture, p); +    } + +    SkPath path; +    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); +    path.addOval(rect); +    drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias()); + +    return DrawGlInfo::kStatusDrew;  }  status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom, @@ -2366,40 +2342,23 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto      return drawShape(left, top, texture, paint);  } -status_t OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom, -        SkPaint* paint) { -    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; - -    mCaches.activeTexture(0); -    const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint); -    return drawShape(left, top, texture, paint); -} -  status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) { -    if (p->getStyle() != SkPaint::kFill_Style) { -        return drawRectAsShape(left, top, right, bottom, p); -    } - -    if (quickReject(left, top, right, bottom)) { +    if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {          return DrawGlInfo::kStatusDone;      } -    SkXfermode::Mode mode; -    if (!mCaches.extensions.hasFramebufferFetch()) { -        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); -        if (!isMode) { -            // Assume SRC_OVER -            mode = SkXfermode::kSrcOver_Mode; -        } -    } else { -        mode = getXfermode(p->getXfermode()); +    if (p->getStyle() != SkPaint::kFill_Style) { +        mCaches.activeTexture(0); +        const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, p); +        return drawShape(left, top, texture, p);      } -    int color = p->getColor();      if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) { -        drawAARect(left, top, right, bottom, color, mode); +        SkPath path; +        path.addRect(left, top, right, bottom); +        drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), true);      } else { -        drawColorRect(left, top, right, bottom, color, mode); +        drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));      }      return DrawGlInfo::kStatusDrew; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 3e343361eede..7d5da68121cd 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -493,19 +493,6 @@ private:      status_t drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);      /** -     * Renders the rect defined by the specified bounds as a shape. -     * This will render the rect using a path texture, which is used to render -     * rects with stroke effects. -     * -     * @param left The left coordinate of the rect to draw -     * @param top The top coordinate of the rect to draw -     * @param right The right coordinate of the rect to draw -     * @param bottom The bottom coordinate of the rect to draw -     * @param p The paint to draw the rect with -     */ -    status_t drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p); - -    /**       * Draws the specified texture as an alpha bitmap. Alpha bitmaps obey       * different compositing rules.       * @@ -517,17 +504,14 @@ private:      void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);      /** -     * Renders the rect defined by the specified bounds as an anti-aliased rect. +     * Renders the convex hull defined by the specified path as a strip of polygons.       * -     * @param left The left coordinate of the rect to draw -     * @param top The top coordinate of the rect to draw -     * @param right The right coordinate of the rect to draw -     * @param bottom The bottom coordinate of the rect to draw +     * @param path The hull of the path to draw       * @param color The color of the rect -     * @param mode The blending mode to draw the rect +     * @param mode The blending mode to draw the path +     * @param isAA True if the drawing should be anti-aliased       */ -    void drawAARect(float left, float top, float right, float bottom, -            int color, SkXfermode::Mode mode); +    void drawConvexPath(const SkPath& path, int color, SkXfermode::Mode mode, bool isAA);      /**       * Draws a textured rectangle with the specified texture. The specified coordinates @@ -688,8 +672,8 @@ private:      void setupDrawWithTexture(bool isAlpha8 = false);      void setupDrawWithExternalTexture();      void setupDrawNoTexture(); -    void setupDrawAALine(); -    void setupDrawAARect(); +    void setupDrawAA(); +    void setupDrawVertexShape();      void setupDrawPoint(float pointSize);      void setupDrawColor(int color);      void setupDrawColor(int color, int alpha); diff --git a/libs/hwui/PathRenderer.cpp b/libs/hwui/PathRenderer.cpp new file mode 100644 index 000000000000..d222009b6742 --- /dev/null +++ b/libs/hwui/PathRenderer.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "PathRenderer" +#define LOG_NDEBUG 1 +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#define VERTEX_DEBUG 0 + +#include <SkPath.h> + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Log.h> +#include <utils/Trace.h> + +#include "PathRenderer.h" +#include "Matrix.h" +#include "Vector.h" +#include "Vertex.h" + +namespace android { +namespace uirenderer { + +#define THRESHOLD 0.5f + +void PathRenderer::computeInverseScales(const mat4 *transform, +        float &inverseScaleX, float& inverseScaleY) { +    inverseScaleX = 1.0f; +    inverseScaleY = 1.0f; +    if (CC_UNLIKELY(!transform->isPureTranslate())) { +        float m00 = transform->data[Matrix4::kScaleX]; +        float m01 = transform->data[Matrix4::kSkewY]; +        float m10 = transform->data[Matrix4::kSkewX]; +        float m11 = transform->data[Matrix4::kScaleY]; +        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; +    } +} + +void PathRenderer::convexPathFillVertices(const SkPath &path, const mat4 *transform, +        VertexBuffer &vertexBuffer, bool isAA) { +    ATRACE_CALL(); +    float inverseScaleX; +    float inverseScaleY; +    computeInverseScales(transform, inverseScaleX, inverseScaleY); + +    Vector<Vertex> tempVertices; +    float thresholdx = THRESHOLD * inverseScaleX; +    float thresholdy = THRESHOLD * inverseScaleY; +    convexPathVertices(path, +                       thresholdx * thresholdx, +                       thresholdy * thresholdy, +                       tempVertices); + +#if VERTEX_DEBUG +    for (unsigned int i = 0; i < tempVertices.size(); i++) { +        ALOGD("orig path: point at %f %f", +              tempVertices[i].position[0], +              tempVertices[i].position[1]); +    } +#endif +    int currentIndex = 0; +    if (!isAA) { +        Vertex* buffer = vertexBuffer.alloc<Vertex>(tempVertices.size()); + +        // zig zag between all previous points on the inside of the hull to create a +        // triangle strip that fills the hull +        int srcAindex = 0; +        int srcBindex = tempVertices.size() - 1; +        while (srcAindex <= srcBindex) { +            Vertex::set(&buffer[currentIndex++], +                        tempVertices.editArray()[srcAindex].position[0], +                        tempVertices.editArray()[srcAindex].position[1]); +            if (srcAindex == srcBindex) break; +            Vertex::set(&buffer[currentIndex++], +                        tempVertices.editArray()[srcBindex].position[0], +                        tempVertices.editArray()[srcBindex].position[1]); +            srcAindex++; +            srcBindex--; +        } +        return; +    } +    AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(tempVertices.size() * 3 + 2); + +    // generate alpha points - fill Alpha vertex gaps in between each point with +    // alpha 0 vertex, offset by a scaled normal. +    Vertex* last = &(tempVertices.editArray()[tempVertices.size()-1]); + +    for (unsigned int i = 0; i<tempVertices.size(); i++) { +        Vertex* current = &(tempVertices.editArray()[i]); +        Vertex* next = &(tempVertices.editArray()[i + 1 >= tempVertices.size() ? 0 : i + 1]); + +        vec2 lastNormal(current->position[1] - last->position[1], +                        last->position[0] - current->position[0]); +        lastNormal.normalize(); +        vec2 nextNormal(next->position[1] - current->position[1], +                        current->position[0] - next->position[0]); +        nextNormal.normalize(); + +        // AA point offset from original point is that point's normal, such that +        // each side is offset by .5 pixels +        vec2 totalOffset = (lastNormal + nextNormal) / (2 * (1 + lastNormal.dot(nextNormal))); +        totalOffset.x *= inverseScaleX; +        totalOffset.y *= inverseScaleY; + +        AlphaVertex::set(&buffer[currentIndex++], +                         current->position[0] + totalOffset.x, +                         current->position[1] + totalOffset.y, +                         0.0f); +        AlphaVertex::set(&buffer[currentIndex++], +                         current->position[0] - totalOffset.x, +                         current->position[1] - totalOffset.y, +                         1.0f); +        last = current; +    } + +    // wrap around to beginning +    AlphaVertex::set(&buffer[currentIndex++], +                     buffer[0].position[0], +                     buffer[0].position[1], 0.0f); +    AlphaVertex::set(&buffer[currentIndex++], +                     buffer[1].position[0], +                     buffer[1].position[1], 1.0f); + +    // zig zag between all previous points on the inside of the hull to create a +    // triangle strip that fills the hull, repeating the first inner point to +    // create degenerate tris to start inside path +    int srcAindex = 0; +    int srcBindex = tempVertices.size() - 1; +    while (srcAindex <= srcBindex) { +        AlphaVertex::set(&buffer[currentIndex++], +                         buffer[srcAindex * 2 + 1].position[0], +                         buffer[srcAindex * 2 + 1].position[1], +                         1.0f); +        if (srcAindex == srcBindex) break; +        AlphaVertex::set(&buffer[currentIndex++], +                         buffer[srcBindex * 2 + 1].position[0], +                         buffer[srcBindex * 2 + 1].position[1], +                         1.0f); +        srcAindex++; +        srcBindex--; +    } + +#if VERTEX_DEBUG +    for (unsigned int i = 0; i < vertexBuffer.mSize; i++) { +        ALOGD("point at %f %f", +              buffer[i].position[0], +              buffer[i].position[1]); +    } +#endif +} + + +void PathRenderer::convexPathVertices(const SkPath &path, float thresholdx, float thresholdy, +        Vector<Vertex> &outputVertices) { +    ATRACE_CALL(); + +    SkPath::Iter iter(path, true); +    SkPoint pos; +    SkPoint pts[4]; +    SkPath::Verb v; +    Vertex* newVertex = 0; +    while (SkPath::kDone_Verb != (v = iter.next(pts))) { +            switch (v) { +                case SkPath::kMove_Verb: +                    pos = pts[0]; +                    ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y()); +                    break; +                case SkPath::kClose_Verb: +                    ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y()); +                    break; +                case SkPath::kLine_Verb: +                    ALOGV("kLine_Verb %f %f -> %f %f", +                          pts[0].x(), pts[0].y(), +                          pts[1].x(), pts[1].y()); + +                    // TODO: make this not yuck +                    outputVertices.push(); +                    newVertex = &(outputVertices.editArray()[outputVertices.size()-1]); +                    Vertex::set(newVertex, pts[1].x(), pts[1].y()); +                    break; +                case SkPath::kQuad_Verb: +                    ALOGV("kQuad_Verb"); +                    recursiveQuadraticBezierVertices( +                        pts[0].x(), pts[0].y(), +                        pts[2].x(), pts[2].y(), +                        pts[1].x(), pts[1].y(), +                        thresholdx, thresholdy, +                        outputVertices); +                    break; +                case SkPath::kCubic_Verb: +                    ALOGV("kCubic_Verb"); +                    recursiveCubicBezierVertices( +                        pts[0].x(), pts[0].y(), +                        pts[1].x(), pts[1].y(), +                        pts[3].x(), pts[3].y(), +                        pts[2].x(), pts[2].y(), +                        thresholdx, thresholdy, outputVertices); +                    break; +                default: +                    break; +            } +    } +} + +void PathRenderer::recursiveCubicBezierVertices( +        float p1x, float p1y, float c1x, float c1y, +        float p2x, float p2y, float c2x, float c2y, +        float thresholdx, float thresholdy, Vector<Vertex> &outputVertices) { +    float dx = p2x - p1x; +    float dy = p2y - p1y; +    float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx); +    float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx); +    float d = d1 + d2; + +    if (d * d < (thresholdx * (dx * dx) + thresholdy * (dy * dy))) { +        // below thresh, draw line by adding endpoint +        // TODO: make this not yuck +        outputVertices.push(); +        Vertex* newVertex = &(outputVertices.editArray()[outputVertices.size()-1]); +        Vertex::set(newVertex, p2x, p2y); +    } else { +        float p1c1x = (p1x + c1x) * 0.5f; +        float p1c1y = (p1y + c1y) * 0.5f; +        float p2c2x = (p2x + c2x) * 0.5f; +        float p2c2y = (p2y + c2y) * 0.5f; + +        float c1c2x = (c1x + c2x) * 0.5f; +        float c1c2y = (c1y + c2y) * 0.5f; + +        float p1c1c2x = (p1c1x + c1c2x) * 0.5f; +        float p1c1c2y = (p1c1y + c1c2y) * 0.5f; + +        float p2c1c2x = (p2c2x + c1c2x) * 0.5f; +        float p2c1c2y = (p2c2y + c1c2y) * 0.5f; + +        float mx = (p1c1c2x + p2c1c2x) * 0.5f; +        float my = (p1c1c2y + p2c1c2y) * 0.5f; + +        recursiveCubicBezierVertices( +                p1x, p1y, p1c1x, p1c1y, +                mx, my, p1c1c2x, p1c1c2y, +                thresholdx, thresholdy, +                outputVertices); +        recursiveCubicBezierVertices( +                mx, my, p2c1c2x, p2c1c2y, +                p2x, p2y, p2c2x, p2c2y, +                thresholdx, thresholdy, +                outputVertices); +    } +} + +void PathRenderer::recursiveQuadraticBezierVertices( +        float ax, float ay, +        float bx, float by, +        float cx, float cy, +        float thresholdx, float thresholdy, Vector<Vertex> &outputVertices) { +    float dx = bx - ax; +    float dy = by - ay; +    float d = (cx - bx) * dy - (cy - by) * dx; + +    if (d * d < (thresholdx * (dx * dx) + thresholdy * (dy * dy))) { +        // below thresh, draw line by adding endpoint +        // TODO: make this not yuck +        outputVertices.push(); +        Vertex* newVertex = &(outputVertices.editArray()[outputVertices.size()-1]); +        Vertex::set(newVertex, bx, by); +    } else { +        float acx = (ax + cx) * 0.5f; +        float bcx = (bx + cx) * 0.5f; +        float acy = (ay + cy) * 0.5f; +        float bcy = (by + cy) * 0.5f; + +        // midpoint +        float mx = (acx + bcx) * 0.5f; +        float my = (acy + bcy) * 0.5f; + +        recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy, +                thresholdx, thresholdy, outputVertices); +        recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy, +                thresholdx, thresholdy, outputVertices); +    } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/PathRenderer.h b/libs/hwui/PathRenderer.h new file mode 100644 index 000000000000..1354f161c74c --- /dev/null +++ b/libs/hwui/PathRenderer.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HWUI_PATH_RENDERER_H +#define ANDROID_HWUI_PATH_RENDERER_H + +#include <utils/Vector.h> + +#include "Vertex.h" + +namespace android { +namespace uirenderer { + +class Matrix4; +typedef Matrix4 mat4; + +class VertexBuffer { +public: +    VertexBuffer(): +        mBuffer(0), +        mSize(0), +        mCleanupMethod(0) +    {} + +    ~VertexBuffer() +    { +        if (mCleanupMethod) +            mCleanupMethod(mBuffer); +    } + +    template <class TYPE> +    TYPE* alloc(int size) +    { +        mSize = size; +        mBuffer = (void*)new TYPE[size]; +        mCleanupMethod = &(cleanup<TYPE>); + +        return (TYPE*)mBuffer; +    } + +    void* getBuffer() { return mBuffer; } +    unsigned int getSize() { return mSize; } + +private: +    template <class TYPE> +    static void cleanup(void* buffer) +    { +        delete[] (TYPE*)buffer; +    } + +    void* mBuffer; +    unsigned int mSize; +    void (*mCleanupMethod)(void*); +}; + +class PathRenderer { +public: +    static void computeInverseScales( +        const mat4 *transform, float &inverseScaleX, float& inverseScaleY); + +    static void convexPathFillVertices( +        const SkPath &path, const mat4 *transform, +        VertexBuffer &vertexBuffer, bool isAA); + +private: +    static void convexPathVertices( +        const SkPath &path, +        float thresholdx, float thresholdy, +        Vector<Vertex> &outputVertices); + +/* +  endpoints a & b, +  control c + */ +    static void recursiveQuadraticBezierVertices( +        float ax, float ay, +        float bx, float by, +        float cx, float cy, +        float thresholdx, float thresholdy, +        Vector<Vertex> &outputVertices); + +/* +  endpoints p1, p2 +  control c1, c2 + */ +    static void recursiveCubicBezierVertices( +        float p1x, float p1y, +        float c1x, float c1y, +        float p2x, float p2y, +        float c2x, float c2y, +        float thresholdx, float thresholdy, +        Vector<Vertex> &outputVertices); +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_PATH_RENDERER_H diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index a821a9cab5b6..b1cb44690265 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -81,7 +81,7 @@ namespace uirenderer {  #define PROGRAM_IS_SIMPLE_GRADIENT 41 -#define PROGRAM_IS_AA_RECT_SHIFT 42 +#define PROGRAM_IS_VERTEX_SHAPE_SHIFT 42  ///////////////////////////////////////////////////////////////////////////////  // Types @@ -130,7 +130,7 @@ struct ProgramDescription {      bool isBitmapNpot;      bool isAA; -    bool isAARect; +    bool isVertexShape;      bool hasGradient;      Gradient gradientType; @@ -168,7 +168,7 @@ struct ProgramDescription {          hasTextureTransform = false;          isAA = false; -        isAARect = false; +        isVertexShape = false;          modulate = false; @@ -263,7 +263,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 (isAARect) key |= programid(0x1) << PROGRAM_IS_AA_RECT_SHIFT; +        if (isVertexShape) key |= programid(0x1) << PROGRAM_IS_VERTEX_SHAPE_SHIFT;          return key;      } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 6baf44847d4b..de7afede10c9 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -40,10 +40,10 @@ const char* gVS_Header_Attributes =          "attribute vec4 position;\n";  const char* gVS_Header_Attributes_TexCoords =          "attribute vec2 texCoords;\n"; -const char* gVS_Header_Attributes_AAParameters = +const char* gVS_Header_Attributes_AALineParameters =          "attribute float vtxWidth;\n"          "attribute float vtxLength;\n"; -const char* gVS_Header_Attributes_AARectParameters = +const char* gVS_Header_Attributes_AAVertexShapeParameters =          "attribute float vtxAlpha;\n";  const char* gVS_Header_Uniforms_TextureTransform =          "uniform mat4 mainTextureTransform;\n"; @@ -64,10 +64,10 @@ 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_IsAA = +const char* gVS_Header_Varyings_IsAALine =          "varying float widthProportion;\n"          "varying float lengthProportion;\n"; -const char* gVS_Header_Varyings_IsAARect = +const char* gVS_Header_Varyings_IsAAVertexShape =          "varying float alpha;\n";  const char* gVS_Header_Varyings_HasBitmap =          "varying highp vec2 outBitmapTexCoords;\n"; @@ -113,10 +113,10 @@ const char* gVS_Main_Position =          "    gl_Position = transform * position;\n";  const char* gVS_Main_PointSize =          "    gl_PointSize = pointSize;\n"; -const char* gVS_Main_AA = +const char* gVS_Main_AALine =          "    widthProportion = vtxWidth;\n"          "    lengthProportion = vtxLength;\n"; -const char* gVS_Main_AARect = +const char* gVS_Main_AAVertexShape =          "    alpha = vtxAlpha;\n";  const char* gVS_Footer =          "}\n\n"; @@ -133,7 +133,7 @@ const char* gFS_Header =          "precision mediump float;\n\n";  const char* gFS_Uniforms_Color =          "uniform vec4 color;\n"; -const char* gFS_Uniforms_AA = +const char* gFS_Uniforms_AALine =          "uniform float boundaryWidth;\n"          "uniform float boundaryLength;\n";  const char* gFS_Header_Uniforms_PointHasBitmap = @@ -243,10 +243,10 @@ const char* gFS_Main_FetchColor =          "    fragColor = color;\n";  const char* gFS_Main_ModulateColor =          "    fragColor *= color.a;\n"; -const char* gFS_Main_AccountForAA = +const char* gFS_Main_AccountForAALine =          "    fragColor *= (1.0 - smoothstep(boundaryWidth, 0.5, abs(0.5 - widthProportion)))\n"          "               * (1.0 - smoothstep(boundaryLength, 0.5, abs(0.5 - lengthProportion)));\n"; -const char* gFS_Main_AccountForAARect = +const char* gFS_Main_AccountForAAVertexShape =          "    fragColor *= alpha;\n";  const char* gFS_Main_FetchTexture[2] = { @@ -456,10 +456,12 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description      if (description.hasTexture || description.hasExternalTexture) {          shader.append(gVS_Header_Attributes_TexCoords);      } -    if (description.isAARect) { -        shader.append(gVS_Header_Attributes_AARectParameters); -    } else if (description.isAA) { -        shader.append(gVS_Header_Attributes_AAParameters); +    if (description.isAA) { +        if (description.isVertexShape) { +            shader.append(gVS_Header_Attributes_AAVertexShapeParameters); +        } else { +            shader.append(gVS_Header_Attributes_AALineParameters); +        }      }      // Uniforms      shader.append(gVS_Header_Uniforms); @@ -479,10 +481,12 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description      if (description.hasTexture || description.hasExternalTexture) {          shader.append(gVS_Header_Varyings_HasTexture);      } -    if (description.isAARect) { -        shader.append(gVS_Header_Varyings_IsAARect); -    } else if (description.isAA) { -        shader.append(gVS_Header_Varyings_IsAA); +    if (description.isAA) { +        if (description.isVertexShape) { +            shader.append(gVS_Header_Varyings_IsAAVertexShape); +        } else { +            shader.append(gVS_Header_Varyings_IsAALine); +        }      }      if (description.hasGradient) {          shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); @@ -500,10 +504,12 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description          } else if (description.hasTexture || description.hasExternalTexture) {              shader.append(gVS_Main_OutTexCoords);          } -        if (description.isAARect) { -            shader.append(gVS_Main_AARect); -        } else if (description.isAA) { -            shader.append(gVS_Main_AA); +        if (description.isAA) { +            if (description.isVertexShape) { +                shader.append(gVS_Main_AAVertexShape); +            } else { +                shader.append(gVS_Main_AALine); +            }          }          if (description.hasGradient) {              shader.append(gVS_Main_OutGradient[gradientIndex(description)]); @@ -552,10 +558,12 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti      if (description.hasTexture || description.hasExternalTexture) {          shader.append(gVS_Header_Varyings_HasTexture);      } -    if (description.isAARect) { -        shader.append(gVS_Header_Varyings_IsAARect); -    } else if (description.isAA) { -        shader.append(gVS_Header_Varyings_IsAA); +    if (description.isAA) { +        if (description.isVertexShape) { +            shader.append(gVS_Header_Varyings_IsAAVertexShape); +        } else { +            shader.append(gVS_Header_Varyings_IsAALine); +        }      }      if (description.hasGradient) {          shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); @@ -580,8 +588,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti      } else if (description.hasExternalTexture) {          shader.append(gFS_Uniforms_ExternalTextureSampler);      } -    if (description.isAA) { -        shader.append(gFS_Uniforms_AA); +    if (description.isAA && !description.isVertexShape) { +        shader.append(gFS_Uniforms_AALine);      }      if (description.hasGradient) {          shader.append(gFS_Uniforms_GradientSampler[gradientIndex(description)]); @@ -596,7 +604,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti      // Optimization for common cases      if (!description.isAA && !blendFramebuffer &&              description.colorOp == ProgramDescription::kColorNone && -            !description.isPoint && !description.isAARect) { +            !description.isPoint && !description.isVertexShape) {          bool fast = false;          const bool noShader = !description.hasGradient && !description.hasBitmap; @@ -730,10 +738,12 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti          // Apply the color op if needed          shader.append(gFS_Main_ApplyColorOp[description.colorOp]); -        if (description.isAARect) { -            shader.append(gFS_Main_AccountForAARect); -        } else if (description.isAA) { -            shader.append(gFS_Main_AccountForAA); +        if (description.isAA) { +            if (description.isVertexShape) { +                shader.append(gFS_Main_AccountForAAVertexShape); +            } else { +                shader.append(gFS_Main_AccountForAALine); +            }          }          // Output the fragment  |