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

Commit bf96c356 authored by Chet Haase's avatar Chet Haase Committed by Android (Google) Code Review
Browse files

Merge "Enable anti-aliasing for hw-accelerated lines"

parents 52c03d2c 5b0200bd
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -60,7 +60,10 @@ static const TextureVertex gMeshVertices[] = {
        FV(1.0f, 1.0f, 1.0f, 1.0f)
};
static const GLsizei gMeshStride = sizeof(TextureVertex);
static const GLsizei gVertexStride = sizeof(Vertex);
static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
static const GLsizei gMeshCount = 4;

///////////////////////////////////////////////////////////////////////////////
+205 −84
Original line number Diff line number Diff line
@@ -882,6 +882,10 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
    mDescription.hasAlpha8Texture = isAlpha8;
}

void OpenGLRenderer::setupDrawAALine() {
    mDescription.hasWidth = true;
}

void OpenGLRenderer::setupDrawPoint(float pointSize) {
    mDescription.isPoint = true;
    mDescription.pointSize = pointSize;
@@ -893,6 +897,7 @@ void OpenGLRenderer::setupDrawColor(int color) {

void OpenGLRenderer::setupDrawColor(int color, int alpha) {
    mColorA = alpha / 255.0f;
    // BUG on this next line? a is alpha divided by 255 *twice*
    const float a = mColorA / 255.0f;
    mColorR = a * ((color >> 16) & 0xFF);
    mColorG = a * ((color >>  8) & 0xFF);
@@ -1060,6 +1065,37 @@ void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint v
    }
}

void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
    mCaches.unbindMeshBuffer();
    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
            gVertexStride, vertices);
}

/**
 * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
 * outer boundary that fades out to 0. The variables set in the shader define the width of the
 * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The
 * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment
 * shader where the fragment is in relation to the line width overall; this value is then used
 * to compute the proper color, based on whether the fragment lies in the fading AA region of
 * the line.
 */
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) {
    mCaches.unbindMeshBuffer();
    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
            gAlphaVertexStride, vertices);
    int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance");
    glEnableVertexAttribArray(distanceSlot);
    glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords);
    int widthSlot = mCaches.currentProgram->getUniform("width");
    int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
    int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
    float boundaryWidth = (1 - strokeWidth) / 2;
    glUniform1f(widthSlot, strokeWidth);
    glUniform1f(boundaryWidthSlot, boundaryWidth);
    glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth));
}

void OpenGLRenderer::finishDrawTexture() {
    glDisableVertexAttribArray(mTexCoordsSlot);
}
@@ -1350,46 +1386,55 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
    }
}

void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
    if (mSnapshot->isIgnored()) return;

    const bool isAA = paint->isAntiAlias();
    const float strokeWidth = paint->getStrokeWidth() * 0.5f;
    // A stroke width of 0 has a special meaningin Skia:
    // it draws an unscaled 1px wide line
    const bool isHairLine = paint->getStrokeWidth() == 0.0f;

    int alpha;
    SkXfermode::Mode mode;
    getAlphaAndMode(paint, &alpha, &mode);

    int verticesCount = count >> 2;
    int generatedVerticesCount = 0;
    if (!isHairLine) {
        // TODO: AA needs more vertices
        verticesCount *= 6;
void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline,
        float strokeWidth) {
    int verticesCount = count;
    if (count > 4) {
        // Polyline: account for extra vertices needed for continous tri-strip
        verticesCount += (count -4);
    }
    if (isAA) {
        // Expand boundary to enable AA calculations on the quad border
        strokeWidth += .5f;
    }
    Vertex lines[verticesCount];
    Vertex* vertices = &lines[0];
    AlphaVertex wLines[verticesCount];
    AlphaVertex* aaVertices = &wLines[0];
    if (!isAA) {
        setupDrawVertices(vertices);
    } else {
        // TODO: AA will be different
        verticesCount *= 2;
        void *alphaCoords = ((void*) aaVertices) + gVertexAlphaOffset;
        // innerProportion is the ratio of the inner (non-AA) port of the line to the total
        // AA stroke width (the base stroke width expanded by a half pixel on either side).
        // This value is used in the fragment shader to determine how to fill fragments.
        float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f);
        setupDrawAALine((void*) aaVertices, (void*) alphaCoords, innerProportion);
    }

    TextureVertex lines[verticesCount];
    TextureVertex* vertex = &lines[0];

    setupDraw();
    setupDrawColor(paint->getColor(), alpha);
    setupDrawColorFilter();
    setupDrawShader();
    setupDrawBlending(mode);
    setupDrawProgram();
    setupDrawModelViewIdentity();
    setupDrawColorUniforms();
    setupDrawColorFilterUniforms();
    setupDrawShaderIdentityUniforms();
    setupDrawMesh(vertex);

    if (!isHairLine) {
        // TODO: Handle the AA case
    int generatedVerticesCount = 0;
    AlphaVertex *prevAAVertex = NULL;
    Vertex *prevVertex = NULL;
    float inverseScaleX, inverseScaleY;
    if (isHairline) {
        // The quad that we use for AA hairlines needs to account for scaling because the line
        // should always be one pixel wide regardless of scale.
        inverseScaleX = 1.0f;
        inverseScaleY = 1.0f;
        if (!mSnapshot->transform->isPureTranslate()) {
            Matrix4 *mat = mSnapshot->transform;
            float m00 = mat->data[Matrix4::kScaleX];
            float m01 = mat->data[Matrix4::kSkewY];
            float m02 = mat->data[2];
            float m10 = mat->data[Matrix4::kSkewX];
            float m11 = mat->data[Matrix4::kScaleX];
            float m12 = mat->data[6];
            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;
        }
    }
    for (int i = 0; i < count; i += 4) {
        // a = start point, b = end point
        vec2 a(points[i], points[i + 1]);
@@ -1401,6 +1446,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {

        // Find the normal to the line
        vec2 n = (b - a).copyNormalized() * strokeWidth;
        if (isHairline) {
            float wideningFactor;
            if (fabs(n.x) >= fabs(n.y)) {
                wideningFactor = fabs(1.0f / n.x);
            } else {
                wideningFactor = fabs(1.0f / n.y);
            }
            n.x *= inverseScaleX;
            n.y *= inverseScaleY;
            n *= wideningFactor;
        }
        float x = n.x;
        n.x = -n.y;
        n.y = x;
@@ -1421,36 +1477,100 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
            // by using only 4 vertices and the correct indices
            // Also we should probably used non textured vertices
            // when line AA is disabled to save on bandwidth
                TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f);
                TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f);
                TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f);
                TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f);
                TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f);
                TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f);

                generatedVerticesCount += 6;

            if (!isAA) {
                if (prevVertex != NULL) {
                    // Issue two repeat vertices to create degenerate triangles to bridge
                    // between the previous line and the new one. This is necessary because
                    // we are creating a single triangle_strip which will contain
                    // potentially discontinuous line segments.
                    Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]);
                    Vertex::set(vertices++, p1.x, p1.y);
                    generatedVerticesCount += 2;
                }
                Vertex::set(vertices++, p1.x, p1.y);
                Vertex::set(vertices++, p2.x, p2.y);
                Vertex::set(vertices++, p4.x, p4.y);
                Vertex::set(vertices++, p3.x, p3.y);
                prevVertex = vertices - 1;
                generatedVerticesCount += 4;
            } else {
                if (prevAAVertex != NULL) {
                    // Issue two repeat vertices to create degenerate triangles to bridge
                    // between the previous line and the new one. This is necessary because
                    // we are creating a single triangle_strip which will contain
                    // potentially discontinuous line segments.
                    AlphaVertex::set(aaVertices++,prevAAVertex->position[0],
                            prevAAVertex->position[1], prevAAVertex->alpha);
                    AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
                    generatedVerticesCount += 2;
                }
                AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
                AlphaVertex::set(aaVertices++, p1.x, p1.y, 1);
                AlphaVertex::set(aaVertices++, p3.x, p3.y, 0);
                AlphaVertex::set(aaVertices++, p2.x, p2.y, 0);
                prevAAVertex = aaVertices - 1;
                generatedVerticesCount += 4;
            }
            dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
        }
    }

    if (generatedVerticesCount > 0) {
            // GL_LINE does not give the result we want to match Skia
            glDrawArrays(GL_TRIANGLES, 0, generatedVerticesCount);
       glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount);
    }
}

void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
    if (mSnapshot->isIgnored()) return;

    const bool isAA = paint->isAntiAlias();
    const float strokeWidth = paint->getStrokeWidth() * 0.5f;
    // A stroke width of 0 has a special meaning in Skia:
    // it draws a line 1 px wide regardless of current transform
    bool isHairLine = paint->getStrokeWidth() == 0.0f;

    int alpha;
    SkXfermode::Mode mode;
    getAlphaAndMode(paint, &alpha, &mode);
    int generatedVerticesCount = 0;

    setupDraw();
    if (isAA) {
        setupDrawAALine();
    }
    setupDrawColor(paint->getColor(), alpha);
    setupDrawColorFilter();
    setupDrawShader();
    if (isAA) {
        setupDrawBlending(true, mode);
    } else {
        // TODO: Handle the AA case
        for (int i = 0; i < count; i += 4) {
            TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
            TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f);
        setupDrawBlending(mode);
    }
    setupDrawProgram();
    setupDrawModelViewIdentity();
    setupDrawColorUniforms();
    setupDrawColorFilterUniforms();
    setupDrawShaderIdentityUniforms();

            generatedVerticesCount += 2;
    if (!isHairLine) {
        drawLinesAsQuads(points, count, isAA, isHairLine, strokeWidth);
    } else {
        if (isAA) {
            drawLinesAsQuads(points, count, isAA, isHairLine, .5f);
        } else {
            int verticesCount = count >> 1;
            Vertex lines[verticesCount];
            Vertex* vertices = &lines[0];
            setupDrawVertices(vertices);
            for (int i = 0; i < count; i += 4) {

                const float left = fmin(points[i], points[i + 2]);
                const float right = fmax(points[i], points[i + 2]);
                const float top = fmin(points[i + 1], points[i + 3]);
                const float bottom = fmax(points[i + 1], points[i + 3]);

                Vertex::set(vertices++, points[i], points[i + 1]);
                Vertex::set(vertices++, points[i + 2], points[i + 3]);
                generatedVerticesCount += 2;
                dirtyLayer(left, top,
                        right == left ? left + 1 : right, bottom == top ? top + 1 : bottom,
                        *mSnapshot->transform);
@@ -1460,6 +1580,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
            glDrawArrays(GL_LINES, 0, generatedVerticesCount);
        }
    }
}

void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
    if (mSnapshot->isIgnored()) return;
+16 −0
Original line number Diff line number Diff line
@@ -282,6 +282,19 @@ private:

    void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);

    /**
     * Draws a line as a quad. Called by drawLines() for all cases except hairline without AA.
     *
     * @param points The vertices of the lines. Every four entries specifies the x/y points
     * of a single line segment.
     * @param count The number of entries in the points array.
     * @param isAA Whether the line is anti-aliased
     * @param isHairline Whether the line has strokeWidth==0, which results in the line being
     * one pixel wide on the display regardless of scale.
     */
    void drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline,
            float strokeWidth);

    /**
     * Draws a textured rectangle with the specified texture. The specified coordinates
     * are transformed by the current snapshot's transform matrix.
@@ -425,6 +438,7 @@ private:
     * Various methods to setup OpenGL rendering.
     */
    void setupDrawWithTexture(bool isAlpha8 = false);
    void setupDrawAALine();
    void setupDrawPoint(float pointSize);
    void setupDrawColor(int color);
    void setupDrawColor(int color, int alpha);
@@ -453,6 +467,8 @@ private:
    void setupDrawSimpleMesh();
    void setupDrawTexture(GLuint texture);
    void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
    void setupDrawVertices(GLvoid* vertices);
    void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
    void finishDrawTexture();

    void drawRegionRects(const Region& region);
+36 −2
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ const char* gVS_Header_Attributes =
        "attribute vec4 position;\n";
const char* gVS_Header_Attributes_TexCoords =
        "attribute vec2 texCoords;\n";
const char* gVS_Header_Attributes_Distance =
        "attribute float vtxDistance;\n";
const char* gVS_Header_Uniforms =
        "uniform mat4 transform;\n";
const char* gVS_Header_Uniforms_IsPoint =
@@ -56,6 +58,8 @@ 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_HasWidth =
        "varying float distance;\n";
const char* gVS_Header_Varyings_HasBitmap =
        "varying vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_PointHasBitmap =
@@ -88,6 +92,8 @@ const char* gVS_Main_Position =
        "    gl_Position = transform * position;\n";
const char* gVS_Main_PointSize =
        "    gl_PointSize = pointSize;\n";
const char* gVS_Main_Width =
        "    distance = vtxDistance;\n";
const char* gVS_Footer =
        "}\n\n";

@@ -101,6 +107,10 @@ const char* gFS_Header =
        "precision mediump float;\n\n";
const char* gFS_Uniforms_Color =
        "uniform vec4 color;\n";
const char* gFS_Uniforms_Width =
        "uniform float width;\n"
        "uniform float boundaryWidth;\n"
        "uniform float inverseBoundaryWidth;\n";
const char* gFS_Header_Uniforms_PointHasBitmap =
        "uniform vec2 textureDimension;\n"
        "uniform float pointSize;\n";
@@ -169,6 +179,12 @@ const char* gFS_Fast_SingleModulateGradient =
// General case
const char* gFS_Main_FetchColor =
        "    fragColor = color;\n";
const char* gFS_Main_AccountForWidth =
        "    if (distance < boundaryWidth) {\n"
        "        fragColor *= (distance * inverseBoundaryWidth);\n"
        "    } else if (distance > (1.0 - boundaryWidth)) {\n"
        "        fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n"
        "    }\n";
const char* gFS_Main_FetchTexture[2] = {
        // Don't modulate
        "    fragColor = texture2D(sampler, outTexCoords);\n",
@@ -354,6 +370,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
    if (description.hasTexture) {
        shader.append(gVS_Header_Attributes_TexCoords);
    }
    if (description.hasWidth) {
        shader.append(gVS_Header_Attributes_Distance);
    }
    // Uniforms
    shader.append(gVS_Header_Uniforms);
    if (description.hasGradient) {
@@ -369,6 +388,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
    if (description.hasTexture) {
        shader.append(gVS_Header_Varyings_HasTexture);
    }
    if (description.hasWidth) {
        shader.append(gVS_Header_Varyings_HasWidth);
    }
    if (description.hasGradient) {
        shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
    }
@@ -383,6 +405,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
        if (description.hasTexture) {
            shader.append(gVS_Main_OutTexCoords);
        }
        if (description.hasWidth) {
            shader.append(gVS_Main_Width);
        }
        if (description.hasGradient) {
            shader.append(gVS_Main_OutGradient[description.gradientType]);
        }
@@ -420,6 +445,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    if (description.hasTexture) {
        shader.append(gVS_Header_Varyings_HasTexture);
    }
    if (description.hasWidth) {
        shader.append(gVS_Header_Varyings_HasWidth);
    }
    if (description.hasGradient) {
        shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
    }
@@ -441,6 +469,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    if (description.hasTexture) {
        shader.append(gFS_Uniforms_TextureSampler);
    }
    if (description.hasWidth) {
        shader.append(gFS_Uniforms_Width);
    }
    if (description.hasGradient) {
        shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
    }
@@ -449,8 +480,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    }

    // Optimization for common cases
    if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone &&
            !description.isPoint) {
    if (!description.hasWidth && !blendFramebuffer &&
            description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
        bool fast = false;

        const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -534,6 +565,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
                shader.append(gFS_Main_FetchColor);
            }
        }
        if (description.hasWidth) {
            shader.append(gFS_Main_AccountForWidth);
        }
        if (description.hasGradient) {
            shader.append(gFS_Main_FetchGradient[description.gradientType]);
        }
+6 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ namespace uirenderer {
#define PROGRAM_KEY_COLOR_BLEND 0x80
#define PROGRAM_KEY_BITMAP_NPOT 0x100
#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
#define PROGRAM_KEY_VERTEX_WIDTH 0x4000

#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
@@ -119,6 +120,8 @@ struct ProgramDescription {
    bool hasBitmap;
    bool isBitmapNpot;

    bool hasWidth;

    bool hasGradient;
    Gradient gradientType;

@@ -148,6 +151,8 @@ struct ProgramDescription {
        hasTexture = false;
        hasAlpha8Texture = false;

        hasWidth = false;

        modulate = false;

        hasBitmap = false;
@@ -200,6 +205,7 @@ struct ProgramDescription {
    programid key() const {
        programid key = 0;
        if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
        if (hasWidth) key |= PROGRAM_KEY_VERTEX_WIDTH;
        if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
        if (hasBitmap) {
            key |= PROGRAM_KEY_BITMAP;
Loading