Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0ec63b6 authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Merge "Add tessellation path for points"

parents 00a5de1a 6d29c8d5
Loading
Loading
Loading
Loading
+12 −65
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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;
    }
@@ -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);
@@ -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) {
+0 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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();
+101 −44
Original line number Diff line number Diff line
@@ -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);
}

@@ -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)));
}

@@ -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:
 *
@@ -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));

@@ -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();
}
@@ -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;
@@ -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,
+25 −10
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ class VertexBuffer {
public:
    VertexBuffer():
        mBuffer(0),
        mSize(0),
        mVertexCount(0),
        mCleanupMethod(NULL)
    {}

@@ -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));
@@ -81,7 +93,7 @@ private:
    }

    void* mBuffer;
    unsigned int mSize;
    unsigned int mVertexCount;

    void* mReallocBuffer; // used for multi-allocation

@@ -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);

+9 −18
Original line number Diff line number Diff line
@@ -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
@@ -157,9 +155,6 @@ struct ProgramDescription {
    SkXfermode::Mode framebufferMode;
    bool swapSrcDst;

    bool isPoint;
    float pointSize;

    bool hasGammaCorrection;
    float gamma;

@@ -201,9 +196,6 @@ struct ProgramDescription {
        framebufferMode = SkXfermode::kClear_Mode;
        swapSrcDst = false;

        isPoint = false;
        pointSize = 0.0f;

        hasGammaCorrection = false;
        gamma = 2.2f;

@@ -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