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