void Layer::defer(const OpenGLRenderer& rootRenderer) {
    ATRACE_LAYER_WORK("Optimize");

    updateLightPosFromRenderer(rootRenderer);
    const float width = layer.getWidth();
    const float height = layer.getHeight();

    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
        dirtyRect.set(0, 0, width, height);
    }

    deferredList.reset(new DeferredDisplayList(dirtyRect));

    DeferStateStruct deferredState(*deferredList, *renderer,
            RenderNode::kReplayFlag_ClipChildren);

    renderer->setViewport(width, height);
    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
            dirtyRect.right, dirtyRect.bottom, !isBlend());

    renderNode->computeOrdering();
    renderNode->defer(deferredState, 0);

    deferredUpdateScheduled = false;
}
void Layer::defer() {
    const float width = layer.getWidth();
    const float height = layer.getHeight();

    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
        dirtyRect.set(0, 0, width, height);
    }

    if (deferredList) {
        deferredList->reset(dirtyRect);
    } else {
        deferredList = new DeferredDisplayList(dirtyRect);
    }
    DeferStateStruct deferredState(*deferredList, *renderer,
            DisplayList::kReplayFlag_ClipChildren);

    renderer->initViewport(width, height);
    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
            dirtyRect.right, dirtyRect.bottom, !isBlend());

    displayList->defer(deferredState, 0);

    deferredUpdateScheduled = false;
}
void Layer::render() {
    renderer->setViewport(layer.getWidth(), layer.getHeight());
    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
            !isBlend());

    renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);

    renderer->finish();
    renderer = NULL;

    dirtyRect.setEmpty();

    deferredUpdateScheduled = false;
    displayList = NULL;
}
void Layer::flush() {
    if (deferredList) {
        renderer->setViewport(layer.getWidth(), layer.getHeight());
        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
                !isBlend());

        deferredList->flush(*renderer, dirtyRect);

        renderer->finish();
        renderer = NULL;

        dirtyRect.setEmpty();
        displayList = NULL;
    }
}
void Layer::render(const OpenGLRenderer& rootRenderer) {
    ATRACE_LAYER_WORK("Direct-Issue");

    updateLightPosFromRenderer(rootRenderer);
    renderer->prepareDirty(layer.getWidth(), layer.getHeight(),
            dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend());

    renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);

    renderer->finish();

    dirtyRect.setEmpty();

    deferredUpdateScheduled = false;
    renderNode = nullptr;
}
void Layer::flush() {
    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
    if (deferredList && renderer) {
        renderer->setViewport(layer.getWidth(), layer.getHeight());
        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
                !isBlend());

        deferredList->flush(*renderer, dirtyRect);

        renderer->finish();
        renderer = NULL;

        dirtyRect.setEmpty();
        displayList = NULL;
    }
}
void Layer::flush() {
    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
    if (deferredList && renderer) {
        ATRACE_LAYER_WORK("Issue");
        renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer");

        renderer->prepareDirty(layer.getWidth(), layer.getHeight(),
                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend());

        deferredList->flush(*renderer, dirtyRect);

        renderer->finish();

        dirtyRect.setEmpty();
        renderNode = nullptr;

        renderer->endMark();
    }
}