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

Commit 818c9fbf authored by Chris Craik's avatar Chris Craik
Browse files

Initial version of clipped saveLayer in new pipeline

Additionally disables usage of FBO cache, so FBO destruction safely
interacts with renderstate caching.

Change-Id: I25c277cb7afec2ca33bf226445d6c8867a15a915
parent 914e362d
Loading
Loading
Loading
Loading
+82 −4
Original line number Diff line number Diff line
@@ -25,6 +25,15 @@
namespace android {
namespace uirenderer {

void BakedOpRenderer::Info::setViewport(uint32_t width, uint32_t height) {
    viewportWidth = width;
    viewportHeight = height;
    orthoMatrix.loadOrtho(viewportWidth, viewportHeight);

    renderState.setViewport(width, height);
    renderState.blend().syncEnabled();
}

Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) {
    Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap);
    if (!texture) {
@@ -45,9 +54,54 @@ void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& gl
    didDraw = true;
}

void BakedOpRenderer::startFrame(Info& info) {
    info.renderState.setViewport(info.viewportWidth, info.viewportHeight);
    info.renderState.blend().syncEnabled();
Layer* BakedOpRenderer::startLayer(Info& info, uint32_t width, uint32_t height) {
    info.caches.textureState().activateTexture(0);
    Layer* layer = info.caches.layerCache.get(info.renderState, width, height);
    LOG_ALWAYS_FATAL_IF(!layer, "need layer...");

    info.layer = layer;
    layer->texCoords.set(0.0f, width / float(layer->getHeight()),
            height / float(layer->getWidth()), 0.0f);

    layer->setFbo(info.renderState.genFramebuffer());
    info.renderState.bindFramebuffer(layer->getFbo());
    layer->bindTexture();

    // Initialize the texture if needed
    if (layer->isEmpty()) {
        layer->allocateTexture();
        layer->setEmpty(false);
    }

    // attach the texture to the FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
            layer->getTextureId(), 0);
    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
    LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
            "framebuffer incomplete!");

    // Clear the FBO
    info.renderState.scissor().setEnabled(false);
    glClear(GL_COLOR_BUFFER_BIT);

    // Change the viewport & ortho projection
    info.setViewport(width, height);
    return layer;
}

void BakedOpRenderer::endLayer(Info& info) {
    Layer* layer = info.layer;
    info.layer = nullptr;

    // Detach the texture from the FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
    layer->removeFbo(false);
}

void BakedOpRenderer::startFrame(Info& info, uint32_t width, uint32_t height) {
    info.renderState.bindFramebuffer(0);
    info.setViewport(width, height);
    Caches::getInstance().clearGarbage();

    if (!info.opaque) {
@@ -130,7 +184,31 @@ void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const Baked
}

void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) {
    LOG_ALWAYS_FATAL("unsupported operation");
    Layer* layer = *op.layerHandle;

    // TODO: make this work for HW layers
    layer->setPaint(op.paint);
    layer->setBlend(true);
    float layerAlpha = (layer->getAlpha() / 255.0f) * state.alpha;

    const bool tryToSnap = state.computedState.transform.isPureTranslate();
    Glop glop;
    GlopBuilder(info.renderState, info.caches, &glop)
            .setRoundRectClipState(state.roundRectClipState)
            .setMeshTexturedUvQuad(nullptr, layer->texCoords)
            .setFillLayer(layer->getTexture(), layer->getColorFilter(), layerAlpha, layer->getMode(), Blend::ModeOrderSwap::NoSwap)
            .setTransform(state.computedState.transform, TransformFlags::None)
            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
            .build();
    info.renderGlop(state, glop);

    // return layer to cache, since each clipped savelayer is only drawn once.
    layer->setConvexMask(nullptr);
    if (!info.caches.layerCache.put(layer)) {
        // Failing to add the layer to the cache should happen only if the layer is too large
        LAYER_LOGD("Deleting layer");
        layer->decStrong(nullptr);
    }
}

} // namespace uirenderer
+12 −9
Original line number Diff line number Diff line
@@ -25,21 +25,21 @@ namespace uirenderer {

class Caches;
struct Glop;
class Layer;
class RenderState;

class BakedOpRenderer {
public:
    class Info {
    public:
        Info(Caches& caches, RenderState& renderState, int viewportWidth, int viewportHeight, bool opaque)
        Info(Caches& caches, RenderState& renderState, bool opaque)
                : renderState(renderState)
                , caches(caches)
                , opaque(opaque)
                , viewportWidth(viewportWidth)
                , viewportHeight(viewportHeight) {
            orthoMatrix.loadOrtho(viewportWidth, viewportHeight);
                , opaque(opaque) {
        }

        void setViewport(uint32_t width, uint32_t height);

        Texture* getTexture(const SkBitmap* bitmap);

        void renderGlop(const BakedOpState& state, const Glop& glop);
@@ -47,16 +47,19 @@ public:
        Caches& caches;

        bool didDraw = false;
        bool opaque;

        Layer* layer = nullptr;

        // where should these live? layer state object?
        int viewportWidth;
        int viewportHeight;
        bool opaque;
        uint32_t viewportWidth = 0;
        uint32_t viewportHeight = 0;
        Matrix4 orthoMatrix;
    };

    static void startFrame(Info& info);
    static Layer* startLayer(Info& info, uint32_t width, uint32_t height);
    static void endLayer(Info& info);
    static void startFrame(Info& info, uint32_t width, uint32_t height);
    static void endFrame(Info& info);

    /**
+1 −2
Original line number Diff line number Diff line
@@ -155,8 +155,7 @@ void Layer::removeFbo(bool flush) {

    if (fbo) {
        if (flush) LayerRenderer::flushLayer(renderState, this);
        // If put fails the cache will delete the FBO
        caches.fboCache.put(fbo);
        renderState.deleteFramebuffer(fbo);
        fbo = 0;
    }
}
+4 −4
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
    LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);

    Caches& caches = Caches::getInstance();
    GLuint fbo = caches.fboCache.get();
    GLuint fbo = renderState.genFramebuffer();
    if (!fbo) {
        ALOGW("Could not obtain an FBO");
        return nullptr;
@@ -204,7 +204,7 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width

    // We first obtain a layer before comparing against the max texture size
    // because layers are not allocated at the exact desired size. They are
    // always created slighly larger to improve recycling
    // always created slightly larger to improve recycling
    const uint32_t maxTextureSize = caches.maxTextureSize;
    if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) {
        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
@@ -357,7 +357,7 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap*
            && bitmap->width() <= caches.maxTextureSize
            && bitmap->height() <= caches.maxTextureSize) {

        GLuint fbo = caches.fboCache.get();
        GLuint fbo = renderState.getFramebuffer();
        if (!fbo) {
            ALOGW("Could not obtain an FBO");
            return false;
@@ -465,7 +465,7 @@ error:
        layer->setAlpha(alpha, mode);
        layer->setFbo(previousLayerFbo);
        caches.textureState().deleteTexture(texture);
        caches.fboCache.put(fbo);
        renderState.deleteFramebuffer(fbo);
        renderState.setViewport(previousViewportWidth, previousViewportHeight);

        return status;
+23 −20
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ private:
};

// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still interate to find similar batch to insert after
// if no target, merging ops still iterate to find similar batch to insert after
void OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
        BatchBase** targetBatch, size_t* insertBatchIndex) const {
    for (int i = mBatches.size() - 1; i >= 0; i--) {
@@ -292,18 +292,14 @@ void OpReorderer::LayerReorderer::dump() const {
    }
}

OpReorderer::OpReorderer()
OpReorderer::OpReorderer(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
        const std::vector< sp<RenderNode> >& nodes)
        : mCanvasState(*this) {
    mLayerReorderers.emplace_back();
    mLayerStack.push_back(0);
}

void OpReorderer::onViewportInitialized() {}
    ATRACE_NAME("prepare drawing commands");

void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
    mLayerStack.push_back(0);

void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight,
        const std::vector< sp<RenderNode> >& nodes) {
    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
            clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
            Vector3());
@@ -321,13 +317,22 @@ void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeigh
    }
}

void OpReorderer::defer(int viewportWidth, int viewportHeight, const DisplayList& displayList) {
OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList)
        : mCanvasState(*this) {
    ATRACE_NAME("prepare drawing commands");

    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
    mLayerStack.push_back(0);

    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
            0, 0, viewportWidth, viewportHeight, Vector3());
    deferImpl(displayList);
}

void OpReorderer::onViewportInitialized() {}

void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}

/**
 * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
 *
@@ -350,11 +355,6 @@ void OpReorderer::deferImpl(const DisplayList& displayList) {

void OpReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) {
    ATRACE_NAME("flush drawing commands");
    // Relay through layers in reverse order, since layers
    // later in the list will be drawn by earlier ones
    for (int i = mLayerReorderers.size() - 1; i >= 0; i--) {
        mLayerReorderers[i].replayBakedOpsImpl(arg, receivers);
    }
}

void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
@@ -405,15 +405,17 @@ void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) {

// TODO: test rejection at defer time, where the bounds become empty
void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) {
    const uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
    const uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();

    mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
    mCanvasState.writableSnapshot()->transform->loadIdentity();
    mCanvasState.writableSnapshot()->initializeViewport(
            (int) op.unmappedBounds.getWidth(), (int) op.unmappedBounds.getHeight());
    mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
    mCanvasState.writableSnapshot()->roundRectClipState = nullptr;

    // create a new layer, and push its index on the stack
    mLayerStack.push_back(mLayerReorderers.size());
    mLayerReorderers.emplace_back();
    mLayerReorderers.emplace_back(layerWidth, layerHeight);
    mLayerReorderers.back().beginLayerOp = &op;
}

@@ -432,7 +434,8 @@ void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) {
            beginLayerOp.unmappedBounds,
            beginLayerOp.localMatrix,
            beginLayerOp.localClipRect,
            beginLayerOp.paint);
            beginLayerOp.paint,
            &mLayerReorderers[finishedLayerIndex].layer);
    BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);

    if (bakedOpState) {
Loading