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 "DumpOpsCanvas.h" 20 #include "SkiaPipeline.h" 21 #include "VectorDrawable.h" 22 #include "renderthread/CanvasContext.h" 23 24 #include <SkImagePriv.h> 25 26 namespace android { 27 namespace uirenderer { 28 namespace skiapipeline { 29 30 void SkiaDisplayList::syncContents() { 31 for (auto& functor : mChildFunctors) { 32 functor.syncFunctor(); 33 } 34 for (auto& animatedImage : mAnimatedImages) { 35 animatedImage->syncProperties(); 36 } 37 for (auto& vectorDrawable : mVectorDrawables) { 38 vectorDrawable->syncProperties(); 39 } 40 } 41 42 bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) { 43 reset(); 44 node->attachAvailableList(this); 45 return true; 46 } 47 48 void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) { 49 for (auto& child : mChildNodes) { 50 updateFn(child.getRenderNode()); 51 } 52 } 53 54 bool SkiaDisplayList::prepareListAndChildren( 55 TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, 56 std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { 57 // If the prepare tree is triggered by the UI thread and no previous call to 58 // pinImages has failed then we must pin all mutable images in the GPU cache 59 // until the next UI thread draw. 60 if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) { 61 // In the event that pinning failed we prevent future pinImage calls for the 62 // remainder of this tree traversal and also unpin any currently pinned images 63 // to free up GPU resources. 64 info.prepareTextures = false; 65 info.canvasContext.unpinImages(); 66 } 67 68 bool hasBackwardProjectedNodesHere = false; 69 bool hasBackwardProjectedNodesSubtree = false; 70 71 for (auto& child : mChildNodes) { 72 hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards(); 73 RenderNode* childNode = child.getRenderNode(); 74 Matrix4 mat4(child.getRecordedMatrix()); 75 info.damageAccumulator->pushTransform(&mat4); 76 // TODO: a layer is needed if the canvas is rotated or has a non-rect clip 77 info.hasBackwardProjectedNodes = false; 78 childFn(childNode, observer, info, functorsNeedLayer); 79 hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes; 80 info.damageAccumulator->popTransform(); 81 } 82 83 // The purpose of next block of code is to reset projected display list if there are no 84 // backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree 85 if (mProjectionReceiver) { 86 mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this 87 : nullptr); 88 info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere; 89 } else { 90 info.hasBackwardProjectedNodes = 91 hasBackwardProjectedNodesSubtree || hasBackwardProjectedNodesHere; 92 } 93 94 bool isDirty = false; 95 for (auto& animatedImage : mAnimatedImages) { 96 nsecs_t timeTilNextFrame = TreeInfo::Out::kNoAnimatedImageDelay; 97 // If any animated image in the display list needs updated, then damage the node. 98 if (animatedImage->isDirty(&timeTilNextFrame)) { 99 isDirty = true; 100 } 101 102 if (animatedImage->isRunning() && 103 timeTilNextFrame != TreeInfo::Out::kNoAnimatedImageDelay) { 104 auto& delay = info.out.animatedImageDelay; 105 if (delay == TreeInfo::Out::kNoAnimatedImageDelay || timeTilNextFrame < delay) { 106 delay = timeTilNextFrame; 107 } 108 } 109 } 110 111 for (auto& vectorDrawable : mVectorDrawables) { 112 // If any vector drawable in the display list needs update, damage the node. 113 if (vectorDrawable->isDirty()) { 114 isDirty = true; 115 static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) 116 ->getVectorDrawables() 117 ->push_back(vectorDrawable); 118 } 119 vectorDrawable->setPropertyChangeWillBeConsumed(true); 120 } 121 return isDirty; 122 } 123 124 void SkiaDisplayList::reset() { 125 mProjectionReceiver = nullptr; 126 127 mDisplayList.reset(); 128 129 mMutableImages.clear(); 130 mVectorDrawables.clear(); 131 mAnimatedImages.clear(); 132 mChildFunctors.clear(); 133 mChildNodes.clear(); 134 135 projectionReceiveIndex = -1; 136 allocator.~LinearAllocator(); 137 new (&allocator) LinearAllocator(); 138 } 139 140 void SkiaDisplayList::output(std::ostream& output, uint32_t level) { 141 DumpOpsCanvas canvas(output, level, *this); 142 mDisplayList.draw(&canvas); 143 } 144 145 }; // namespace skiapipeline 146 }; // namespace uirenderer 147 }; // namespace android 148