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