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

Commit 710f46d9 authored by Chris Craik's avatar Chris Craik
Browse files

Polygonal rendering of simple fill shapes

bug:4419017

Change-Id: If0428e1732139786cba15f54b285d880e4a56b89
parent 5ca88a10
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
		LayerRenderer.cpp \
		Matrix.cpp \
		OpenGLRenderer.cpp \
		PathRenderer.cpp \
		Patch.cpp \
		PatchCache.cpp \
		PathCache.cpp \
+7 −2
Original line number Diff line number Diff line
@@ -345,7 +345,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();
@@ -358,6 +358,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {

        GLuint texture;
        GLuint previousFbo;
        GLuint previousViewport[4];

        GLenum format;
        GLenum type;
@@ -387,11 +388,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);
@@ -459,9 +462,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;
    }
+4 −4
Original line number Diff line number Diff line
@@ -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;
}

+4 −4
Original line number Diff line number Diff line
@@ -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;
+96 −137
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@

#include "OpenGLRenderer.h"
#include "DisplayListRenderer.h"
#include "PathRenderer.h"
#include "Vector.h"

namespace android {
@@ -473,15 +474,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());
            }
        } else {
            mode = SkXfermode::kSrcOver_Mode;
        }
@@ -1193,12 +1186,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) {
@@ -1805,97 +1798,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;

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

    if (!quickReject(left, top, right, bottom)) {
    setupDraw();
    setupDrawNoTexture();
        setupDrawAARect();
    if (isAA) setupDrawAA();
    setupDrawVertexShape();
    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
    setupDrawColorFilter();
    setupDrawShader();
        setupDrawBlending(true, mode);
    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,
                aVertices, gAlphaVertexStride);
                                      vertices, isAA ? gAlphaVertexStride : gVertexStride);
    mCaches.resetTexCoordsVertexPointer();
    mCaches.unbindIndicesBuffer();

        int alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
    int alphaSlot = -1;
    if (isAA) {
        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
        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);

        dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
    SkRect bounds = path.getBounds();
    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *mSnapshot->transform);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 14);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize());

    if (isAA) {
        glDisableVertexAttribArray(alphaSlot);
    }
}
@@ -1973,7 +1917,7 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
    setupDraw();
    setupDrawNoTexture();
    if (isAA) {
        setupDrawAALine();
        setupDrawAA();
    }
    setupDrawColor(paint->getColor(), alpha);
    setupDrawColorFilter();
@@ -2259,30 +2203,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;
    }

    if (p->getStyle() != SkPaint::kFill_Style) {
        mCaches.activeTexture(0);
        const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
            right - left, bottom - top, rx, ry, paint);
    return drawShape(left, top, texture, paint);
                right - left, bottom - top, rx, ry, p);
        return drawShape(left, top, texture, p);
    }

status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
    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* p) {
    if (mSnapshot->isIgnored() || quickReject(x - radius, y - radius, x + radius, y + radius)) {
        return DrawGlInfo::kStatusDone;
    }

    if (p->getStyle() != SkPaint::kFill_Style) {
        mCaches.activeTexture(0);
    const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
    return drawShape(x - radius, y - radius, texture, paint);
        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;
    }

    if (p->getStyle() != SkPaint::kFill_Style) {
        mCaches.activeTexture(0);
    const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
    return drawShape(left, top, texture, paint);
        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,
@@ -2299,40 +2275,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;
Loading