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

Commit 99585ade authored by Chet Haase's avatar Chet Haase
Browse files

Line endcaps for AA lines are now antialiased.

Also fixed other minor issues with AA and line rendering.

Change-Id: Icd4638d27c70e2ee0f28b5d9a2b97d8b29e8ac4d
parent 71a0dab1
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -62,8 +62,10 @@ static const TextureVertex gMeshVertices[] = {
static const GLsizei gMeshStride = sizeof(TextureVertex);
static const GLsizei gVertexStride = sizeof(Vertex);
static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
static const GLsizei gAAVertexStride = sizeof(AAVertex);
static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
static const GLsizei gMeshCount = 4;

///////////////////////////////////////////////////////////////////////////////
+60 −32
Original line number Diff line number Diff line
@@ -915,7 +915,7 @@ void OpenGLRenderer::setupDrawWithExternalTexture() {
}

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

void OpenGLRenderer::setupDrawPoint(float pointSize) {
@@ -1121,25 +1121,30 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* 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.
 * outer boundary that fades out to 0. The variables set in the shader define the proportion of
 * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
 * attributes (one per vertex) are values from zero to one that tells the fragment
 * shader where the fragment is in relation to the line width/length overall; these values are
 * then used to compute the proper color, based on whether the fragment lies in the fading AA
 * region of the line.
 * Note that we only pass down the width values in this setup function. The length coordinates
 * are set up for each individual segment.
 */
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) {
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
        GLvoid* lengthCoords, 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");
            gAAVertexStride, vertices);
    int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
    glEnableVertexAttribArray(widthSlot);
    glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
    int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
    glEnableVertexAttribArray(lengthSlot);
    glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
    int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
    // Setting the inverse value saves computations per-fragment in the shader
    int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
    float boundaryWidth = (1 - strokeWidth) / 2;
    glUniform1f(widthSlot, strokeWidth);
    glUniform1f(boundaryWidthSlot, boundaryWidth);
    glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth));
}
@@ -1480,20 +1485,21 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
    }
    Vertex lines[verticesCount];
    Vertex* vertices = &lines[0];
    AlphaVertex wLines[verticesCount];
    AlphaVertex* aaVertices = &wLines[0];
    AAVertex wLines[verticesCount];
    AAVertex* aaVertices = &wLines[0];
    if (!isAA) {
        setupDrawVertices(vertices);
    } else {
        void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset;
        void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
        void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
        // 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, alphaCoords, innerProportion);
        setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, innerProportion);
    }

    AlphaVertex *prevAAVertex = NULL;
    AAVertex *prevAAVertex = NULL;
    Vertex *prevVertex = NULL;
    float inverseScaleX = 1.0f;
    float inverseScaleY = 1.0f;
@@ -1516,15 +1522,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
        }
    }

    int boundaryLengthSlot = -1;
    int inverseBoundaryLengthSlot = -1;
    for (int i = 0; i < count; i += 4) {
        // a = start point, b = end point
        vec2 a(points[i], points[i + 1]);
        vec2 b(points[i + 2], points[i + 3]);
        float length = 0;

        // Find the normal to the line
        vec2 n = (b - a).copyNormalized() * strokeWidth;
        if (isHairLine) {
            n *= inverseScaleX;
            if (isAA) {
                float wideningFactor;
                if (fabs(n.x) >= fabs(n.y)) {
@@ -1534,27 +1542,35 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
                }
                n *= wideningFactor;
            }
            n.x *= inverseScaleX;
            n.y *= inverseScaleY;
        }
        float x = n.x;
        n.x = -n.y;
        n.y = x;

        // aa lines expand the endpoint vertices to encompass the AA boundary
        if (isAA) {
            vec2 abVector = (b - a);
            length = abVector.length();
            abVector.normalize();
            a -= abVector;
            b += abVector;
        }

        // Four corners of the rectangle defining a thick line
        vec2 p1 = a - n;
        vec2 p2 = a + n;
        vec2 p3 = b + n;
        vec2 p4 = b - n;


        const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
        const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
        const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
        const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));

        if (!quickReject(left, top, right, bottom)) {
            // Draw the line as 2 triangles, could be optimized
            // 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
            if (!isAA) {
                if (prevVertex != NULL) {
                    // Issue two repeat vertices to create degenerate triangles to bridge
@@ -1572,24 +1588,36 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
                prevVertex = vertices - 1;
                generatedVerticesCount += 4;
            } else {
                if (boundaryLengthSlot < 0) {
                    boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
                    inverseBoundaryLengthSlot =
                            mCaches.currentProgram->getUniform("inverseBoundaryLength");
                }
                float innerProportion = (length) / (length + 2);
                float boundaryLength = (1 - innerProportion) / 2;
                glUniform1f(boundaryLengthSlot, boundaryLength);
                glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLength));

                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);
                    AAVertex::set(aaVertices++,prevAAVertex->position[0],
                            prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
                    AAVertex::set(aaVertices++, p4.x, p4.y, 1, 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);
                AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
                AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
                AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
                AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
                prevAAVertex = aaVertices - 1;
                generatedVerticesCount += 4;
            }
            dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
            dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
                    a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
                    *mSnapshot->transform);
        }
    }
    if (generatedVerticesCount > 0) {
+2 −1
Original line number Diff line number Diff line
@@ -468,7 +468,8 @@ private:
    void setupDrawTextureTransform(mat4& transform);
    void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
    void setupDrawVertices(GLvoid* vertices);
    void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
    void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
            float strokeWidth);
    void finishDrawTexture();

    void drawRegionRects(const Region& region);
+36 −27
Original line number Diff line number Diff line
@@ -39,8 +39,9 @@ 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_Attributes_AAParameters =
        "attribute float vtxWidth;\n"
        "attribute float vtxLength;\n";
const char* gVS_Header_Uniforms_TextureTransform =
        "uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
@@ -60,8 +61,9 @@ 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_IsAA =
        "varying float widthProportion;\n"
        "varying float lengthProportion;\n";
const char* gVS_Header_Varyings_HasBitmap =
        "varying vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_PointHasBitmap =
@@ -96,8 +98,9 @@ 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_Main_AA =
        "    widthProportion = vtxWidth;\n"
        "    lengthProportion = vtxLength;\n";
const char* gVS_Footer =
        "}\n\n";

@@ -113,10 +116,11 @@ 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"
const char* gFS_Uniforms_AA =
        "uniform float boundaryWidth;\n"
        "uniform float inverseBoundaryWidth;\n";
        "uniform float inverseBoundaryWidth;\n"
        "uniform float boundaryLength;\n"
        "uniform float inverseBoundaryLength;\n";
const char* gFS_Header_Uniforms_PointHasBitmap =
        "uniform vec2 textureDimension;\n"
        "uniform float pointSize;\n";
@@ -189,11 +193,16 @@ const char* gFS_Main_FetchColor =
        "    fragColor = color;\n";
const char* gFS_Main_ModulateColor =
        "    fragColor *= color.a;\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"
const char* gFS_Main_AccountForAA =
        "    if (widthProportion < boundaryWidth) {\n"
        "        fragColor *= (widthProportion * inverseBoundaryWidth);\n"
        "    } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
        "        fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
        "    }\n"
        "    if (lengthProportion < boundaryLength) {\n"
        "        fragColor *= (lengthProportion * inverseBoundaryLength);\n"
        "    } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
        "        fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
        "    }\n";
const char* gFS_Main_FetchTexture[2] = {
        // Don't modulate
@@ -380,8 +389,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
    if (description.hasTexture || description.hasExternalTexture) {
        shader.append(gVS_Header_Attributes_TexCoords);
    }
    if (description.hasWidth) {
        shader.append(gVS_Header_Attributes_Distance);
    if (description.isAA) {
        shader.append(gVS_Header_Attributes_AAParameters);
    }
    // Uniforms
    shader.append(gVS_Header_Uniforms);
@@ -401,8 +410,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
    if (description.hasTexture || description.hasExternalTexture) {
        shader.append(gVS_Header_Varyings_HasTexture);
    }
    if (description.hasWidth) {
        shader.append(gVS_Header_Varyings_HasWidth);
    if (description.isAA) {
        shader.append(gVS_Header_Varyings_IsAA);
    }
    if (description.hasGradient) {
        shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -421,8 +430,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
        if (description.hasExternalTexture) {
            shader.append(gVS_Main_OutTransformedTexCoords);
        }
        if (description.hasWidth) {
            shader.append(gVS_Main_Width);
        if (description.isAA) {
            shader.append(gVS_Main_AA);
        }
        if (description.hasGradient) {
            shader.append(gVS_Main_OutGradient[description.gradientType]);
@@ -464,8 +473,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    if (description.hasTexture || description.hasExternalTexture) {
        shader.append(gVS_Header_Varyings_HasTexture);
    }
    if (description.hasWidth) {
        shader.append(gVS_Header_Varyings_HasWidth);
    if (description.isAA) {
        shader.append(gVS_Header_Varyings_IsAA);
    }
    if (description.hasGradient) {
        shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -491,8 +500,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    if (description.hasExternalTexture) {
        shader.append(gFS_Uniforms_ExternalTextureSampler);
    }
    if (description.hasWidth) {
        shader.append(gFS_Uniforms_Width);
    if (description.isAA) {
        shader.append(gFS_Uniforms_AA);
    }
    if (description.hasGradient) {
        shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
@@ -502,7 +511,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    }

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

@@ -587,8 +596,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
                shader.append(gFS_Main_FetchColor);
            }
        }
        if (description.hasWidth) {
            shader.append(gFS_Main_AccountForWidth);
        if (description.isAA) {
            shader.append(gFS_Main_AccountForAA);
        }
        if (description.hasGradient) {
            shader.append(gFS_Main_FetchGradient[description.gradientType]);
+4 −4
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ namespace uirenderer {

#define PROGRAM_IS_POINT_SHIFT 36

#define PROGRAM_HAS_WIDTH_SHIFT 37
#define PROGRAM_HAS_AA_SHIFT 37

#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38

@@ -124,7 +124,7 @@ struct ProgramDescription {
    bool hasBitmap;
    bool isBitmapNpot;

    bool hasWidth;
    bool isAA;

    bool hasGradient;
    Gradient gradientType;
@@ -156,7 +156,7 @@ struct ProgramDescription {
        hasAlpha8Texture = false;
        hasExternalTexture = false;

        hasWidth = false;
        isAA = false;

        modulate = false;

@@ -243,7 +243,7 @@ struct ProgramDescription {
        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 (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
        if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
        if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
        return key;
    }
Loading