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