1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "SkiaDisplayList.h" 18 19#include "renderthread/CanvasContext.h" 20#include "VectorDrawable.h" 21#include "DumpOpsCanvas.h" 22#include "SkiaPipeline.h" 23 24#include <SkImagePriv.h> 25 26 27namespace android { 28namespace uirenderer { 29namespace skiapipeline { 30 31void SkiaDisplayList::syncContents() { 32 for (auto& functor : mChildFunctors) { 33 functor.syncFunctor(); 34 } 35 for (auto& vectorDrawable : mVectorDrawables) { 36 vectorDrawable->syncProperties(); 37 } 38} 39 40bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) { 41 reset(); 42 node->attachAvailableList(this); 43 return true; 44} 45 46void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) { 47 for (auto& child : mChildNodes) { 48 updateFn(child.getRenderNode()); 49 } 50} 51 52bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info, 53 bool functorsNeedLayer, 54 std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { 55 // If the prepare tree is triggered by the UI thread and no previous call to 56 // pinImages has failed then we must pin all mutable images in the GPU cache 57 // until the next UI thread draw. 58 if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) { 59 // In the event that pinning failed we prevent future pinImage calls for the 60 // remainder of this tree traversal and also unpin any currently pinned images 61 // to free up GPU resources. 62 info.prepareTextures = false; 63 info.canvasContext.unpinImages(); 64 } 65 66 bool hasBackwardProjectedNodesHere = false; 67 bool hasBackwardProjectedNodesSubtree= false; 68 69 for (auto& child : mChildNodes) { 70 hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards(); 71 RenderNode* childNode = child.getRenderNode(); 72 Matrix4 mat4(child.getRecordedMatrix()); 73 info.damageAccumulator->pushTransform(&mat4); 74 // TODO: a layer is needed if the canvas is rotated or has a non-rect clip 75 info.hasBackwardProjectedNodes = false; 76 childFn(childNode, observer, info, functorsNeedLayer); 77 hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes; 78 info.damageAccumulator->popTransform(); 79 } 80 81 //The purpose of next block of code is to reset projected display list if there are no 82 //backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree 83 if (mProjectionReceiver) { 84 mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this : nullptr); 85 info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere; 86 } else { 87 info.hasBackwardProjectedNodes = hasBackwardProjectedNodesSubtree 88 || hasBackwardProjectedNodesHere; 89 } 90 91 bool isDirty = false; 92 for (auto& vectorDrawable : mVectorDrawables) { 93 // If any vector drawable in the display list needs update, damage the node. 94 if (vectorDrawable->isDirty()) { 95 isDirty = true; 96 static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) 97 ->getVectorDrawables()->push_back(vectorDrawable); 98 } 99 vectorDrawable->setPropertyChangeWillBeConsumed(true); 100 } 101 return isDirty; 102} 103 104void SkiaDisplayList::reset() { 105 mProjectionReceiver = nullptr; 106 107 mDisplayList.reset(); 108 109 mMutableImages.clear(); 110 mVectorDrawables.clear(); 111 mChildFunctors.clear(); 112 mChildNodes.clear(); 113 114 projectionReceiveIndex = -1; 115 allocator.~LinearAllocator(); 116 new (&allocator) LinearAllocator(); 117} 118 119void SkiaDisplayList::output(std::ostream& output, uint32_t level) { 120 DumpOpsCanvas canvas(output, level, *this); 121 mDisplayList.draw(&canvas); 122} 123 124}; // namespace skiapipeline 125}; // namespace uirenderer 126}; // namespace android 127