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

Commit ccec048d authored by kui.zheng's avatar kui.zheng Committed by Steve Kondik
Browse files

Optimize drawBitmapMesh using TRIANGLE_STRIP



Draw BitmapMesh using STRIP instead of TRIANGLES.
Depending on where the bottleneck is located in the pipeline,
there is a potential for saving two-thirds of the time spent rendering.
The speedup is due to avoiding redundant operations,
i.e., mapping each vertex four times to texture and color attribute,
sending each vertex twice to the GPU, vertex processing of GPU ...

In this patch:
1. Refactoring mesh using Strip.
2. Batch triangles by adding degenerate triangles.
3. Optimize computing positions of texture and color attribute.

Benchmark: Drawing Bitmap(1152x768 px) with 200x200 meshes
Performance is doubled (from 26.4 fps to 53 fps, Nexus10).
Memory footprint: only 17% of original method.
(from 240000 to 40401 vertices with xy, uv, rgba data.)

Change-Id: I08c5c20d981d88528ce7b02012feefae468d6ec4
Signed-off-by: default avatarkui.zheng <kui.zheng@arm.com>
parent 5387341d
Loading
Loading
Loading
Loading
+53 −36
Original line number Diff line number Diff line
@@ -2088,15 +2088,17 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
    float right = FLT_MIN;
    float bottom = FLT_MIN;

    const uint32_t count = meshWidth * meshHeight * 6;
    uint32_t vertexCountWidth = meshWidth + 1;
    uint32_t vertexCountHeight = meshHeight + 1;
    uint32_t vertexCount = vertexCountWidth * vertexCountHeight;

    Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
    mesh.setCapacity(count);
    mesh.setCapacity(vertexCount);
    ColorTextureVertex* vertex = mesh.editArray();

    bool cleanupColors = false;
    if (!colors) {
        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
        uint32_t colorsCount = vertexCountWidth * vertexCountHeight;
        int* newColors = new int[colorsCount];
        memset(newColors, 0xff, colorsCount * sizeof(int));
        colors = newColors;
@@ -2107,39 +2109,54 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
    Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
    const UvMapper& mapper(getMapper(texture));

    for (int32_t y = 0; y < meshHeight; y++) {
        for (int32_t x = 0; x < meshWidth; x++) {
            uint32_t i = (y * (meshWidth + 1) + x) * 2;

            float u1 = float(x) / meshWidth;
            float u2 = float(x + 1) / meshWidth;
            float v1 = float(y) / meshHeight;
            float v2 = float(y + 1) / meshHeight;

            mapper.map(u1, v1, u2, v2);

            int ax = i + (meshWidth + 1) * 2;
            int ay = ax + 1;
            int bx = i;
            int by = bx + 1;
            int cx = i + 2;
            int cy = cx + 1;
            int dx = i + (meshWidth + 1) * 2 + 2;
            int dy = dx + 1;

            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);

            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);

            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
        }
    // Set vertices from Mesh's up to bottom (left to right in every row).
    // Update V coordinate only once for every row.
    for (uint32_t i = 0; i < vertexCountHeight; i++) {
        float v = float(i) / meshHeight;
        mapper.mapV(v);
        for (uint32_t j = 0; j < vertexCountWidth; j++) {
            uint32_t x = i * vertexCountWidth * 2 + j * 2;
            uint32_t y = x + 1;
            float u = float(j) / meshWidth;
            mapper.mapU(u);

            left = fminf(left, vertices[x]);
            top = fminf(top, vertices[y]);
            right = fmaxf(right, vertices[x]);
            bottom = fmaxf(bottom, vertices[y]);

            ColorTextureVertex::set(vertex++, vertices[x], vertices[y], u, v, colors[x/2]);
        }
    }

    // Set index order from mesh's bottom to up, So that
    // construct the same triangle mesh with original implementation.
    // Or, May result in diffrent interpolated color.
    //
    // For each row, add degenerate triangle for triangle strip
    // Take below for example:
    // v00 --- v01 --- v02 --- v03
    //  |  ...  |  ...  |  ...  |
    // v10 --- v11 --- v12 --- v13
    //  |  ...  |  ...  |  ...  |
    // v20 --- v21 --- v22 --- v23
    // Indices are: v20, v20, v10, v21, v11, v22, v12, v23, v13, v13,
    //              v10, v10, v00, v11, v01, v12, v02, v13, v03, v03
    uint32_t indexCount = meshHeight * (meshWidth * 2 + 4);
    uint16_t indices[indexCount];
    uint32_t currVertexRow = meshHeight;
    uint32_t index = 0;
    while (currVertexRow > 0) {
        uint32_t upVertexRow = currVertexRow - 1;
        indices[index++] = currVertexRow * vertexCountWidth;
        indices[index++] = currVertexRow * vertexCountWidth;
        indices[index++] = upVertexRow * vertexCountWidth;
        for (int i = 1; i <= meshWidth; i++) {
            indices[index++] = currVertexRow * vertexCountWidth + i;
            indices[index++] = upVertexRow * vertexCountWidth + i;
        }
        indices[index++] = upVertexRow * vertexCountWidth + meshWidth;
        currVertexRow--;
    }

    if (quickRejectSetupScissor(left, top, right, bottom)) {
@@ -2182,7 +2199,7 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
    setupDrawColorFilterUniforms(getColorFilter(paint));
    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);

    glDrawArrays(GL_TRIANGLES, 0, count);
    glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_SHORT, indices);

    int slot = mCaches.currentProgram->getAttrib("colors");
    if (slot >= 0) {