1 /*
2  * Copyright (C) 2014 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 #pragma once
18 
19 #include <SkCamera.h>
20 #include <SkMatrix.h>
21 
22 #include <utils/LinearAllocator.h>
23 #include <utils/RefBase.h>
24 #include <utils/String8.h>
25 
26 #include <cutils/compiler.h>
27 
28 #include <androidfw/ResourceTypes.h>
29 
30 #include <ui/FatVector.h>
31 
32 #include "AnimatorManager.h"
33 #include "CanvasTransform.h"
34 #include "Debug.h"
35 #include "DisplayList.h"
36 #include "Matrix.h"
37 #include "RenderProperties.h"
38 #include "pipeline/skia/SkiaDisplayList.h"
39 #include "pipeline/skia/SkiaLayer.h"
40 
41 #include <vector>
42 
43 class SkBitmap;
44 class SkPaint;
45 class SkPath;
46 class SkRegion;
47 class SkSurface;
48 
49 namespace android {
50 namespace uirenderer {
51 
52 class CanvasState;
53 class Rect;
54 class SkiaShader;
55 struct RenderNodeOp;
56 
57 class TreeInfo;
58 class TreeObserver;
59 
60 namespace proto {
61 class RenderNode;
62 }
63 
64 /**
65  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display
66  * properties.
67  *
68  * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
69  * functionality is split between RecordingCanvas (which manages the recording), DisplayList
70  * (which holds the actual data), and RenderNode (which holds properties used for render playback).
71  *
72  * Note that DisplayList is swapped out from beneath an individual RenderNode when a view's
73  * recorded stream of canvas operations is refreshed. The RenderNode (and its properties) stay
74  * attached.
75  */
76 class RenderNode : public VirtualLightRefBase {
77     friend class TestUtils;  // allow TestUtils to access syncDisplayList / syncProperties
78 
79 public:
80     enum DirtyPropertyMask {
81         GENERIC = 1 << 1,
82         TRANSLATION_X = 1 << 2,
83         TRANSLATION_Y = 1 << 3,
84         TRANSLATION_Z = 1 << 4,
85         SCALE_X = 1 << 5,
86         SCALE_Y = 1 << 6,
87         ROTATION = 1 << 7,
88         ROTATION_X = 1 << 8,
89         ROTATION_Y = 1 << 9,
90         X = 1 << 10,
91         Y = 1 << 11,
92         Z = 1 << 12,
93         ALPHA = 1 << 13,
94         DISPLAY_LIST = 1 << 14,
95     };
96 
97     ANDROID_API RenderNode();
98     ANDROID_API virtual ~RenderNode();
99 
100     // See flags defined in DisplayList.java
101     enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };
102 
103     ANDROID_API void setStagingDisplayList(DisplayList* newData);
104 
105     ANDROID_API void output();
106     ANDROID_API int getUsageSize();
107     ANDROID_API int getAllocatedSize();
108 
isRenderable()109     bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
110 
hasProjectionReceiver()111     bool hasProjectionReceiver() const {
112         return mDisplayList && mDisplayList->containsProjectionReceiver();
113     }
114 
getName()115     const char* getName() const { return mName.string(); }
116 
setName(const char * name)117     void setName(const char* name) {
118         if (name) {
119             const char* lastPeriod = strrchr(name, '.');
120             if (lastPeriod) {
121                 mName.setTo(lastPeriod + 1);
122             } else {
123                 mName.setTo(name);
124             }
125         }
126     }
127 
getUserContext()128     VirtualLightRefBase* getUserContext() const { return mUserContext.get(); }
129 
setUserContext(VirtualLightRefBase * context)130     void setUserContext(VirtualLightRefBase* context) { mUserContext = context; }
131 
isPropertyFieldDirty(DirtyPropertyMask field)132     bool isPropertyFieldDirty(DirtyPropertyMask field) const {
133         return mDirtyPropertyFields & field;
134     }
135 
setPropertyFieldsDirty(uint32_t fields)136     void setPropertyFieldsDirty(uint32_t fields) { mDirtyPropertyFields |= fields; }
137 
properties()138     const RenderProperties& properties() const { return mProperties; }
139 
animatorProperties()140     RenderProperties& animatorProperties() { return mProperties; }
141 
stagingProperties()142     const RenderProperties& stagingProperties() { return mStagingProperties; }
143 
mutateStagingProperties()144     RenderProperties& mutateStagingProperties() { return mStagingProperties; }
145 
isValid()146     bool isValid() { return mValid; }
147 
getWidth()148     int getWidth() const { return properties().getWidth(); }
149 
getHeight()150     int getHeight() const { return properties().getHeight(); }
151 
152     ANDROID_API virtual void prepareTree(TreeInfo& info);
153     void destroyHardwareResources(TreeInfo* info = nullptr);
154     void destroyLayers();
155 
156     // UI thread only!
157     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
158     void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
159 
160     // This can only happen during pushStaging()
onAnimatorTargetChanged(BaseRenderNodeAnimator * animator)161     void onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
162         mAnimatorManager.onAnimatorTargetChanged(animator);
163     }
164 
animators()165     AnimatorManager& animators() { return mAnimatorManager; }
166 
167     void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const;
168 
nothingToDraw()169     bool nothingToDraw() const {
170         const Outline& outline = properties().getOutline();
171         return mDisplayList == nullptr || properties().getAlpha() <= 0 ||
172                (outline.getShouldClip() && outline.isEmpty()) || properties().getScaleX() == 0 ||
173                properties().getScaleY() == 0;
174     }
175 
getDisplayList()176     const DisplayList* getDisplayList() const { return mDisplayList; }
177 
178     // Note: The position callbacks are relying on the listener using
179     // the frameNumber to appropriately batch/synchronize these transactions.
180     // There is no other filtering/batching to ensure that only the "final"
181     // state called once per frame.
182     class ANDROID_API PositionListener : public VirtualLightRefBase {
183     public:
~PositionListener()184         virtual ~PositionListener() {}
185         // Called when the RenderNode's position changes
186         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
187         // Called when the RenderNode no longer has a position. As in, it's
188         // no longer being drawn.
189         // Note, tree info might be null
190         virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0;
191     };
192 
setPositionListener(PositionListener * listener)193     ANDROID_API void setPositionListener(PositionListener* listener) {
194         mStagingPositionListener = listener;
195         mPositionListenerDirty = true;
196     }
197 
198     // This is only modified in MODE_FULL, so it can be safely accessed
199     // on the UI thread.
hasParents()200     ANDROID_API bool hasParents() { return mParentCount; }
201 
202     void onRemovedFromTree(TreeInfo* info);
203 
204     // Called by CanvasContext to promote a RenderNode to be a root node
makeRoot()205     void makeRoot() { incParentRefCount(); }
206 
207     // Called by CanvasContext when it drops a RenderNode from being a root node
208     void clearRoot();
209 
210     void output(std::ostream& output, uint32_t level);
211 
setUsageHint(UsageHint usageHint)212     void setUsageHint(UsageHint usageHint) { mUsageHint = usageHint; }
213 
usageHint()214     UsageHint usageHint() const { return mUsageHint; }
215 
uniqueId()216     int64_t uniqueId() const { return mUniqueId; }
217 
218     void markDrawStart(SkCanvas& canvas);
219     void markDrawEnd(SkCanvas& canvas);
220 
221 private:
222     void computeOrderingImpl(RenderNodeOp* opState,
223                              std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
224                              const mat4* transformFromProjectionSurface);
225 
226     void syncProperties();
227     void syncDisplayList(TreeObserver& observer, TreeInfo* info);
228     void handleForceDark(TreeInfo* info);
229 
230     void prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer);
231     void pushStagingPropertiesChanges(TreeInfo& info);
232     void pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info);
233     void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
234     void pushLayerUpdate(TreeInfo& info);
235     void deleteDisplayList(TreeObserver& observer, TreeInfo* info = nullptr);
236     void damageSelf(TreeInfo& info);
237 
incParentRefCount()238     void incParentRefCount() { mParentCount++; }
239     void decParentRefCount(TreeObserver& observer, TreeInfo* info = nullptr);
240 
241     const int64_t mUniqueId;
242     String8 mName;
243     sp<VirtualLightRefBase> mUserContext;
244 
245     uint32_t mDirtyPropertyFields;
246     RenderProperties mProperties;
247     RenderProperties mStagingProperties;
248 
249     // Owned by UI. Set when DL is set, cleared when DL cleared or when node detached
250     // (likely by parent re-record/removal)
251     bool mValid = false;
252 
253     bool mNeedsDisplayListSync;
254     // WARNING: Do not delete this directly, you must go through deleteDisplayList()!
255     DisplayList* mDisplayList;
256     DisplayList* mStagingDisplayList;
257 
258     int64_t mDamageGenerationId;
259 
260     friend class AnimatorManager;
261     AnimatorManager mAnimatorManager;
262 
263     /**
264      * Draw time state - these properties are only set and used during rendering
265      */
266 
267     // for projection surfaces, contains a list of all children items
268     std::vector<RenderNodeOp*> mProjectedNodes;
269 
270     // How many references our parent(s) have to us. Typically this should alternate
271     // between 2 and 1 (when a staging push happens we inc first then dec)
272     // When this hits 0 we are no longer in the tree, so any hardware resources
273     // (specifically Layers) should be released.
274     // This is *NOT* thread-safe, and should therefore only be tracking
275     // mDisplayList, not mStagingDisplayList.
276     uint32_t mParentCount;
277 
278     bool mPositionListenerDirty = false;
279     sp<PositionListener> mStagingPositionListener;
280     sp<PositionListener> mPositionListener;
281 
282     UsageHint mUsageHint = UsageHint::Unknown;
283 
284     // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
285 public:
286     /**
287      * Detach and transfer ownership of an already allocated displayList for use
288      * in recording updated content for this renderNode
289      */
detachAvailableList()290     std::unique_ptr<skiapipeline::SkiaDisplayList> detachAvailableList() {
291         return std::move(mAvailableDisplayList);
292     }
293 
294     /**
295      * Attach unused displayList to this node for potential future reuse.
296      */
attachAvailableList(skiapipeline::SkiaDisplayList * skiaDisplayList)297     void attachAvailableList(skiapipeline::SkiaDisplayList* skiaDisplayList) {
298         mAvailableDisplayList.reset(skiaDisplayList);
299     }
300 
301     /**
302      * Returns true if an offscreen layer from any renderPipeline is attached
303      * to this node.
304      */
hasLayer()305     bool hasLayer() const { return mSkiaLayer.get(); }
306 
307     /**
308      * Used by the RenderPipeline to attach an offscreen surface to the RenderNode.
309      * The surface is then will be used to store the contents of a layer.
310      */
setLayerSurface(sk_sp<SkSurface> layer)311     void setLayerSurface(sk_sp<SkSurface> layer) {
312         if (layer.get()) {
313             if (!mSkiaLayer.get()) {
314                 mSkiaLayer = std::make_unique<skiapipeline::SkiaLayer>();
315             }
316             mSkiaLayer->layerSurface = std::move(layer);
317             mSkiaLayer->inverseTransformInWindow.loadIdentity();
318         } else {
319             mSkiaLayer.reset();
320         }
321     }
322 
323     /**
324      * If the RenderNode is of type LayerType::RenderLayer then this method will
325      * return the an offscreen rendering surface that is used to both render into
326      * the layer and composite the layer into its parent.  If the type is not
327      * LayerType::RenderLayer then it will return a nullptr.
328      *
329      * NOTE: this function is only guaranteed to return accurate results after
330      *       prepareTree has been run for this RenderNode
331      */
getLayerSurface()332     SkSurface* getLayerSurface() const {
333         return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
334     }
335 
getSkiaLayer()336     skiapipeline::SkiaLayer* getSkiaLayer() const { return mSkiaLayer.get(); }
337 
338     /**
339      * Returns the path that represents the outline of RenderNode intersected with
340      * the provided rect.  This call will internally cache the resulting path in
341      * order to potentially return that path for subsequent calls to this method.
342      * By reusing the same path we get better performance on the GPU backends since
343      * those resources are cached in the hardware based on the path's genID.
344      *
345      * The returned path is only guaranteed to be valid until this function is called
346      * again or the RenderNode's outline is mutated.
347      */
348     const SkPath* getClippedOutline(const SkRect& clipRect) const;
349 
350 private:
351     /**
352      * If this RenderNode has been used in a previous frame then the SkiaDisplayList
353      * from that frame is cached here until one of the following conditions is met:
354      *  1) The RenderNode is deleted (causing this to be deleted)
355      *  2) It is replaced with the displayList from the next completed frame
356      *  3) It is detached and used to to record a new displayList for a later frame
357      */
358     std::unique_ptr<skiapipeline::SkiaDisplayList> mAvailableDisplayList;
359 
360     /**
361      * An offscreen rendering target used to contain the contents this RenderNode
362      * when it has been set to draw as a LayerType::RenderLayer.
363      */
364     std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
365 
366     struct ClippedOutlineCache {
367         // keys
368         uint32_t outlineID = 0;
369         SkRect clipRect;
370 
371         // value
372         SkPath clippedOutline;
373     };
374     mutable ClippedOutlineCache mClippedOutlineCache;
375 };  // class RenderNode
376 
377 class MarkAndSweepRemoved : public TreeObserver {
378     PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
379 
380 public:
MarkAndSweepRemoved(TreeInfo * info)381     explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
382 
onMaybeRemovedFromTree(RenderNode * node)383     void onMaybeRemovedFromTree(RenderNode* node) override { mMarked.emplace_back(node); }
384 
~MarkAndSweepRemoved()385     ~MarkAndSweepRemoved() {
386         for (auto& node : mMarked) {
387             if (!node->hasParents()) {
388                 node->onRemovedFromTree(mTreeInfo);
389             }
390         }
391     }
392 
393 private:
394     FatVector<sp<RenderNode>, 10> mMarked;
395     TreeInfo* mTreeInfo;
396 };
397 
398 } /* namespace uirenderer */
399 } /* namespace android */
400