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

Commit f86ef57f authored by Romain Guy's avatar Romain Guy
Browse files

Don't use full screen FBOs, this dramatically increase performance.

The next step will be to add an FBO cache to avoid churning memory on every
frame we draw. This change also adds support for drawBitmap(Bitmap, Matrix, Paint).

Change-Id: I7825cdcf0cad9bffe6219e05d8328a53d4a6e583
parent 1a3e1056
Loading
Loading
Loading
Loading
+7 −7
Original line number Original line Diff line number Diff line
@@ -368,19 +368,19 @@ class GLES20Canvas extends Canvas {


    @Override
    @Override
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
        final float width = bitmap.getWidth();
        final float height = bitmap.getHeight();
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, 0.0f, 0.0f, width, height,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint,
                0.0f, 0.0f, width, height, matrix.native_instance, nativePaint,
                bitmap.getDensity(), mDensity, mScreenDensity);
                bitmap.getDensity(), mDensity, mScreenDensity);
    }
    }


    private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint,
            int bitmapDensity, int canvasDensity, int screenDensity);

    @Override
    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
                dst.left, dst.top, dst.right, dst.bottom, 0, nativePaint,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint,
                bitmap.getDensity(), mDensity, mScreenDensity);
                bitmap.getDensity(), mDensity, mScreenDensity);
    }
    }


@@ -388,7 +388,7 @@ class GLES20Canvas extends Canvas {
    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
                dst.left, dst.top, dst.right, dst.bottom, 0, nativePaint,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint,
                bitmap.getDensity(), mDensity, mScreenDensity);
                bitmap.getDensity(), mDensity, mScreenDensity);
    }
    }


@@ -397,7 +397,7 @@ class GLES20Canvas extends Canvas {


    private native void nDrawBitmap(int renderer, int bitmap,
    private native void nDrawBitmap(int renderer, int bitmap,
            float srcLeft, float srcTop, float srcRight, float srcBottom,
            float srcLeft, float srcTop, float srcRight, float srcBottom,
            float left, float top, float right, float bottom, int matrix, int paint,
            float left, float top, float right, float bottom, int paint,
            int bitmapDensity, int canvasDensity, int screenDensity);
            int bitmapDensity, int canvasDensity, int screenDensity);


    @Override
    @Override
+17 −22
Original line number Original line Diff line number Diff line
@@ -413,33 +413,30 @@ abstract class HardwareRenderer {
            }
            }


            EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
            EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
                int[] num_config = new int[1];
                int[] index = new int[1];
                if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
                if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
                        num_config)) {
                    throw new IllegalArgumentException("eglChooseConfig failed");
                    throw new IllegalArgumentException("eglChooseConfig failed");
                }
                }


                int numConfigs = num_config[0];
                int numConfigs = index[0];

                if (numConfigs <= 0) {
                if (numConfigs <= 0) {
                    throw new IllegalArgumentException(
                    throw new IllegalArgumentException("No configs match configSpec");
                            "No configs match configSpec");
                }
                }


                EGLConfig[] configs = new EGLConfig[numConfigs];
                EGLConfig[] configs = new EGLConfig[numConfigs];
                if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
                if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
                        num_config)) {
                    throw new IllegalArgumentException("eglChooseConfig failed");
                    throw new IllegalArgumentException("eglChooseConfig#2 failed");
                }
                }

                EGLConfig config = chooseConfig(egl, display, configs);
                EGLConfig config = chooseConfig(egl, display, configs);
                if (config == null) {
                if (config == null) {
                    throw new IllegalArgumentException("No config chosen");
                    throw new IllegalArgumentException("No config chosen");
                }
                }

                return config;
                return config;
            }
            }


            abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
            abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
                    EGLConfig[] configs);


            private int[] filterConfigSpec(int[] configSpec) {
            private int[] filterConfigSpec(int[] configSpec) {
                if (mGlVersion != 2) {
                if (mGlVersion != 2) {
@@ -496,13 +493,12 @@ abstract class HardwareRenderer {
                for (EGLConfig config : configs) {
                for (EGLConfig config : configs) {
                    int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
                    int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
                    int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
                    int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
                    if ((d >= mDepthSize) && (s >= mStencilSize)) {
                    if (d >= mDepthSize && s >= mStencilSize) {
                        int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
                        int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
                        int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
                        int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
                        int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
                        int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
                        int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
                        int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
                        if ((r == mRedSize) && (g == mGreenSize) && (b == mBlueSize) &&
                        if (r == mRedSize && g == mGreenSize && b == mBlueSize && a >= mAlphaSize) {
                                (a == mAlphaSize)) {
                            return config;
                            return config;
                        }
                        }
                    }
                    }
@@ -510,9 +506,8 @@ abstract class HardwareRenderer {
                return null;
                return null;
            }
            }


            private int findConfigAttrib(EGL10 egl, EGLDisplay display,
            private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
                    EGLConfig config, int attribute, int defaultValue) {
                    int attribute, int defaultValue) {

                if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
                if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
                    return mValue[0];
                    return mValue[0];
                }
                }
+14 −4
Original line number Original line Diff line number Diff line
@@ -195,13 +195,22 @@ static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject canvas
        OpenGLRenderer* renderer, SkBitmap* bitmap,
        OpenGLRenderer* renderer, SkBitmap* bitmap,
        float srcLeft, float srcTop, float srcRight, float srcBottom,
        float srcLeft, float srcTop, float srcRight, float srcBottom,
        float dstLeft, float dstTop, float dstRight, float dstBottom,
        float dstLeft, float dstTop, float dstRight, float dstBottom,
        SkMatrix* matrix, SkPaint* paint,
        SkPaint* paint, jint bitmapDensity, jint canvasDensity, jint screenDensity) {
        jint bitmapDensity, jint canvasDensity, jint screenDensity) {
    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
        renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
        renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
                dstLeft, dstTop, dstRight, dstBottom, matrix, paint);
                dstLeft, dstTop, dstRight, dstBottom, paint);
    } else {
    } else {
        // TODO: implement
    }
}


static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canvas,
        OpenGLRenderer* renderer, SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint,
        jint bitmapDensity, jint canvasDensity,jint screenDensity) {
    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
        renderer->drawBitmap(bitmap, matrix, paint);
    } else {
        // TODO: implement
    }
    }
}
}


@@ -249,7 +258,8 @@ static JNINativeMethod gMethods[] = {
    {   "nConcatMatrix",      "(II)V",              (void*) android_view_GLES20Canvas_concatMatrix },
    {   "nConcatMatrix",      "(II)V",              (void*) android_view_GLES20Canvas_concatMatrix },


    {   "nDrawBitmap",        "(IIFFIIII)V",        (void*) android_view_GLES20Canvas_drawBitmap },
    {   "nDrawBitmap",        "(IIFFIIII)V",        (void*) android_view_GLES20Canvas_drawBitmap },
    {   "nDrawBitmap",        "(IIFFFFFFFFIIIII)V", (void*) android_view_GLES20Canvas_drawBitmapRect },
    {   "nDrawBitmap",        "(IIFFFFFFFFIIII)V",  (void*) android_view_GLES20Canvas_drawBitmapRect },
    {   "nDrawBitmap",        "(IIIIIII)V",         (void*) android_view_GLES20Canvas_drawBitmapMatrix },
    {   "nDrawColor",         "(III)V",             (void*) android_view_GLES20Canvas_drawColor },
    {   "nDrawColor",         "(III)V",             (void*) android_view_GLES20Canvas_drawColor },
    {   "nDrawRect",          "(IFFFFI)V",          (void*) android_view_GLES20Canvas_drawRect },
    {   "nDrawRect",          "(IFFFFI)V",          (void*) android_view_GLES20Canvas_drawRect },


+53 −25
Original line number Original line Diff line number Diff line
@@ -111,6 +111,7 @@ void OpenGLRenderer::setViewport(int width, int height) {


    mWidth = width;
    mWidth = width;
    mHeight = height;
    mHeight = height;
    mFirstSnapshot.height = height;
}
}


void OpenGLRenderer::prepare() {
void OpenGLRenderer::prepare() {
@@ -170,10 +171,15 @@ int OpenGLRenderer::saveSnapshot() {
bool OpenGLRenderer::restoreSnapshot() {
bool OpenGLRenderer::restoreSnapshot() {
    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;


    sp<Snapshot> current = mSnapshot;
    sp<Snapshot> current = mSnapshot;
    sp<Snapshot> previous = mSnapshot->previous;
    sp<Snapshot> previous = mSnapshot->previous;


    if (restoreOrtho) {
        memcpy(mOrthoMatrix, current->orthoMatrix, sizeof(mOrthoMatrix));
    }

    if (restoreLayer) {
    if (restoreLayer) {
        composeLayer(current, previous);
        composeLayer(current, previous);
    }
    }
@@ -197,21 +203,11 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
    // The texture is currently as big as the window but drawn with
    // The texture is currently as big as the window but drawn with
    // a quad of the appropriate size
    // a quad of the appropriate size
    const Rect& layer = current->layer;
    const Rect& layer = current->layer;
    Rect texCoords(current->layer);
    mSnapshot->transform.mapRect(texCoords);

    const float u1 = texCoords.left / float(mWidth);
    const float v1 = (mHeight - texCoords.top) / float(mHeight);
    const float u2 = texCoords.right / float(mWidth);
    const float v2 = (mHeight - texCoords.bottom) / float(mHeight);

    resetDrawTextureTexCoords(u1, v1, u2, v2);


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


    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
    // TODO Don't delete these things, but cache them

    glDeleteFramebuffers(1, &current->fbo);
    glDeleteFramebuffers(1, &current->fbo);
    glDeleteTextures(1, &current->texture);
    glDeleteTextures(1, &current->texture);
}
}
@@ -268,14 +264,10 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


    // TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time
    // TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time
    // TODO ***** IMPORTANT *****
    // TODO Use an FBO cache
    // Creating a texture-backed FBO works only if the texture is the same size
    // as the original rendering buffer (in this case, mWidth and mHeight.)
    // This is expensive and wasteful and must be fixed.
    // TODO Additionally we should use an FBO cache


    const GLsizei width = mWidth; //right - left;
    const GLsizei width = right - left;
    const GLsizei height = mHeight; //bottom - right;
    const GLsizei height = bottom - top;


    const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB;
    const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB;
    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
@@ -287,7 +279,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,


    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        LOGD("Framebuffer incomplete %d", status);
        LOGD("Framebuffer incomplete (GL error code 0x%x)", status);


        glDeleteFramebuffers(1, &snapshot->fbo);
        glDeleteFramebuffers(1, &snapshot->fbo);
        glDeleteTextures(1, &snapshot->texture);
        glDeleteTextures(1, &snapshot->texture);
@@ -295,11 +287,34 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
        return false;
        return false;
    }
    }


    // Clear the FBO
    glDisable(GL_SCISSOR_TEST);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_SCISSOR_TEST);

    snapshot->flags |= Snapshot::kFlagIsLayer;
    snapshot->flags |= Snapshot::kFlagIsLayer;
    snapshot->mode = mode;
    snapshot->mode = mode;
    snapshot->alpha = alpha / 255.0f;
    snapshot->alpha = alpha / 255.0f;
    snapshot->layer.set(left, top, right, bottom);
    snapshot->layer.set(left, top, right, bottom);


    // Creates a new snapshot to draw into the FBO
    saveSnapshot();
    // TODO: This doesn't preserve other transformations (check Skia first)
    mSnapshot->transform.loadTranslate(-left, -top, 0.0f);
    mSnapshot->clipRect.set(left, top, right, bottom);
    mSnapshot->height = bottom - top;
    setScissorFromClip();

    mSnapshot->flags = Snapshot::kFlagDirtyTransform | Snapshot::kFlagDirtyOrtho |
            Snapshot::kFlagClipSet;
    memcpy(mSnapshot->orthoMatrix, mOrthoMatrix, sizeof(mOrthoMatrix));

    // Change the ortho projection
    mat4 ortho;
    ortho.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
    ortho.copyTo(mOrthoMatrix);

    return true;
    return true;
}
}


@@ -343,7 +358,7 @@ void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {


void OpenGLRenderer::setScissorFromClip() {
void OpenGLRenderer::setScissorFromClip() {
    const Rect& clip = mSnapshot->getMappedClip();
    const Rect& clip = mSnapshot->getMappedClip();
    glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
    glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
}
}


const Rect& OpenGLRenderer::getClipBounds() {
const Rect& OpenGLRenderer::getClipBounds() {
@@ -381,7 +396,7 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
    Texture* texture = mTextureCache.get(bitmap);
    const Texture* texture = mTextureCache.get(bitmap);


    int alpha;
    int alpha;
    SkXfermode::Mode mode;
    SkXfermode::Mode mode;
@@ -391,11 +406,26 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const S
            alpha / 255.0f, mode, texture->blend, true);
            alpha / 255.0f, mode, texture->blend, true);
}
}


void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
    const mat4 transform(*matrix);
    transform.mapRect(r);

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

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

    drawTextureRect(r.left, r.top, r.right, r.bottom, texture->id,
            alpha / 255.0f, mode, texture->blend, true);
}

void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
         float srcLeft, float srcTop, float srcRight, float srcBottom,
         float srcLeft, float srcTop, float srcRight, float srcBottom,
         float dstLeft, float dstTop, float dstRight, float dstBottom,
         float dstLeft, float dstTop, float dstRight, float dstBottom,
         const SkMatrix* matrix, const SkPaint* paint) {
         const SkPaint* paint) {
    Texture* texture = mTextureCache.get(bitmap);
    const Texture* texture = mTextureCache.get(bitmap);


    int alpha;
    int alpha;
    SkXfermode::Mode mode;
    SkXfermode::Mode mode;
@@ -411,8 +441,6 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,


    resetDrawTextureTexCoords(u1, v1, u2, v2);
    resetDrawTextureTexCoords(u1, v1, u2, v2);


    // TODO: implement Matrix

    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture->id,
    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture->id,
            alpha / 255.0f, mode, texture->blend, true);
            alpha / 255.0f, mode, texture->blend, true);


+2 −2
Original line number Original line Diff line number Diff line
@@ -103,9 +103,9 @@ public:
    bool clipRect(float left, float top, float right, float bottom);
    bool clipRect(float left, float top, float right, float bottom);


    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
    void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
            float dstLeft, float dstTop, float dstRight, float dstBottom,
            float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint);
            const SkMatrix* matrix, const SkPaint* paint);
    void drawColor(int color, SkXfermode::Mode mode);
    void drawColor(int color, SkXfermode::Mode mode);
    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);


Loading