• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <SkImagePriv.h>
20 #include <SkPathOps.h>
21 
22 // clang-format off
23 #include "FunctorDrawable.h" // Must be included before DumpOpsCanvas.h
24 #include "DumpOpsCanvas.h"
25 // clang-format on
26 #include "SkiaPipeline.h"
27 #include "TreeInfo.h"
28 #include "VectorDrawable.h"
29 #include "renderthread/CanvasContext.h"
30 
31 namespace android {
32 namespace uirenderer {
33 namespace skiapipeline {
34 
syncContents(const WebViewSyncData & data)35 void SkiaDisplayList::syncContents(const WebViewSyncData& data) {
36     for (auto& functor : mChildFunctors) {
37         functor->syncFunctor(data);
38     }
39     for (auto& animatedImage : mAnimatedImages) {
40         animatedImage->syncProperties();
41     }
42     for (auto& vectorDrawable : mVectorDrawables) {
43         vectorDrawable.first->syncProperties();
44     }
45 }
46 
onRemovedFromTree()47 void SkiaDisplayList::onRemovedFromTree() {
48     for (auto& functor : mChildFunctors) {
49         functor->onRemovedFromTree();
50     }
51 }
52 
reuseDisplayList(RenderNode * node)53 bool SkiaDisplayList::reuseDisplayList(RenderNode* node) {
54     reset();
55     node->attachAvailableList(this);
56     return true;
57 }
58 
updateChildren(std::function<void (RenderNode *)> updateFn)59 void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
60     for (auto& child : mChildNodes) {
61         updateFn(child.getRenderNode());
62     }
63 }
64 
visit(std::function<void (const RenderNode &)> func) const65 void SkiaDisplayList::visit(std::function<void(const RenderNode&)> func) const {
66     for (auto& child : mChildNodes) {
67         child.getRenderNode()->visit(func);
68     }
69 }
70 
intersects(const SkISize screenSize,const Matrix4 & mat,const SkRect & bounds)71 static bool intersects(const SkISize screenSize, const Matrix4& mat, const SkRect& bounds) {
72     Vector3 points[] = { Vector3 {bounds.fLeft, bounds.fTop, 0},
73                          Vector3 {bounds.fRight, bounds.fTop, 0},
74                          Vector3 {bounds.fRight, bounds.fBottom, 0},
75                          Vector3 {bounds.fLeft, bounds.fBottom, 0}};
76     float minX, minY, maxX, maxY;
77     bool first = true;
78     for (auto& point : points) {
79         mat.mapPoint3d(point);
80         if (first) {
81             minX = maxX = point.x;
82             minY = maxY = point.y;
83             first = false;
84         } else {
85             minX = std::min(minX, point.x);
86             minY = std::min(minY, point.y);
87             maxX = std::max(maxX, point.x);
88             maxY = std::max(maxY, point.y);
89         }
90     }
91     return SkRect::Make(screenSize).intersects(SkRect::MakeLTRB(minX, minY, maxX, maxY));
92 }
93 
prepareListAndChildren(TreeObserver & observer,TreeInfo & info,bool functorsNeedLayer,std::function<void (RenderNode *,TreeObserver &,TreeInfo &,bool)> childFn)94 bool SkiaDisplayList::prepareListAndChildren(
95         TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
96         std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
97     // If the prepare tree is triggered by the UI thread and no previous call to
98     // pinImages has failed then we must pin all mutable images in the GPU cache
99     // until the next UI thread draw.
100     if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) {
101         // In the event that pinning failed we prevent future pinImage calls for the
102         // remainder of this tree traversal and also unpin any currently pinned images
103         // to free up GPU resources.
104         info.prepareTextures = false;
105         info.canvasContext.unpinImages();
106     }
107 
108 #ifdef __ANDROID__
109     auto grContext = info.canvasContext.getGrContext();
110     for (const auto& bufferData : mMeshBufferData) {
111         bufferData->updateBuffers(grContext);
112     }
113 #endif
114 
115     bool hasBackwardProjectedNodesHere = false;
116     bool hasBackwardProjectedNodesSubtree = false;
117 
118     for (auto& child : mChildNodes) {
119         RenderNode* childNode = child.getRenderNode();
120         Matrix4 mat4(child.getRecordedMatrix());
121         info.damageAccumulator->pushTransform(&mat4);
122         info.hasBackwardProjectedNodes = false;
123         childFn(childNode, observer, info, functorsNeedLayer);
124         hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
125         hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes;
126         info.damageAccumulator->popTransform();
127     }
128 
129     // The purpose of next block of code is to reset projected display list if there are no
130     // backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
131     if (mProjectionReceiver) {
132         mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this
133                                                                                       : nullptr);
134         info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere;
135     } else {
136         info.hasBackwardProjectedNodes =
137                 hasBackwardProjectedNodesSubtree || hasBackwardProjectedNodesHere;
138     }
139 
140     bool isDirty = false;
141     for (auto& animatedImage : mAnimatedImages) {
142         nsecs_t timeTilNextFrame = TreeInfo::Out::kNoAnimatedImageDelay;
143         // If any animated image in the display list needs updated, then damage the node.
144         if (animatedImage->isDirty(&timeTilNextFrame)) {
145             isDirty = true;
146         }
147 
148         if (animatedImage->isRunning() &&
149             timeTilNextFrame != TreeInfo::Out::kNoAnimatedImageDelay) {
150             auto& delay = info.out.animatedImageDelay;
151             if (delay == TreeInfo::Out::kNoAnimatedImageDelay || timeTilNextFrame < delay) {
152                 delay = timeTilNextFrame;
153             }
154         }
155     }
156 
157     for (auto& [vectorDrawable, cachedMatrix] : mVectorDrawables) {
158         // If any vector drawable in the display list needs update, damage the node.
159         if (vectorDrawable->isDirty()) {
160             Matrix4 totalMatrix;
161             info.damageAccumulator->computeCurrentTransform(&totalMatrix);
162             Matrix4 canvasMatrix(cachedMatrix);
163             totalMatrix.multiply(canvasMatrix);
164             const SkRect& bounds = vectorDrawable->properties().getBounds();
165             if (intersects(info.screenSize, totalMatrix, bounds)) {
166                 isDirty = true;
167                 vectorDrawable->setPropertyChangeWillBeConsumed(true);
168             }
169         }
170     }
171     return isDirty;
172 }
173 
reset()174 void SkiaDisplayList::reset() {
175     mProjectionReceiver = nullptr;
176 
177     mDisplayList.reset();
178 
179     mMeshBufferData.clear();
180     mMutableImages.clear();
181     mVectorDrawables.clear();
182     mAnimatedImages.clear();
183     mChildFunctors.clear();
184     mChildNodes.clear();
185 
186     allocator.~LinearAllocator();
187     new (&allocator) LinearAllocator();
188 }
189 
output(std::ostream & output,uint32_t level) const190 void SkiaDisplayList::output(std::ostream& output, uint32_t level) const {
191     DumpOpsCanvas canvas(output, level, *this);
192     mDisplayList.draw(&canvas);
193 }
194 
195 }  // namespace skiapipeline
196 }  // namespace uirenderer
197 }  // namespace android
198