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

Commit 749b9dba authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

Merge "Don't blend transparent pixels when rendering layers." into honeycomb

parents c237bb27 f219da5e
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include "Rect.h"
#include "SkiaColorFilter.h"
#include "Vertex.h"

namespace android {
namespace uirenderer {
@@ -41,6 +42,14 @@ namespace uirenderer {
struct Layer {
    Layer(const uint32_t layerWidth, const uint32_t layerHeight):
            width(layerWidth), height(layerHeight) {
        mesh = NULL;
        meshIndices = NULL;
        meshElementCount = 0;
    }

    ~Layer() {
        if (mesh) delete mesh;
        if (meshIndices) delete meshIndices;
    }

    /**
@@ -99,6 +108,13 @@ struct Layer {
     * Color filter used to draw this layer. Optional.
     */
    SkiaColorFilter* colorFilter;

    /**
     * If the layer can be rendered as a mesh, this is non-null.
     */
    TextureVertex* mesh;
    uint16_t* meshIndices;
    GLsizei meshElementCount;
}; // struct Layer

}; // namespace uirenderer
+91 −1
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ namespace uirenderer {
void LayerRenderer::prepare(bool opaque) {
    LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);

#if RENDER_LAYERS_AS_REGIONS
    mLayer->region.clear();
#endif

    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo);
    glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);

@@ -39,11 +43,97 @@ void LayerRenderer::finish() {
    OpenGLRenderer::finish();
    glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo);

    generateMesh();

    LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo);
}

///////////////////////////////////////////////////////////////////////////////
// Static functions
// Dirty region tracking
///////////////////////////////////////////////////////////////////////////////

bool LayerRenderer::hasLayer() {
    return true;
}

Region* LayerRenderer::getRegion() {
#if RENDER_LAYERS_AS_REGIONS
    if (getSnapshot()->flags & Snapshot::kFlagFboTarget) {
        return OpenGLRenderer::getRegion();
    }
    return &mLayer->region;
#else
    return OpenGLRenderer::getRegion();
#endif
}

void LayerRenderer::generateMesh() {
#if RENDER_LAYERS_AS_REGIONS
    if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
        if (mLayer->mesh) {
            delete mLayer->mesh;
            delete mLayer->meshIndices;

            mLayer->mesh = NULL;
            mLayer->meshIndices = NULL;
            mLayer->meshElementCount = 0;
        }
        return;
    }

    size_t count;
    const android::Rect* rects = mLayer->region.getArray(&count);

    GLsizei elementCount = count * 6;

    if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
        delete mLayer->mesh;
        delete mLayer->meshIndices;

        mLayer->mesh = NULL;
        mLayer->meshIndices = NULL;
    }

    if (!mLayer->mesh) {
        mLayer->mesh = new TextureVertex[count * 4];
        mLayer->meshIndices = new uint16_t[elementCount];
        mLayer->meshElementCount = elementCount;
    }

    const float texX = 1.0f / float(mLayer->width);
    const float texY = 1.0f / float(mLayer->height);
    const float height = mLayer->layer.getHeight();

    TextureVertex* mesh = mLayer->mesh;
    uint16_t* indices = mLayer->meshIndices;

    for (size_t i = 0; i < count; i++) {
        const android::Rect* r = &rects[i];

        const float u1 = r->left * texX;
        const float v1 = (height - r->top) * texY;
        const float u2 = r->right * texX;
        const float v2 = (height - r->bottom) * texY;

        TextureVertex::set(mesh++, r->left, r->top, u1, v1);
        TextureVertex::set(mesh++, r->right, r->top, u2, v1);
        TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
        TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);

        uint16_t quad = i * 4;
        int index = i * 6;
        indices[index    ] = quad;       // top-left
        indices[index + 1] = quad + 1;   // top-right
        indices[index + 2] = quad + 2;   // bottom-left
        indices[index + 3] = quad + 2;   // bottom-left
        indices[index + 4] = quad + 1;   // top-right
        indices[index + 5] = quad + 3;   // bottom-right
    }
#endif
}

///////////////////////////////////////////////////////////////////////////////
// Layers management
///////////////////////////////////////////////////////////////////////////////

Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
+5 −0
Original line number Diff line number Diff line
@@ -49,12 +49,17 @@ public:
    void prepare(bool opaque);
    void finish();

    bool hasLayer();
    Region* getRegion();

    static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
    static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
    static void destroyLayer(Layer* layer);
    static void destroyLayerDeferred(Layer* layer);

private:
    void generateMesh();

    Layer* mLayer;
    GLuint mPreviousFbo;

+40 −15
Original line number Diff line number Diff line
@@ -615,6 +615,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
        const float alpha = layer->alpha / 255.0f;
        const float texX = 1.0f / float(layer->width);
        const float texY = 1.0f / float(layer->height);
        const float height = rect.getHeight();

        TextureVertex* mesh = mCaches.getRegionMesh();
        GLsizei numQuads = 0;
@@ -636,9 +637,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
            const android::Rect* r = &rects[i];

            const float u1 = r->left * texX;
            const float v1 = (rect.getHeight() - r->top) * texY;
            const float v1 = (height - r->top) * texY;
            const float u2 = r->right * texX;
            const float v2 = (rect.getHeight() - r->bottom) * texY;
            const float v2 = (height - r->bottom) * texY;

            // TODO: Reject quads outside of the clip
            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
@@ -694,10 +695,10 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
void OpenGLRenderer::dirtyLayer(const float left, const float top,
        const float right, const float bottom, const mat4 transform) {
#if RENDER_LAYERS_AS_REGIONS
    if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
    if (hasLayer()) {
        Rect bounds(left, top, right, bottom);
        transform.mapRect(bounds);
        dirtyLayerUnchecked(bounds, mSnapshot->region);
        dirtyLayerUnchecked(bounds, getRegion());
    }
#endif
}
@@ -705,9 +706,9 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top,
void OpenGLRenderer::dirtyLayer(const float left, const float top,
        const float right, const float bottom) {
#if RENDER_LAYERS_AS_REGIONS
    if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
    if (hasLayer()) {
        Rect bounds(left, top, right, bottom);
        dirtyLayerUnchecked(bounds, mSnapshot->region);
        dirtyLayerUnchecked(bounds, getRegion());
    }
#endif
}
@@ -1419,24 +1420,20 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);

#if RENDER_LAYERS_AS_REGIONS
    bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
    bool hasActiveLayer = hasLayer();
#else
    bool hasLayer = false;
    bool hasActiveLayer = false;
#endif

    mCaches.unbindMeshBuffer();
    if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
            hasLayer ? &bounds : NULL)) {
            hasActiveLayer ? &bounds : NULL)) {
#if RENDER_LAYERS_AS_REGIONS
        if (hasLayer) {
        if (hasActiveLayer) {
            if (!pureTranslate) {
                mSnapshot->transform->mapRect(bounds);
            }
            bounds.intersect(*mSnapshot->clipRect);
            bounds.snapToPixelBoundaries();

            android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
            mSnapshot->region->orSelf(dirty);
            dirtyLayerUnchecked(bounds, getRegion());
        }
#endif
    }
@@ -1501,8 +1498,36 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
    layer->alpha = alpha;
    layer->mode = mode;


#if RENDER_LAYERS_AS_REGIONS
    if (layer->region.isRect()) {
        const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
        composeLayerRect(layer, r);
    } else if (!layer->region.isEmpty() && layer->mesh) {
        const Rect& rect = layer->layer;

        setupDraw();
        setupDrawWithTexture();
        setupDrawColor(alpha, alpha, alpha, alpha);
        setupDrawColorFilter();
        setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
        setupDrawProgram();
        setupDrawDirtyRegionsDisabled();
        setupDrawPureColorUniforms();
        setupDrawColorFilterUniforms();
        setupDrawTexture(layer->texture);
        setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
        setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);

        glDrawElements(GL_TRIANGLES, layer->meshElementCount,
                GL_UNSIGNED_SHORT, layer->meshIndices);

        finishDrawTexture();
    }
#else
    const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
    composeLayerRect(layer, r);
#endif
}

///////////////////////////////////////////////////////////////////////////////
+26 −8
Original line number Diff line number Diff line
@@ -133,19 +133,24 @@ protected:
    virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);

    /**
     * Mark the layer as dirty at the specified coordinates. The coordinates
     * are transformed with the supplied matrix.
     * Marks the specified region as dirty at the specified bounds.
     */
    virtual void dirtyLayer(const float left, const float top,
            const float right, const float bottom, const mat4 transform);
    void dirtyLayerUnchecked(Rect& bounds, Region* region);

    /**
     * Mark the layer as dirty at the specified coordinates.
     * Returns the current snapshot.
     */
    virtual void dirtyLayer(const float left, const float top,
            const float right, const float bottom);
    sp<Snapshot> getSnapshot() {
        return mSnapshot;
    }

    void dirtyLayerUnchecked(Rect& bounds, Region* region);
    virtual Region* getRegion() {
        return mSnapshot->region;
    }

    virtual bool hasLayer() {
        return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
    }

private:
    /**
@@ -224,6 +229,19 @@ private:
     */
    void clearLayerRegions();

    /**
     * Mark the layer as dirty at the specified coordinates. The coordinates
     * are transformed with the supplied matrix.
     */
    void dirtyLayer(const float left, const float top,
            const float right, const float bottom, const mat4 transform);

    /**
     * Mark the layer as dirty at the specified coordinates.
     */
    void dirtyLayer(const float left, const float top,
            const float right, const float bottom);

    /**
     * Draws a colored rectangle with the specified color. The specified coordinates
     * are transformed by the current snapshot's transform matrix.
Loading