RenderNode.cpp revision 182952f5eeefc2a21d76d4664ada0e2d78c1105c
179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong/*
279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * Copyright (C) 2014 The Android Open Source Project
379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong *
479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * Licensed under the Apache License, Version 2.0 (the "License");
579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * you may not use this file except in compliance with the License.
679f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * You may obtain a copy of the License at
779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong *
879f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong *      http://www.apache.org/licenses/LICENSE-2.0
979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong *
1079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * Unless required by applicable law or agreed to in writing, software
1179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * distributed under the License is distributed on an "AS IS" BASIS,
1279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * See the License for the specific language governing permissions and
1479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong * limitations under the License.
1579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong */
1679f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
1779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong#define ATRACE_TAG ATRACE_TAG_VIEW
1879f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong#define LOG_TAG "OpenGLRenderer"
1979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
2079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong#include "RenderNode.h"
2179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
2279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong#include <algorithm>
2388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <string>
2488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
2588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <SkCanvas.h>
2688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <algorithm>
278d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber
288d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber
2979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong#include "DamageAccumulator.h"
3079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong#include "Debug.h"
3115ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "DisplayListOp.h"
3215ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "LayerRenderer.h"
3315ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "OpenGLRenderer.h"
3415ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "TreeInfo.h"
3515ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "utils/MathUtils.h"
3615ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "utils/TraceUtils.h"
3715ef59e081846b43660635391d536361c3253a22Jaesung Chung#include "renderthread/CanvasContext.h"
3815ef59e081846b43660635391d536361c3253a22Jaesung Chung
3915ef59e081846b43660635391d536361c3253a22Jaesung Chungnamespace android {
4015ef59e081846b43660635391d536361c3253a22Jaesung Chungnamespace uirenderer {
4115ef59e081846b43660635391d536361c3253a22Jaesung Chung
4215ef59e081846b43660635391d536361c3253a22Jaesung Chungvoid RenderNode::debugDumpLayers(const char* prefix) {
4315ef59e081846b43660635391d536361c3253a22Jaesung Chung    if (mLayer) {
448409c0691fb128fef6244305977342776bddf919Jaesung Chung        ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)",
458409c0691fb128fef6244305977342776bddf919Jaesung Chung                prefix, this, getName(), mLayer, mLayer->getFbo(),
468409c0691fb128fef6244305977342776bddf919Jaesung Chung                mLayer->wasBuildLayered ? "true" : "false");
478409c0691fb128fef6244305977342776bddf919Jaesung Chung    }
488409c0691fb128fef6244305977342776bddf919Jaesung Chung    if (mDisplayListData) {
498409c0691fb128fef6244305977342776bddf919Jaesung Chung        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
508409c0691fb128fef6244305977342776bddf919Jaesung Chung            mDisplayListData->children()[i]->mRenderNode->debugDumpLayers(prefix);
518409c0691fb128fef6244305977342776bddf919Jaesung Chung        }
528409c0691fb128fef6244305977342776bddf919Jaesung Chung    }
538409c0691fb128fef6244305977342776bddf919Jaesung Chung}
548409c0691fb128fef6244305977342776bddf919Jaesung Chung
558409c0691fb128fef6244305977342776bddf919Jaesung ChungRenderNode::RenderNode()
568409c0691fb128fef6244305977342776bddf919Jaesung Chung        : mDirtyPropertyFields(0)
578409c0691fb128fef6244305977342776bddf919Jaesung Chung        , mNeedsDisplayListDataSync(false)
588409c0691fb128fef6244305977342776bddf919Jaesung Chung        , mDisplayListData(nullptr)
598409c0691fb128fef6244305977342776bddf919Jaesung Chung        , mStagingDisplayListData(nullptr)
608409c0691fb128fef6244305977342776bddf919Jaesung Chung        , mAnimatorManager(*this)
618409c0691fb128fef6244305977342776bddf919Jaesung Chung        , mLayer(nullptr)
628409c0691fb128fef6244305977342776bddf919Jaesung Chung        , mParentCount(0) {
638409c0691fb128fef6244305977342776bddf919Jaesung Chung}
648409c0691fb128fef6244305977342776bddf919Jaesung Chung
658409c0691fb128fef6244305977342776bddf919Jaesung ChungRenderNode::~RenderNode() {
668409c0691fb128fef6244305977342776bddf919Jaesung Chung    deleteDisplayListData();
678409c0691fb128fef6244305977342776bddf919Jaesung Chung    delete mStagingDisplayListData;
688409c0691fb128fef6244305977342776bddf919Jaesung Chung    if (mLayer) {
698409c0691fb128fef6244305977342776bddf919Jaesung Chung        ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer);
708409c0691fb128fef6244305977342776bddf919Jaesung Chung        mLayer->postDecStrong();
718409c0691fb128fef6244305977342776bddf919Jaesung Chung        mLayer = nullptr;
728409c0691fb128fef6244305977342776bddf919Jaesung Chung    }
738409c0691fb128fef6244305977342776bddf919Jaesung Chung}
748409c0691fb128fef6244305977342776bddf919Jaesung Chung
758409c0691fb128fef6244305977342776bddf919Jaesung Chungvoid RenderNode::setStagingDisplayList(DisplayListData* data) {
768409c0691fb128fef6244305977342776bddf919Jaesung Chung    mNeedsDisplayListDataSync = true;
778409c0691fb128fef6244305977342776bddf919Jaesung Chung    delete mStagingDisplayListData;
788409c0691fb128fef6244305977342776bddf919Jaesung Chung    mStagingDisplayListData = data;
798409c0691fb128fef6244305977342776bddf919Jaesung Chung}
808409c0691fb128fef6244305977342776bddf919Jaesung Chung
818409c0691fb128fef6244305977342776bddf919Jaesung Chung/**
828409c0691fb128fef6244305977342776bddf919Jaesung Chung * This function is a simplified version of replay(), where we simply retrieve and log the
838409c0691fb128fef6244305977342776bddf919Jaesung Chung * display list. This function should remain in sync with the replay() function.
848409c0691fb128fef6244305977342776bddf919Jaesung Chung */
858409c0691fb128fef6244305977342776bddf919Jaesung Chungvoid RenderNode::output(uint32_t level) {
868409c0691fb128fef6244305977342776bddf919Jaesung Chung    ALOGD("%*sStart display list (%p, %s%s%s%s)", (level - 1) * 2, "", this,
878409c0691fb128fef6244305977342776bddf919Jaesung Chung            getName(),
888409c0691fb128fef6244305977342776bddf919Jaesung Chung            (properties().hasShadow() ? ", casting shadow" : ""),
898409c0691fb128fef6244305977342776bddf919Jaesung Chung            (isRenderable() ? "" : ", empty"),
908409c0691fb128fef6244305977342776bddf919Jaesung Chung            (mLayer != nullptr ? ", on HW Layer" : ""));
918409c0691fb128fef6244305977342776bddf919Jaesung Chung    ALOGD("%*s%s %d", level * 2, "", "Save",
928409c0691fb128fef6244305977342776bddf919Jaesung Chung            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
938409c0691fb128fef6244305977342776bddf919Jaesung Chung
948409c0691fb128fef6244305977342776bddf919Jaesung Chung    properties().debugOutputProperties(level);
958409c0691fb128fef6244305977342776bddf919Jaesung Chung    int flags = DisplayListOp::kOpLogFlag_Recurse;
96d4c505c9b4d5b0e743301e3f385895efdb9785d4Jaesung Chung    if (mDisplayListData) {
978f7a8f1eba590f4a0bb21988fc2a876dcb72dccdAnton Daubert        // TODO: consider printing the chunk boundaries here
988f7a8f1eba590f4a0bb21988fc2a876dcb72dccdAnton Daubert        for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
998409c0691fb128fef6244305977342776bddf919Jaesung Chung            mDisplayListData->displayListOps[i]->output(level, flags);
1008409c0691fb128fef6244305977342776bddf919Jaesung Chung        }
1018409c0691fb128fef6244305977342776bddf919Jaesung Chung    }
1028409c0691fb128fef6244305977342776bddf919Jaesung Chung
1038409c0691fb128fef6244305977342776bddf919Jaesung Chung    ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
1048409c0691fb128fef6244305977342776bddf919Jaesung Chung}
1058409c0691fb128fef6244305977342776bddf919Jaesung Chung
1068409c0691fb128fef6244305977342776bddf919Jaesung Chungint RenderNode::getDebugSize() {
1078409c0691fb128fef6244305977342776bddf919Jaesung Chung    int size = sizeof(RenderNode);
1088409c0691fb128fef6244305977342776bddf919Jaesung Chung    if (mStagingDisplayListData) {
1098409c0691fb128fef6244305977342776bddf919Jaesung Chung        size += mStagingDisplayListData->getUsedSize();
1108409c0691fb128fef6244305977342776bddf919Jaesung Chung    }
1118409c0691fb128fef6244305977342776bddf919Jaesung Chung    if (mDisplayListData && mDisplayListData != mStagingDisplayListData) {
1128409c0691fb128fef6244305977342776bddf919Jaesung Chung        size += mDisplayListData->getUsedSize();
1138409c0691fb128fef6244305977342776bddf919Jaesung Chung    }
1148409c0691fb128fef6244305977342776bddf919Jaesung Chung    return size;
1158409c0691fb128fef6244305977342776bddf919Jaesung Chung}
1168409c0691fb128fef6244305977342776bddf919Jaesung Chung
1178409c0691fb128fef6244305977342776bddf919Jaesung Chungvoid RenderNode::prepareTree(TreeInfo& info) {
1188409c0691fb128fef6244305977342776bddf919Jaesung Chung    ATRACE_CALL();
1198409c0691fb128fef6244305977342776bddf919Jaesung Chung    LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
1208409c0691fb128fef6244305977342776bddf919Jaesung Chung
1218409c0691fb128fef6244305977342776bddf919Jaesung Chung    prepareTreeImpl(info);
1228409c0691fb128fef6244305977342776bddf919Jaesung Chung}
1238409c0691fb128fef6244305977342776bddf919Jaesung Chung
1248409c0691fb128fef6244305977342776bddf919Jaesung Chungvoid RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
1258409c0691fb128fef6244305977342776bddf919Jaesung Chung    mAnimatorManager.addAnimator(animator);
1268409c0691fb128fef6244305977342776bddf919Jaesung Chung}
1278409c0691fb128fef6244305977342776bddf919Jaesung Chung
1288409c0691fb128fef6244305977342776bddf919Jaesung Chungvoid RenderNode::damageSelf(TreeInfo& info) {
12979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    if (isRenderable()) {
13079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        if (properties().getClipDamageToBounds()) {
13179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
13279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        } else {
13379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            // Hope this is big enough?
13479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            // TODO: Get this from the display list ops or something
13579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            info.damageAccumulator->dirty(INT_MIN, INT_MIN, INT_MAX, INT_MAX);
13679f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        }
13779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    }
13879f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong}
13979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
14079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dongvoid RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {
14179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    LayerType layerType = properties().layerProperties().type();
14279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    if (CC_UNLIKELY(layerType == LayerType::RenderLayer)) {
14379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        // Damage applied so far needs to affect our parent, but does not require
14479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        // the layer to be updated. So we pop/push here to clear out the current
14579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        // damage and get a clean state for display list or children updates to
1463762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        // affect, which will require the layer to be updated
14779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        info.damageAccumulator->popTransform();
14879f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        info.damageAccumulator->pushTransform(this);
14979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        if (dirtyMask & DISPLAY_LIST) {
15079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            damageSelf(info);
15179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        }
15279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    }
15379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong}
15479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
15579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dongvoid RenderNode::pushLayerUpdate(TreeInfo& info) {
15679f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    LayerType layerType = properties().layerProperties().type();
15779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    // If we are not a layer OR we cannot be rendered (eg, view was detached)
15879f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    // we need to destroy any Layers we may have had previously
15979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable())) {
16079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        if (CC_UNLIKELY(mLayer)) {
16179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            LayerRenderer::destroyLayer(mLayer);
16279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            mLayer = nullptr;
16379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        }
16479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        return;
16579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    }
16679f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
16779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    bool transformUpdateNeeded = false;
16879f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    if (!mLayer) {
16979f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        mLayer = LayerRenderer::createRenderLayer(info.renderState, getWidth(), getHeight());
17079f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        applyLayerPropertiesToLayer(info);
17179f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        damageSelf(info);
17279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        transformUpdateNeeded = true;
17379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
17479f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
17579f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            LayerRenderer::destroyLayer(mLayer);
17679f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong            mLayer = nullptr;
17779f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong        }
17888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        damageSelf(info);
1798d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        transformUpdateNeeded = true;
1808d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    }
18188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
1828d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    SkRect dirty;
1838d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    info.damageAccumulator->peekAtDirty(&dirty);
18488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
18588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (!mLayer) {
1868d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        Caches::getInstance().dumpMemoryUsage();
18788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        if (info.errorHandler) {
18888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            std::string msg = "Unable to create layer for ";
18907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            msg += getName();
1908d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            info.errorHandler->onError(msg);
1918d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        }
19207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        return;
1938d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    }
19407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
19507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    if (transformUpdateNeeded) {
1968d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        // update the transform in window of the layer to reset its origin wrt light source position
19707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        Matrix4 windowTransform;
19807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        info.damageAccumulator->computeCurrentTransform(&windowTransform);
19988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        mLayer->setWindowTransform(windowTransform);
2008d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    }
2018d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber
20288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (dirty.intersect(0, 0, getWidth(), getHeight())) {
2038d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        dirty.roundOut(&dirty);
2048d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
20588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
20688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // This is not inside the above if because we may have called
2078d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    // updateDeferred on a previous prepare pass that didn't have a renderer
20888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (info.renderer && mLayer->deferredUpdateScheduled) {
20988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        info.renderer->pushLayerUpdate(mLayer);
21088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
21188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
21288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (CC_UNLIKELY(info.canvasContext)) {
21388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // If canvasContext is not null that means there are prefetched layers
21488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // that need to be accounted for. That might be us, so tell CanvasContext
2158d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        // that this layer is in the tree and should not be destroyed.
2168d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        info.canvasContext->markLayerInUse(this);
21788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
21888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
2198d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber
2208d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Hubervoid RenderNode::prepareTreeImpl(TreeInfo& info) {
22188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    info.damageAccumulator->pushTransform(this);
22288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
22388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (info.mode == TreeInfo::MODE_FULL) {
2248d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        pushStagingPropertiesChanges(info);
22588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
22688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    uint32_t animatorDirtyMask = 0;
22788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (CC_LIKELY(info.runAnimations)) {
22888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        animatorDirtyMask = mAnimatorManager.animate(info);
22988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
23088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    prepareLayer(info, animatorDirtyMask);
231b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    if (info.mode == TreeInfo::MODE_FULL) {
232b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        pushStagingDisplayListChanges(info);
233b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    }
234b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    prepareSubTree(info, mDisplayListData);
235b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    pushLayerUpdate(info);
236b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber
2375a15d0d31b877ef512b3379eac033c6bb041c86aAndreas Gampe    info.damageAccumulator->popTransform();
238b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber}
239b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber
240b842599e51e2d3611503c3c7db1111358f99186dAndreas Hubervoid RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
241b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    // Push the animators first so that setupStartValueIfNecessary() is called
242b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    // before properties() is trampled by stagingProperties(), as they are
24388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // required by some animators.
24488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (CC_LIKELY(info.runAnimations)) {
2458d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        mAnimatorManager.pushStaging();
2468d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    }
24788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (mDirtyPropertyFields) {
2488d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        mDirtyPropertyFields = 0;
24988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        damageSelf(info);
25088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        info.damageAccumulator->popTransform();
25188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        mProperties = mStagingProperties;
25288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        applyLayerPropertiesToLayer(info);
2538d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        // We could try to be clever and only re-damage if the matrix changed.
25488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // However, we don't need to worry about that. The cost of over-damaging
25588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // here is only going to be a single additional map rect of this node
25688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // plus a rect join(). The parent's transform (and up) will only be
25788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // performed once.
25888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        info.damageAccumulator->pushTransform(this);
25988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        damageSelf(info);
26088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
2618d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber}
26288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
26388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubervoid RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
26488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (CC_LIKELY(!mLayer)) return;
26588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
26688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    const LayerProperties& props = properties().layerProperties();
26788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mLayer->setAlpha(props.alpha(), props.xferMode());
26888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mLayer->setColorFilter(props.colorFilter());
2698d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    mLayer->setBlend(props.needsBlending());
27088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
27188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
27288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubervoid RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
27388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (mNeedsDisplayListDataSync) {
27488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        mNeedsDisplayListDataSync = false;
27588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // Make sure we inc first so that we don't fluctuate between 0 and 1,
27688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // which would thrash the layer cache
27788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        if (mStagingDisplayListData) {
27888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            for (size_t i = 0; i < mStagingDisplayListData->children().size(); i++) {
27988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount();
28088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            }
28188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
28288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // Damage with the old display list first then the new one to catch any
28388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        // changes in isRenderable or, in the future, bounds
28407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        damageSelf(info);
28507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        deleteDisplayListData();
28607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        // TODO: Remove this caches stuff
28707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        if (mStagingDisplayListData && mStagingDisplayListData->functors.size()) {
28807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            Caches::getInstance().registerFunctors(mStagingDisplayListData->functors.size());
28907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        }
29007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        mDisplayListData = mStagingDisplayListData;
29107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        mStagingDisplayListData = nullptr;
29207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        if (mDisplayListData) {
29388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
29488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
29588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            }
29688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
29788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        damageSelf(info);
29888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
29988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
30088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
30188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubervoid RenderNode::deleteDisplayListData() {
30288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (mDisplayListData) {
30388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
30488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            mDisplayListData->children()[i]->mRenderNode->decParentRefCount();
30588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
30688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        if (mDisplayListData->functors.size()) {
30788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            Caches::getInstance().unregisterFunctors(mDisplayListData->functors.size());
30888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
30988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
31088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    delete mDisplayListData;
31188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mDisplayListData = nullptr;
31288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
31388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3145c850396b39a57baabd37a9c0c8324f1bee408caAndreas Hubervoid RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
31588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (subtree) {
3165c850396b39a57baabd37a9c0c8324f1bee408caAndreas Huber        TextureCache& cache = Caches::getInstance().textureCache;
3175c850396b39a57baabd37a9c0c8324f1bee408caAndreas Huber        info.out.hasFunctors |= subtree->functors.size();
31888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
31988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
32088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
32188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        for (size_t i = 0; i < subtree->children().size(); i++) {
32288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            DrawRenderNodeOp* op = subtree->children()[i];
32388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            RenderNode* childNode = op->mRenderNode;
324b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            info.damageAccumulator->pushTransform(&op->mTransformFromParent);
325b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            childNode->prepareTreeImpl(info);
326b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            info.damageAccumulator->popTransform();
327b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        }
328b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    }
329b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber}
330b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber
331b842599e51e2d3611503c3c7db1111358f99186dAndreas Hubervoid RenderNode::destroyHardwareResources() {
332b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    if (mLayer) {
333f953ca2ec8e418d54ab7d4585302db22964bcb70Elliott Hughes        LayerRenderer::destroyLayer(mLayer);
334b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        mLayer = nullptr;
335b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    }
336b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    if (mDisplayListData) {
337b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
338b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            mDisplayListData->children()[i]->mRenderNode->destroyHardwareResources();
339b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        }
340f953ca2ec8e418d54ab7d4585302db22964bcb70Elliott Hughes        if (mNeedsDisplayListDataSync) {
341b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            // Next prepare tree we are going to push a new display list, so we can
342b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            // drop our current one now
343b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber            deleteDisplayListData();
344b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        }
345b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    }
346b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber}
347f953ca2ec8e418d54ab7d4585302db22964bcb70Elliott Hughes
348b842599e51e2d3611503c3c7db1111358f99186dAndreas Hubervoid RenderNode::decParentRefCount() {
349b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
350b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    mParentCount--;
351b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    if (!mParentCount) {
352b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        // If a child of ours is being attached to our parent then this will incorrectly
353b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        // destroy its hardware resources. However, this situation is highly unlikely
354f953ca2ec8e418d54ab7d4585302db22964bcb70Elliott Hughes        // and the failure is "just" that the layer is re-created, so this should
355b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        // be safe enough
356b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber        destroyHardwareResources();
357b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber    }
358b842599e51e2d3611503c3c7db1111358f99186dAndreas Huber}
35988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
36088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber/*
36188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * For property operations, we pass a savecount of 0, since the operations aren't part of the
36288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
36388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * base saveCount (i.e., how RestoreToCount uses saveCount + properties().getCount())
36488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber */
36588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#define PROPERTY_SAVECOUNT 0
3665a15d0d31b877ef512b3379eac033c6bb041c86aAndreas Gampe
36788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubertemplate <class T>
36888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubervoid RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
36988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#if DEBUG_DISPLAY_LIST
37088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    properties().debugOutputProperties(handler.level() + 1);
37188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#endif
37288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (properties().getLeft() != 0 || properties().getTop() != 0) {
37388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        renderer.translate(properties().getLeft(), properties().getTop());
37488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
37588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (properties().getStaticMatrix()) {
37688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        renderer.concatMatrix(*properties().getStaticMatrix());
37788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    } else if (properties().getAnimationMatrix()) {
37888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        renderer.concatMatrix(*properties().getAnimationMatrix());
37988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
38088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (properties().hasTransformMatrix()) {
3818d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        if (properties().isTransformTranslateOnly()) {
3828d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            renderer.translate(properties().getTranslationX(), properties().getTranslationY());
3838d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        } else {
3848d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            renderer.concatMatrix(*properties().getTransformMatrix());
3858d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        }
3868d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    }
3878d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    const bool isLayer = properties().layerProperties().type() != LayerType::None;
3888d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    int clipFlags = properties().getClippingFlags();
3898d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    if (properties().getAlpha() < 1) {
3908d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        if (isLayer) {
39188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
39288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
39388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            renderer.setOverrideLayerAlpha(properties().getAlpha());
39488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        } else if (!properties().getHasOverlappingRendering()) {
39588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            renderer.scaleAlpha(properties().getAlpha());
39688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        } else {
39788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            Rect layerBounds(0, 0, getWidth(), getHeight());
39888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
39988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            if (clipFlags) {
40088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
40188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                properties().getClippingRectForFlags(clipFlags, &layerBounds);
40288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                clipFlags = 0; // all clipping done by saveLayer
40388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            }
40488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
40588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            ATRACE_FORMAT("%s alpha caused %ssaveLayer %dx%d", getName(),
40688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                    (saveFlags & SkCanvas::kClipToLayer_SaveFlag) ? "" : "unclipped ",
40788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                    static_cast<int>(layerBounds.getWidth()),
40888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                    static_cast<int>(layerBounds.getHeight()));
40988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
41088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
41188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                    layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
41288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                    properties().getAlpha() * 255, saveFlags);
4138d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
41488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
41588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
41688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (clipFlags) {
41788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        Rect clipRect;
41888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        properties().getClippingRectForFlags(clipFlags, &clipRect);
41988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        ClipRectOp* op = new (handler.allocator()) ClipRectOp(
42088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
42188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                SkRegion::kIntersect_Op);
42288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
42388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
42488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
42588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // TODO: support nesting round rect clips
42688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (mProperties.getRevealClip().willClip()) {
42788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        Rect bounds;
42888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        mProperties.getRevealClip().getBounds(&bounds);
42988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        renderer.setClippingRoundRect(handler.allocator(), bounds, mProperties.getRevealClip().getRadius());
4308d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    } else if (mProperties.getOutline().willClip()) {
43188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline()));
43288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
43388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
43488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
43588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber/**
43688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Apply property-based transformations to input matrix
43788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
43888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4
43988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * matrix computation instead of the Skia 3x3 matrix + camera hackery.
44088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber */
4418d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Hubervoid RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) const {
44288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (properties().getLeft() != 0 || properties().getTop() != 0) {
4438d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        matrix.translate(properties().getLeft(), properties().getTop());
44488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
44588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (properties().getStaticMatrix()) {
44688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        mat4 stat(*properties().getStaticMatrix());
44788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        matrix.multiply(stat);
44888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    } else if (properties().getAnimationMatrix()) {
4498d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        mat4 anim(*properties().getAnimationMatrix());
4508d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        matrix.multiply(anim);
4518d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    }
4528d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber
4538d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getZ());
4548d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    if (properties().hasTransformMatrix() || applyTranslationZ) {
4558d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        if (properties().isTransformTranslateOnly()) {
4568d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
4578d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber                    true3dTransform ? properties().getZ() : 0.0f);
45888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        } else {
4598d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            if (!true3dTransform) {
46088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                matrix.multiply(*properties().getTransformMatrix());
46188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            } else {
46288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                mat4 true3dMat;
46388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                true3dMat.loadTranslate(
46488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                        properties().getPivotX() + properties().getTranslationX(),
4658d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber                        properties().getPivotY() + properties().getTranslationY(),
46688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                        properties().getZ());
4678d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber                true3dMat.rotate(properties().getRotationX(), 1, 0, 0);
46888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                true3dMat.rotate(properties().getRotationY(), 0, 1, 0);
46988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                true3dMat.rotate(properties().getRotation(), 0, 0, 1);
47088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                true3dMat.scale(properties().getScaleX(), properties().getScaleY(), 1);
4718d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber                true3dMat.translate(-properties().getPivotX(), -properties().getPivotY());
47288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
47388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                matrix.multiply(true3dMat);
47488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            }
47588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        }
47688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
47788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
47888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
47988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber/**
48088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Organizes the DisplayList hierarchy to prepare for background projection reordering.
48188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
48288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * This should be called before a call to defer() or drawDisplayList()
48388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
48488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Each DisplayList that serves as a 3d root builds its list of composited children,
48588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * which are flagged to not draw in the standard draw loop.
48688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber */
4878d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Hubervoid RenderNode::computeOrdering() {
48888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    ATRACE_CALL();
48988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mProjectedNodes.clear();
49088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
49188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
49288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // transform properties are applied correctly to top level children
49388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (mDisplayListData == nullptr) return;
49488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
49588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
49688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        childOp->mRenderNode->computeOrderingImpl(childOp,
49788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber                properties().getOutline().getPath(), &mProjectedNodes, &mat4::identity());
49888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
49988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
50088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
50188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubervoid RenderNode::computeOrderingImpl(
50288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        DrawRenderNodeOp* opState,
5039b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber        const SkPath* outlineOfProjectionSurface,
50488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        Vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
50588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        const mat4* transformFromProjectionSurface) {
50688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mProjectedNodes.clear();
50788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (mDisplayListData == nullptr || mDisplayListData->isEmpty()) return;
50888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
50988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // TODO: should avoid this calculation in most cases
51088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    // TODO: just calculate single matrix, down to all leaf composited elements
51188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface);
51279f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong    localTransformFromProjectionSurface.multiply(opState->mTransformFromParent);
51379f407cc6c5ae34fc6f04d52fd034b49d1f002c4James Dong
514    if (properties().getProjectBackwards()) {
515        // composited projectee, flag for out of order draw, save matrix, and store in proj surface
516        opState->mSkipInOrderDraw = true;
517        opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface);
518        compositedChildrenOfProjectionSurface->add(opState);
519    } else {
520        // standard in order draw
521        opState->mSkipInOrderDraw = false;
522    }
523
524    if (mDisplayListData->children().size() > 0) {
525        const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
526        bool haveAppliedPropertiesToProjection = false;
527        for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
528            DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
529            RenderNode* child = childOp->mRenderNode;
530
531            const SkPath* projectionOutline = nullptr;
532            Vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
533            const mat4* projectionTransform = nullptr;
534            if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
535                // if receiving projections, collect projecting descendent
536
537                // Note that if a direct descendent is projecting backwards, we pass it's
538                // grandparent projection collection, since it shouldn't project onto it's
539                // parent, where it will already be drawing.
540                projectionOutline = properties().getOutline().getPath();
541                projectionChildren = &mProjectedNodes;
542                projectionTransform = &mat4::identity();
543            } else {
544                if (!haveAppliedPropertiesToProjection) {
545                    applyViewPropertyTransforms(localTransformFromProjectionSurface);
546                    haveAppliedPropertiesToProjection = true;
547                }
548                projectionOutline = outlineOfProjectionSurface;
549                projectionChildren = compositedChildrenOfProjectionSurface;
550                projectionTransform = &localTransformFromProjectionSurface;
551            }
552            child->computeOrderingImpl(childOp,
553                    projectionOutline, projectionChildren, projectionTransform);
554        }
555    }
556}
557
558class DeferOperationHandler {
559public:
560    DeferOperationHandler(DeferStateStruct& deferStruct, int level)
561        : mDeferStruct(deferStruct), mLevel(level) {}
562    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
563        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
564    }
565    inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
566    inline void startMark(const char* name) {} // do nothing
567    inline void endMark() {}
568    inline int level() { return mLevel; }
569    inline int replayFlags() { return mDeferStruct.mReplayFlags; }
570    inline SkPath* allocPathForFrame() { return mDeferStruct.allocPathForFrame(); }
571
572private:
573    DeferStateStruct& mDeferStruct;
574    const int mLevel;
575};
576
577void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
578    DeferOperationHandler handler(deferStruct, level);
579    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
580}
581
582class ReplayOperationHandler {
583public:
584    ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
585        : mReplayStruct(replayStruct), mLevel(level) {}
586    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
587#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
588        mReplayStruct.mRenderer.eventMark(operation->name());
589#endif
590        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
591    }
592    inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
593    inline void startMark(const char* name) {
594        mReplayStruct.mRenderer.startMark(name);
595    }
596    inline void endMark() {
597        mReplayStruct.mRenderer.endMark();
598    }
599    inline int level() { return mLevel; }
600    inline int replayFlags() { return mReplayStruct.mReplayFlags; }
601    inline SkPath* allocPathForFrame() { return mReplayStruct.allocPathForFrame(); }
602
603private:
604    ReplayStateStruct& mReplayStruct;
605    const int mLevel;
606};
607
608void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
609    ReplayOperationHandler handler(replayStruct, level);
610    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
611}
612
613void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk,
614        Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
615    if (chunk.beginChildIndex == chunk.endChildIndex) return;
616
617    for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
618        DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
619        RenderNode* child = childOp->mRenderNode;
620        float childZ = child->properties().getZ();
621
622        if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
623            zTranslatedNodes.add(ZDrawRenderNodeOpPair(childZ, childOp));
624            childOp->mSkipInOrderDraw = true;
625        } else if (!child->properties().getProjectBackwards()) {
626            // regular, in order drawing DisplayList
627            childOp->mSkipInOrderDraw = false;
628        }
629    }
630
631    // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
632    std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
633}
634
635template <class T>
636void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
637    if (properties().getAlpha() <= 0.0f
638            || properties().getOutline().getAlpha() <= 0.0f
639            || !properties().getOutline().getPath()) {
640        // no shadow to draw
641        return;
642    }
643
644    mat4 shadowMatrixXY(transformFromParent);
645    applyViewPropertyTransforms(shadowMatrixXY);
646
647    // Z matrix needs actual 3d transformation, so mapped z values will be correct
648    mat4 shadowMatrixZ(transformFromParent);
649    applyViewPropertyTransforms(shadowMatrixZ, true);
650
651    const SkPath* casterOutlinePath = properties().getOutline().getPath();
652    const SkPath* revealClipPath = properties().getRevealClip().getPath();
653    if (revealClipPath && revealClipPath->isEmpty()) return;
654
655    float casterAlpha = properties().getAlpha() * properties().getOutline().getAlpha();
656
657
658    // holds temporary SkPath to store the result of intersections
659    SkPath* frameAllocatedPath = nullptr;
660    const SkPath* outlinePath = casterOutlinePath;
661
662    // intersect the outline with the reveal clip, if present
663    if (revealClipPath) {
664        frameAllocatedPath = handler.allocPathForFrame();
665
666        Op(*outlinePath, *revealClipPath, kIntersect_PathOp, frameAllocatedPath);
667        outlinePath = frameAllocatedPath;
668    }
669
670    // intersect the outline with the clipBounds, if present
671    if (properties().getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
672        if (!frameAllocatedPath) {
673            frameAllocatedPath = handler.allocPathForFrame();
674        }
675
676        Rect clipBounds;
677        properties().getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
678        SkPath clipBoundsPath;
679        clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
680                clipBounds.right, clipBounds.bottom);
681
682        Op(*outlinePath, clipBoundsPath, kIntersect_PathOp, frameAllocatedPath);
683        outlinePath = frameAllocatedPath;
684    }
685
686    DisplayListOp* shadowOp  = new (handler.allocator()) DrawShadowOp(
687            shadowMatrixXY, shadowMatrixZ, casterAlpha, outlinePath);
688    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
689}
690
691#define SHADOW_DELTA 0.1f
692
693template <class T>
694void RenderNode::issueOperationsOf3dChildren(ChildrenSelectMode mode,
695        const Matrix4& initialTransform, const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
696        OpenGLRenderer& renderer, T& handler) {
697    const int size = zTranslatedNodes.size();
698    if (size == 0
699            || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f)
700            || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
701        // no 3d children to draw
702        return;
703    }
704
705    // Apply the base transform of the parent of the 3d children. This isolates
706    // 3d children of the current chunk from transformations made in previous chunks.
707    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
708    renderer.setMatrix(initialTransform);
709
710    /**
711     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
712     * with very similar Z heights to draw together.
713     *
714     * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
715     * underneath both, and neither's shadow is drawn on top of the other.
716     */
717    const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
718    size_t drawIndex, shadowIndex, endIndex;
719    if (mode == kNegativeZChildren) {
720        drawIndex = 0;
721        endIndex = nonNegativeIndex;
722        shadowIndex = endIndex; // draw no shadows
723    } else {
724        drawIndex = nonNegativeIndex;
725        endIndex = size;
726        shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
727    }
728
729    DISPLAY_LIST_LOGD("%*s%d %s 3d children:", (handler.level() + 1) * 2, "",
730            endIndex - drawIndex, mode == kNegativeZChildren ? "negative" : "positive");
731
732    float lastCasterZ = 0.0f;
733    while (shadowIndex < endIndex || drawIndex < endIndex) {
734        if (shadowIndex < endIndex) {
735            DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value;
736            RenderNode* caster = casterOp->mRenderNode;
737            const float casterZ = zTranslatedNodes[shadowIndex].key;
738            // attempt to render the shadow if the caster about to be drawn is its caster,
739            // OR if its caster's Z value is similar to the previous potential caster
740            if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
741                caster->issueDrawShadowOperation(casterOp->mTransformFromParent, handler);
742
743                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
744                shadowIndex++;
745                continue;
746            }
747        }
748
749        // only the actual child DL draw needs to be in save/restore,
750        // since it modifies the renderer's matrix
751        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
752
753        DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
754
755        renderer.concatMatrix(childOp->mTransformFromParent);
756        childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
757        handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds());
758        childOp->mSkipInOrderDraw = true;
759
760        renderer.restoreToCount(restoreTo);
761        drawIndex++;
762    }
763    renderer.restoreToCount(rootRestoreTo);
764}
765
766template <class T>
767void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
768    DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size());
769    const SkPath* projectionReceiverOutline = properties().getOutline().getPath();
770    int restoreTo = renderer.getSaveCount();
771
772    LinearAllocator& alloc = handler.allocator();
773    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
774            PROPERTY_SAVECOUNT, properties().getClipToBounds());
775
776    // Transform renderer to match background we're projecting onto
777    // (by offsetting canvas by translationX/Y of background rendernode, since only those are set)
778    const DisplayListOp* op =
779            (mDisplayListData->displayListOps[mDisplayListData->projectionReceiveIndex]);
780    const DrawRenderNodeOp* backgroundOp = reinterpret_cast<const DrawRenderNodeOp*>(op);
781    const RenderProperties& backgroundProps = backgroundOp->mRenderNode->properties();
782    renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
783
784    // If the projection reciever has an outline, we mask each of the projected rendernodes to it
785    // Either with clipRect, or special saveLayer masking
786    if (projectionReceiverOutline != nullptr) {
787        const SkRect& outlineBounds = projectionReceiverOutline->getBounds();
788        if (projectionReceiverOutline->isRect(nullptr)) {
789            // mask to the rect outline simply with clipRect
790            ClipRectOp* clipOp = new (alloc) ClipRectOp(
791                    outlineBounds.left(), outlineBounds.top(),
792                    outlineBounds.right(), outlineBounds.bottom(), SkRegion::kIntersect_Op);
793            handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
794        } else {
795            // wrap the projected RenderNodes with a SaveLayer that will mask to the outline
796            SaveLayerOp* op = new (alloc) SaveLayerOp(
797                    outlineBounds.left(), outlineBounds.top(),
798                    outlineBounds.right(), outlineBounds.bottom(),
799                    255, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag | SkCanvas::kARGB_ClipLayer_SaveFlag);
800            op->setMask(projectionReceiverOutline);
801            handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
802
803            /* TODO: add optimizations here to take advantage of placement/size of projected
804             * children (which may shrink saveLayer area significantly). This is dependent on
805             * passing actual drawing/dirtying bounds of projected content down to native.
806             */
807        }
808    }
809
810    // draw projected nodes
811    for (size_t i = 0; i < mProjectedNodes.size(); i++) {
812        DrawRenderNodeOp* childOp = mProjectedNodes[i];
813
814        // matrix save, concat, and restore can be done safely without allocating operations
815        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
816        renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
817        childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
818        handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds());
819        childOp->mSkipInOrderDraw = true;
820        renderer.restoreToCount(restoreTo);
821    }
822
823    if (projectionReceiverOutline != nullptr) {
824        handler(new (alloc) RestoreToCountOp(restoreTo),
825                PROPERTY_SAVECOUNT, properties().getClipToBounds());
826    }
827}
828
829/**
830 * This function serves both defer and replay modes, and will organize the displayList's component
831 * operations for a single frame:
832 *
833 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
834 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
835 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
836 * defer vs replay logic, per operation
837 */
838template <class T>
839void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
840    if (mDisplayListData->isEmpty()) {
841        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
842        return;
843    }
844
845    const bool drawLayer = (mLayer && (&renderer != mLayer->renderer.get()));
846    // If we are updating the contents of mLayer, we don't want to apply any of
847    // the RenderNode's properties to this issueOperations pass. Those will all
848    // be applied when the layer is drawn, aka when this is true.
849    const bool useViewProperties = (!mLayer || drawLayer);
850    if (useViewProperties) {
851        const Outline& outline = properties().getOutline();
852        if (properties().getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty())) {
853            DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", level * 2, "", this, getName());
854            return;
855        }
856    }
857
858    handler.startMark(getName());
859
860#if DEBUG_DISPLAY_LIST
861    const Rect& clipRect = renderer.getLocalClipBounds();
862    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
863            handler.level() * 2, "", this, getName(),
864            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
865#endif
866
867    LinearAllocator& alloc = handler.allocator();
868    int restoreTo = renderer.getSaveCount();
869    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
870            PROPERTY_SAVECOUNT, properties().getClipToBounds());
871
872    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
873            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
874
875    if (useViewProperties) {
876        setViewProperties<T>(renderer, handler);
877    }
878
879    bool quickRejected = properties().getClipToBounds()
880            && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
881    if (!quickRejected) {
882        Matrix4 initialTransform(*(renderer.currentTransform()));
883
884        if (drawLayer) {
885            handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
886                    renderer.getSaveCount() - 1, properties().getClipToBounds());
887        } else {
888            const int saveCountOffset = renderer.getSaveCount() - 1;
889            const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
890            for (size_t chunkIndex = 0; chunkIndex < mDisplayListData->getChunks().size(); chunkIndex++) {
891                const DisplayListData::Chunk& chunk = mDisplayListData->getChunks()[chunkIndex];
892
893                Vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
894                buildZSortedChildList(chunk, zTranslatedNodes);
895
896                issueOperationsOf3dChildren(kNegativeZChildren,
897                        initialTransform, zTranslatedNodes, renderer, handler);
898
899
900                for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
901                    DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
902#if DEBUG_DISPLAY_LIST
903                    op->output(handler.level() + 1);
904#endif
905                    handler(op, saveCountOffset, properties().getClipToBounds());
906
907                    if (CC_UNLIKELY(!mProjectedNodes.isEmpty() && projectionReceiveIndex >= 0 &&
908                        opIndex == static_cast<size_t>(projectionReceiveIndex))) {
909                        issueOperationsOfProjectedChildren(renderer, handler);
910                    }
911                }
912
913                issueOperationsOf3dChildren(kPositiveZChildren,
914                        initialTransform, zTranslatedNodes, renderer, handler);
915            }
916        }
917    }
918
919    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
920    handler(new (alloc) RestoreToCountOp(restoreTo),
921            PROPERTY_SAVECOUNT, properties().getClipToBounds());
922    renderer.setOverrideLayerAlpha(1.0f);
923
924    DISPLAY_LIST_LOGD("%*sDone (%p, %s)", level * 2, "", this, getName());
925    handler.endMark();
926}
927
928} /* namespace uirenderer */
929} /* namespace android */
930