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

Commit 6926c72e authored by Romain Guy's avatar Romain Guy
Browse files

Correctly support pre-multiplied alpha, optimizations, more stuff.

Add support for the following drawing functions:
- drawBitmap(int[]...)
- drawPaint()

Optimizes shader state changes by enabling/disabling attribute arrays
only when needed.

Adds quick rejects when drawing trivial shapes to avoid unnecessary
OpenGL operations.

Change-Id: Ic2c6c2ed1523d08a63a8c95601a1ec40b6c7fbc9
parent 260e1021
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -46,6 +46,10 @@ class GLES20Canvas extends Canvas {
    private final float[] mPoint = new float[2];
    private final float[] mLine = new float[4];
    
    private final Rect mClipBounds = new Rect();

    private DrawFilter mFilter;

    ///////////////////////////////////////////////////////////////////////////
    // Constructors
    ///////////////////////////////////////////////////////////////////////////
@@ -164,6 +168,7 @@ class GLES20Canvas extends Canvas {

    @Override
    public boolean clipRect(Rect rect, Region.Op op) {
        // TODO: Implement
        throw new UnsupportedOperationException();
    }

@@ -174,6 +179,7 @@ class GLES20Canvas extends Canvas {

    @Override
    public boolean clipRect(RectF rect, Region.Op op) {
        // TODO: Implement
        throw new UnsupportedOperationException();
    }

@@ -336,12 +342,14 @@ class GLES20Canvas extends Canvas {

    @Override
    public void setDrawFilter(DrawFilter filter) {
        throw new UnsupportedOperationException();
        // Don't crash, but ignore the draw filter
        // TODO: Implement PaintDrawFilter
        mFilter = filter;
    }

    @Override
    public DrawFilter getDrawFilter() {
        throw new UnsupportedOperationException();
        return mFilter;
    }

    ///////////////////////////////////////////////////////////////////////////
@@ -408,7 +416,11 @@ class GLES20Canvas extends Canvas {
    @Override
    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
            int width, int height, boolean hasAlpha, Paint paint) {
        // TODO: Implement
        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
        b.recycle();
    }

    @Override
@@ -420,7 +432,7 @@ class GLES20Canvas extends Canvas {
    @Override
    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
            int vertOffset, int[] colors, int colorOffset, Paint paint) {
        throw new UnsupportedOperationException();
        // TODO: Implement
    }

    @Override
@@ -466,7 +478,9 @@ class GLES20Canvas extends Canvas {

    @Override
    public void drawPaint(Paint paint) {
        // TODO: Implement
        final Rect r = mClipBounds;
        nGetClipBounds(mRenderer, r);
        drawRect(r.left, r.top, r.right, r.bottom, paint);
    }

    @Override
@@ -591,6 +605,6 @@ class GLES20Canvas extends Canvas {
    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
            int indexOffset, int indexCount, Paint paint) {
        throw new UnsupportedOperationException();
        // TODO: Implement
    }
}
+23 −9
Original line number Diff line number Diff line
@@ -16,10 +16,25 @@

package android.graphics;

/**
 * Shader used to draw a bitmap as a texture. The bitmap can be repeated or
 * mirrored by setting the tiling mode.
 */
public class BitmapShader extends Shader {

    // we hold on just for the GC, since our native counterpart is using it
    private Bitmap mBitmap;
    /**
     * We hold on just for the GC, since our native counterpart is using it.
     * 
     * @hide 
     */
    public Bitmap mBitmap;
    /**
     * @hide 
     */
    public int mTileX;
    /**
     * @hide 
     */
    public int mTileY;

    /**
     * Call this to create a new shader that will draw with a bitmap.
@@ -30,12 +45,11 @@ public class BitmapShader extends Shader {
     */
    public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
        mBitmap = bitmap;
        native_instance = nativeCreate(bitmap.ni(),
                                       tileX.nativeInt, tileY.nativeInt);
        mTileX = tileX.nativeInt;
        mTileY = tileY.nativeInt;
        native_instance = nativeCreate(bitmap.ni(), mTileX, mTileY);
    }

    private static native int nativeCreate(int native_bitmap,
                                           int shaderTileModeX,
    private static native int nativeCreate(int native_bitmap, int shaderTileModeX,
            int shaderTileModeY);    
}
+50 −23
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ OpenGLRenderer::~OpenGLRenderer() {

    mTextureCache.clear();
    mLayerCache.clear();
    mPatchCache.clear();
}

///////////////////////////////////////////////////////////////////////////////
@@ -242,7 +243,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
    const Rect& rect = layer->layer;

    drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
            layer->texture, layer->alpha, layer->mode, layer->blend);
            layer->texture, layer->alpha, layer->mode, layer->blend, true);

    LayerSize size(rect.getWidth(), rect.getHeight());
    // Failing to add the layer to the cache should happen only if the
@@ -418,8 +419,15 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
///////////////////////////////////////////////////////////////////////////////

void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
    const float right = left + bitmap->width();
    const float bottom = top + bitmap->height();

    if (quickReject(left, top, right, bottom)) {
        return;
    }

    const Texture* texture = mTextureCache.get(bitmap);
    drawTextureRect(left, top, left + texture->width, top + texture->height, texture, paint);
    drawTextureRect(left, top, right, bottom, texture, paint);
}

void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
@@ -427,6 +435,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const
    const mat4 transform(*matrix);
    transform.mapRect(r);

    if (quickReject(r.left, r.top, r.right, r.bottom)) {
        return;
    }

    const Texture* texture = mTextureCache.get(bitmap);
    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
}
@@ -435,6 +447,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
         float srcLeft, float srcTop, float srcRight, float srcBottom,
         float dstLeft, float dstTop, float dstRight, float dstBottom,
         const SkPaint* paint) {
    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
        return;
    }

    const Texture* texture = mTextureCache.get(bitmap);

    const float width = texture->width;
@@ -454,6 +470,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,

void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
        float left, float top, float right, float bottom, const SkPaint* paint) {
    if (quickReject(left, top, right, bottom)) {
        return;
    }

    const Texture* texture = mTextureCache.get(bitmap);

    int alpha;
@@ -477,6 +497,10 @@ void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
}

void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
    if (quickReject(left, top, right, bottom)) {
        return;
    }

    SkXfermode::Mode mode;

    const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
@@ -495,6 +519,10 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
    drawColorRect(left, top, right, bottom, color, mode);
}

///////////////////////////////////////////////////////////////////////////////
// Drawing implementation
///////////////////////////////////////////////////////////////////////////////

void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
        int color, SkXfermode::Mode mode) {
    const int alpha = (color >> 24) & 0xFF;
@@ -503,24 +531,24 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
    const GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
    const GLfloat b = ((color      ) & 0xFF) / 255.0f;

    // Pre-multiplication happens when setting the shader color
    chooseBlending(alpha < 255, mode, true);

    mModelView.loadTranslate(left, top, 0.0f);
    mModelView.scale(right - left, bottom - top, 1.0f);

    useShader(mDrawColorShader);
    const bool inUse = useShader(mDrawColorShader);
    mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform);

    if (!inUse) {
        const GLvoid* p = &gDrawColorVertices[0].position[0];

    glEnableVertexAttribArray(mDrawColorShader->position);
        glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE,
                gDrawColorVertexStride, p);
    glUniform4f(mDrawColorShader->color, r, g, b, a);
    }
    // Render using pre-multiplied alpha
    glUniform4f(mDrawColorShader->color, r * a, g * a, b * a, a);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);

    glDisableVertexAttribArray(mDrawColorShader->position);
}

void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
@@ -529,8 +557,8 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
    SkXfermode::Mode mode;
    getAlphaAndMode(paint, &alpha, &mode);

    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
            isPremultiplied, &mDrawTextureVertices[0].position[0],
    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
            texture->blend, texture->blend, &mDrawTextureVertices[0].position[0],
            &mDrawTextureVertices[0].texture[0], NULL);
}

@@ -555,27 +583,24 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b

    // TODO handle tiling and filtering here

    glActiveTexture(GL_TEXTURE0);
    glUniform1i(mDrawTextureShader->sampler, 0);
    if (isPremultiplied) {
        glUniform4f(mDrawTextureShader->color, alpha, alpha, alpha, alpha);
    } else {
        glUniform4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha);
    }

    glEnableVertexAttribArray(mDrawTextureShader->position);
    glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
            gDrawTextureVertexStride, vertices);

    glEnableVertexAttribArray(mDrawTextureShader->texCoords);
    glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE,
            gDrawTextureVertexStride, texCoords);

    if (!indices) {
        glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
    } else {
        // TODO: Use triangle strip instead
        glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
    }

    glDisableVertexAttribArray(mDrawTextureShader->position);
    glDisableVertexAttribArray(mDrawTextureShader->texCoords);

    glBindTexture(GL_TEXTURE_2D, 0);
}

@@ -605,12 +630,14 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr
    mBlend = blend;
}

void OpenGLRenderer::useShader(const sp<Program>& shader) {
bool OpenGLRenderer::useShader(const sp<Program>& shader) {
    if (!shader->isInUse()) {
        mCurrentShader->remove();
        shader->use();
        mCurrentShader = shader;
        return false;
    }
    return true;
}

void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
+5 −3
Original line number Diff line number Diff line
@@ -179,7 +179,7 @@ private:
     * @param isPremultiplied Indicates whether the texture has premultiplied alpha
     */
    void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
            float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = true);
            float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = false);

    /**
     * Draws a textured rectangle with the specified texture. The specified coordinates
@@ -194,7 +194,7 @@ private:
     * @param isPremultiplied Indicates whether the texture has premultiplied alpha
     */
    void drawTextureRect(float left, float top, float right, float bottom, const Texture* texture,
            const SkPaint* paint, bool isPremultiplied = true);
            const SkPaint* paint, bool isPremultiplied = false);

    /**
     * Draws a textured mesh with the specified texture. If the indices are omitted, the
@@ -252,8 +252,10 @@ private:
     * in use, it will not be bound again. If it is not in use, the current shader is
     * marked unused and the specified shader becomes used and becomes the new
     * current shader.
     *
     * @return true If the specified shader was already in use, false otherwise.
     */
    inline void useShader(const sp<Program>& shader);
    inline bool useShader(const sp<Program>& shader);

    // Dimensions of the drawing surface
    int mWidth, mHeight;
+22 −0
Original line number Diff line number Diff line
@@ -146,6 +146,16 @@ void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMa
    glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
}

void DrawColorProgram::use() {
    Program::use();
    glEnableVertexAttribArray(position);
}

void DrawColorProgram::remove() {
    Program::remove();
    glDisableVertexAttribArray(position);
}

///////////////////////////////////////////////////////////////////////////////
// Draw texture
///////////////////////////////////////////////////////////////////////////////
@@ -156,5 +166,17 @@ DrawTextureProgram::DrawTextureProgram():
    sampler = addUniform("sampler");
}

void DrawTextureProgram::use() {
    DrawColorProgram::use();
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(sampler, 0);
    glEnableVertexAttribArray(texCoords);
}

void DrawTextureProgram::remove() {
    DrawColorProgram::remove();
    glDisableVertexAttribArray(texCoords);
}

}; // namespace uirenderer
}; // namespace android
Loading