• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "drawable/rs_drawable.h"
17 
18 #include <limits>
19 
20 #include "drawable/rs_misc_drawable.h"
21 #include "drawable/rs_property_drawable.h"
22 #include "drawable/rs_property_drawable_background.h"
23 #include "drawable/rs_property_drawable_foreground.h"
24 #include "pipeline/rs_render_node.h"
25 #include "pipeline/rs_surface_render_node.h"
26 
27 namespace OHOS::Rosen {
28 namespace {
29 using namespace DrawableV2;
30 
31 static const std::unordered_map<ModifierNG::RSModifierType, RSDrawableSlot> g_propertyToDrawableLutNG = {
32     { ModifierNG::RSModifierType::INVALID,                      RSDrawableSlot::INVALID },
33     { ModifierNG::RSModifierType::BOUNDS,                       RSDrawableSlot::CLIP_TO_BOUNDS },
34     { ModifierNG::RSModifierType::FRAME,                        RSDrawableSlot::FRAME_OFFSET },
35     { ModifierNG::RSModifierType::TRANSFORM,                    RSDrawableSlot::INVALID },
36     { ModifierNG::RSModifierType::ALPHA,                        RSDrawableSlot::INVALID },
37     { ModifierNG::RSModifierType::FOREGROUND_COLOR,             RSDrawableSlot::FOREGROUND_COLOR },
38     { ModifierNG::RSModifierType::BACKGROUND_COLOR,             RSDrawableSlot::BACKGROUND_COLOR },
39     { ModifierNG::RSModifierType::BACKGROUND_SHADER,            RSDrawableSlot::BACKGROUND_SHADER },
40     { ModifierNG::RSModifierType::BACKGROUND_NG_SHADER,         RSDrawableSlot::BACKGROUND_NG_SHADER },
41     { ModifierNG::RSModifierType::BACKGROUND_IMAGE,             RSDrawableSlot::BACKGROUND_IMAGE },
42     { ModifierNG::RSModifierType::BORDER,                       RSDrawableSlot::BORDER },
43     { ModifierNG::RSModifierType::OUTLINE,                      RSDrawableSlot::OUTLINE },
44     { ModifierNG::RSModifierType::CLIP_TO_BOUNDS,               RSDrawableSlot::CLIP_TO_BOUNDS },
45     { ModifierNG::RSModifierType::CLIP_TO_FRAME,                RSDrawableSlot::CLIP_TO_FRAME },
46     { ModifierNG::RSModifierType::VISIBILITY,                   RSDrawableSlot::INVALID },
47     { ModifierNG::RSModifierType::DYNAMIC_LIGHT_UP,             RSDrawableSlot::DYNAMIC_LIGHT_UP },
48     { ModifierNG::RSModifierType::SHADOW,                       RSDrawableSlot::SHADOW },
49     { ModifierNG::RSModifierType::MASK,                         RSDrawableSlot::MASK },
50     { ModifierNG::RSModifierType::PIXEL_STRETCH,                RSDrawableSlot::PIXEL_STRETCH },
51     { ModifierNG::RSModifierType::USE_EFFECT,                   RSDrawableSlot::USE_EFFECT },
52     { ModifierNG::RSModifierType::BLENDER,                      RSDrawableSlot::BLENDER },
53     { ModifierNG::RSModifierType::POINT_LIGHT,                  RSDrawableSlot::POINT_LIGHT },
54     { ModifierNG::RSModifierType::PARTICLE_EFFECT,              RSDrawableSlot::PARTICLE_EFFECT },
55     { ModifierNG::RSModifierType::COMPOSITING_FILTER,           RSDrawableSlot::COMPOSITING_FILTER },
56     { ModifierNG::RSModifierType::BACKGROUND_FILTER,            RSDrawableSlot::BACKGROUND_FILTER },
57     { ModifierNG::RSModifierType::FOREGROUND_FILTER,            RSDrawableSlot::FOREGROUND_FILTER },
58     { ModifierNG::RSModifierType::HDR_BRIGHTNESS,               RSDrawableSlot::FOREGROUND_FILTER },
59     { ModifierNG::RSModifierType::TRANSITION_STYLE,             RSDrawableSlot::TRANSITION },
60     { ModifierNG::RSModifierType::BACKGROUND_STYLE,             RSDrawableSlot::BACKGROUND_STYLE },
61     { ModifierNG::RSModifierType::CONTENT_STYLE,                RSDrawableSlot::CONTENT_STYLE },
62     { ModifierNG::RSModifierType::FOREGROUND_STYLE,             RSDrawableSlot::FOREGROUND_STYLE },
63     { ModifierNG::RSModifierType::OVERLAY_STYLE,                RSDrawableSlot::OVERLAY },
64     { ModifierNG::RSModifierType::NODE_MODIFIER,                RSDrawableSlot::INVALID },
65     { ModifierNG::RSModifierType::ENV_FOREGROUND_COLOR,         RSDrawableSlot::ENV_FOREGROUND_COLOR },
66     { ModifierNG::RSModifierType::BEHIND_WINDOW_FILTER,         RSDrawableSlot::BACKGROUND_FILTER },
67     { ModifierNG::RSModifierType::FOREGROUND_SHADER,            RSDrawableSlot::FOREGROUND_SHADER },
68     { ModifierNG::RSModifierType::CHILDREN,                     RSDrawableSlot::CHILDREN },
69 };
70 
71 template<ModifierNG::RSModifierType type>
ModifierGenerator(const RSRenderNode & node)72 static inline RSDrawable::Ptr ModifierGenerator(const RSRenderNode& node)
73 {
74     return RSCustomModifierDrawable::OnGenerate(node, type);
75 }
76 
77 // NOTE: This LUT should always the same size as RSDrawableSlot
78 // index = RSDrawableSlotType, value = DrawableGenerator
79 constexpr int GEN_LUT_SIZE = static_cast<int>(RSDrawableSlot::MAX);
80 static const std::array<RSDrawable::Generator, GEN_LUT_SIZE> g_drawableGeneratorLut = {
81     nullptr, // SAVE_ALL
82 
83     // Bounds Geometry
84     RSMaskDrawable::OnGenerate,                                      // MASK,
85     ModifierGenerator<ModifierNG::RSModifierType::TRANSITION_STYLE>, // TRANSITION_STYLE,
86     RSEnvFGColorDrawable::OnGenerate,                                // ENV_FOREGROUND_COLOR,
87     RSShadowDrawable::OnGenerate,                                    // SHADOW,
88     RSForegroundFilterDrawable::OnGenerate,                          // FOREGROUND_FILTER
89     RSOutlineDrawable::OnGenerate,                                   // OUTLINE,
90 
91     // BG properties in Bounds Clip
92     nullptr,                                                         // BG_SAVE_BOUNDS,
93     nullptr,                                                         // CLIP_TO_BOUNDS,
94     RSBeginBlenderDrawable::OnGenerate,                              // BLENDER,
95     RSBackgroundColorDrawable::OnGenerate,                           // BACKGROUND_COLOR,
96     RSBackgroundShaderDrawable::OnGenerate,                          // BACKGROUND_SHADER,
97     RSBackgroundNGShaderDrawable::OnGenerate,                        // BACKGROUND_NG_SHADER,
98     RSBackgroundImageDrawable::OnGenerate,                           // BACKGROUND_IMAGE,
99     RSBackgroundFilterDrawable::OnGenerate,                          // BACKGROUND_FILTER,
100     RSUseEffectDrawable::OnGenerate,                                 // USE_EFFECT,
101     ModifierGenerator<ModifierNG::RSModifierType::BACKGROUND_STYLE>, // BACKGROUND_STYLE,
102     RSDynamicLightUpDrawable::OnGenerate,                            // DYNAMIC_LIGHT_UP,
103     RSEnvFGColorStrategyDrawable::OnGenerate,                        // ENV_FOREGROUND_COLOR_STRATEGY,
104     nullptr,                                                         // BG_RESTORE_BOUNDS,
105 
106     // Frame Geometry
107     nullptr,                                                         // SAVE_FRAME,
108     RSFrameOffsetDrawable::OnGenerate,                               // FRAME_OFFSET,
109     RSClipToFrameDrawable::OnGenerate,                               // CLIP_TO_FRAME,
110     RSCustomClipToFrameDrawable::OnGenerate,                         // CUSTOM_CLIP_TO_FRAME,
111     ModifierGenerator<ModifierNG::RSModifierType::CONTENT_STYLE>,    // CONTENT_STYLE,
112     RSChildrenDrawable::OnGenerate,                                  // CHILDREN,
113     ModifierGenerator<ModifierNG::RSModifierType::FOREGROUND_STYLE>, // FOREGROUND_STYLE,
114     nullptr,                                                         // RESTORE_FRAME,
115 
116     // FG properties in Bounds clip
117     nullptr,                                                         // FG_SAVE_BOUNDS,
118     nullptr,                                                         // FG_CLIP_TO_BOUNDS,
119     RSBinarizationDrawable::OnGenerate,                              // BINARIZATION,
120     RSColorFilterDrawable::OnGenerate,                               // COLOR_FILTER,
121     RSLightUpEffectDrawable::OnGenerate,                             // LIGHT_UP_EFFECT,
122     RSDynamicDimDrawable::OnGenerate,                                // DYNAMIC_DIM,
123     RSCompositingFilterDrawable::OnGenerate,                         // COMPOSITING_FILTER,
124     RSForegroundColorDrawable::OnGenerate,                           // FOREGROUND_COLOR,
125     RSForegroundShaderDrawable::OnGenerate,                          // FOREGROUND_SHADER,
126     nullptr,                                                         // FG_RESTORE_BOUNDS,
127 
128     // No clip (unless ClipToBounds is set)
129     RSPointLightDrawable::OnGenerate,                                // POINT_LIGHT,
130     RSBorderDrawable::OnGenerate,                                    // BORDER,
131     ModifierGenerator<ModifierNG::RSModifierType::OVERLAY_STYLE>,    // OVERLAY,
132     RSParticleDrawable::OnGenerate,                                  // PARTICLE_EFFECT,
133     RSPixelStretchDrawable::OnGenerate,                              // PIXEL_STRETCH,
134 
135     // Restore state
136     RSEndBlenderDrawable::OnGenerate,                                // RESTORE_BLENDER,
137     RSForegroundFilterRestoreDrawable::OnGenerate,                   // RESTORE_FOREGROUND_FILTER
138     nullptr,                                                         // RESTORE_ALL,
139 };
140 
141 enum DrawableVecStatus : uint8_t {
142     CLIP_TO_BOUNDS     = 1 << 0,
143     BG_BOUNDS_PROPERTY = 1 << 1,
144     FG_BOUNDS_PROPERTY = 1 << 2,
145     ENV_CHANGED        = 1 << 3,
146     // Used by skip logic in RSRenderNode::UpdateDisplayList
147     FRAME_NOT_EMPTY    = 1 << 4,
148     NODE_NOT_EMPTY     = 1 << 5,
149 
150     // masks
151     BOUNDS_MASK  = CLIP_TO_BOUNDS | BG_BOUNDS_PROPERTY | FG_BOUNDS_PROPERTY,
152     FRAME_MASK   = FRAME_NOT_EMPTY,
153     OTHER_MASK   = ENV_CHANGED,
154 };
155 
HasPropertyDrawableInRange(const RSDrawable::Vec & drawableVec,RSDrawableSlot begin,RSDrawableSlot end)156 inline static bool HasPropertyDrawableInRange(
157     const RSDrawable::Vec& drawableVec, RSDrawableSlot begin, RSDrawableSlot end) noexcept
158 {
159     // Note: the loop range is [begin, end], both end is included.
160     auto beginIt = drawableVec.begin() + static_cast<size_t>(begin);
161     auto endIt = drawableVec.begin() + static_cast<size_t>(end) + 1;
162     return std::any_of(beginIt, endIt, [](const auto& Ptr) { return Ptr != nullptr; });
163 }
164 
CalculateDrawableVecStatus(RSRenderNode & node,const RSDrawable::Vec & drawableVec)165 static uint8_t CalculateDrawableVecStatus(RSRenderNode& node, const RSDrawable::Vec& drawableVec)
166 {
167     uint8_t result = 0;
168     bool nodeNotEmpty = false;
169     auto& properties = node.GetRenderProperties();
170 
171     // ClipToBounds if either 1. is surface node, 2. has explicit clip properties, 3. has blend mode
172     bool shouldClipToBounds = node.IsInstanceOf<RSSurfaceRenderNode>() || properties.GetClipToBounds() ||
173                               properties.GetClipToRRect() || properties.GetClipBounds() != nullptr ||
174                               properties.GetColorBlendMode() != static_cast<int>(RSColorBlendMode::NONE) ||
175                               properties.IsFgBrightnessValid();
176     if (shouldClipToBounds) {
177         result |= DrawableVecStatus::CLIP_TO_BOUNDS;
178     }
179 
180     if (HasPropertyDrawableInRange(
181         drawableVec, RSDrawableSlot::CONTENT_BEGIN, RSDrawableSlot::CONTENT_END)) {
182         nodeNotEmpty = true;
183         result |= DrawableVecStatus::FRAME_NOT_EMPTY;
184     }
185 
186     if (HasPropertyDrawableInRange(
187         drawableVec, RSDrawableSlot::BG_PROPERTIES_BEGIN, RSDrawableSlot::BG_PROPERTIES_END)) {
188         result |= DrawableVecStatus::BG_BOUNDS_PROPERTY;
189         nodeNotEmpty = true;
190     }
191     if (HasPropertyDrawableInRange(
192         drawableVec, RSDrawableSlot::FG_PROPERTIES_BEGIN, RSDrawableSlot::FG_PROPERTIES_END)) {
193         result |= DrawableVecStatus::FG_BOUNDS_PROPERTY;
194         nodeNotEmpty = true;
195     }
196 
197     nodeNotEmpty = nodeNotEmpty ||
198         HasPropertyDrawableInRange(
199             drawableVec, RSDrawableSlot::TRANSITION_PROPERTIES_BEGIN, RSDrawableSlot::TRANSITION_PROPERTIES_END) ||
200         HasPropertyDrawableInRange(
201             drawableVec, RSDrawableSlot::EXTRA_PROPERTIES_BEGIN, RSDrawableSlot::EXTRA_PROPERTIES_END);
202     if (nodeNotEmpty) {
203         // Set NODE_NOT_EMPTY flag if any drawable (include frame/bg/fg/transition/extra) is set
204         result |= DrawableVecStatus::NODE_NOT_EMPTY;
205     }
206 
207     // Foreground color & Background Effect & Blend Mode should be processed here
208     if (drawableVec[static_cast<size_t>(RSDrawableSlot::ENV_FOREGROUND_COLOR)] ||
209         drawableVec[static_cast<size_t>(RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY)] ||
210         drawableVec[static_cast<size_t>(RSDrawableSlot::BLENDER)] ||
211         (node.GetType() == RSRenderNodeType::EFFECT_NODE &&
212             drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)])) {
213         result |= DrawableVecStatus::ENV_CHANGED;
214     }
215 
216     return result;
217 }
218 
SaveRestoreHelper(RSDrawable::Vec & drawableVec,RSDrawableSlot slot1,RSDrawableSlot slot2,RSPaintFilterCanvas::SaveType type=RSPaintFilterCanvas::kCanvas)219 inline static void SaveRestoreHelper(RSDrawable::Vec& drawableVec, RSDrawableSlot slot1, RSDrawableSlot slot2,
220     RSPaintFilterCanvas::SaveType type = RSPaintFilterCanvas::kCanvas)
221 {
222     if (type == RSPaintFilterCanvas::kNone) {
223         return;
224     }
225     if (type == RSPaintFilterCanvas::kCanvas) {
226         auto count = std::make_shared<uint32_t>(std::numeric_limits<uint32_t>::max());
227         drawableVec[static_cast<size_t>(slot1)] = std::make_unique<RSSaveDrawable>(count);
228         drawableVec[static_cast<size_t>(slot2)] = std::make_unique<RSRestoreDrawable>(count);
229     } else {
230         auto status = std::make_shared<RSPaintFilterCanvas::SaveStatus>();
231         drawableVec[static_cast<size_t>(slot1)] = std::make_unique<RSCustomSaveDrawable>(status, type);
232         drawableVec[static_cast<size_t>(slot2)] = std::make_unique<RSCustomRestoreDrawable>(status);
233     }
234 }
235 
OptimizeBoundsSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)236 static void OptimizeBoundsSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
237 {
238     // Erase existing save/clip/restore before re-generating
239     constexpr static std::array boundsSlotsToErase = {
240         RSDrawableSlot::BG_SAVE_BOUNDS,
241         RSDrawableSlot::CLIP_TO_BOUNDS,
242         RSDrawableSlot::BG_RESTORE_BOUNDS,
243         RSDrawableSlot::FG_SAVE_BOUNDS,
244         RSDrawableSlot::FG_CLIP_TO_BOUNDS,
245         RSDrawableSlot::FG_RESTORE_BOUNDS,
246     };
247     for (auto& slot : boundsSlotsToErase) {
248         drawableVec[static_cast<size_t>(slot)] = nullptr;
249     }
250 
251     if (flags & DrawableVecStatus::CLIP_TO_BOUNDS) {
252         // case 1: ClipToBounds set.
253         // add one clip, and reuse SAVE_ALL and RESTORE_ALL.
254         drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
255         return;
256     }
257 
258     if ((flags & DrawableVecStatus::BG_BOUNDS_PROPERTY) && (flags & DrawableVecStatus::FG_BOUNDS_PROPERTY)) {
259         // case 2: ClipToBounds not set and we have bounds properties both BG and FG.
260         // add two sets of save/clip/restore before & after content.
261 
262         // part 1: before children
263         SaveRestoreHelper(drawableVec, RSDrawableSlot::BG_SAVE_BOUNDS, RSDrawableSlot::BG_RESTORE_BOUNDS,
264             RSPaintFilterCanvas::kCanvas);
265         drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
266 
267         // part 2: after children, add aliases
268         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_SAVE_BOUNDS)] =
269             drawableVec[static_cast<size_t>(RSDrawableSlot::BG_SAVE_BOUNDS)];
270         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_CLIP_TO_BOUNDS)] =
271             drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)];
272         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_RESTORE_BOUNDS)] =
273             drawableVec[static_cast<size_t>(RSDrawableSlot::BG_RESTORE_BOUNDS)];
274         return;
275     }
276 
277     if (flags & DrawableVecStatus::BG_BOUNDS_PROPERTY) {
278         // case 3: ClipToBounds not set and we have background bounds properties.
279         SaveRestoreHelper(drawableVec, RSDrawableSlot::BG_SAVE_BOUNDS, RSDrawableSlot::BG_RESTORE_BOUNDS,
280             RSPaintFilterCanvas::kCanvas);
281 
282         drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
283         return;
284     }
285 
286     if (flags & DrawableVecStatus::FG_BOUNDS_PROPERTY) {
287         // case 4: ClipToBounds not set and we have foreground bounds properties.
288         SaveRestoreHelper(drawableVec, RSDrawableSlot::FG_SAVE_BOUNDS, RSDrawableSlot::FG_RESTORE_BOUNDS,
289             RSPaintFilterCanvas::kCanvas);
290 
291         drawableVec[static_cast<size_t>(RSDrawableSlot::FG_CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
292         return;
293     }
294     // case 5: ClipToBounds not set and no bounds properties, no need to save/clip/restore.
295     // nothing to do
296 }
297 
OptimizeFrameSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)298 static void OptimizeFrameSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
299 {
300     constexpr static std::array frameSlotsToErase = {
301         RSDrawableSlot::SAVE_FRAME,
302         RSDrawableSlot::RESTORE_FRAME,
303     };
304     // Erase existing save/clip/restore before re-generating
305     for (auto& slot : frameSlotsToErase) {
306         drawableVec[static_cast<size_t>(slot)] = nullptr;
307     }
308 
309     if (flags & DrawableVecStatus::FRAME_NOT_EMPTY) {
310         SaveRestoreHelper(
311             drawableVec, RSDrawableSlot::SAVE_FRAME, RSDrawableSlot::RESTORE_FRAME, RSPaintFilterCanvas::kCanvas);
312     }
313 }
314 
OptimizeGlobalSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)315 static void OptimizeGlobalSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
316 {
317     constexpr static std::array globalSlotsToErase = {
318         RSDrawableSlot::SAVE_ALL,
319         RSDrawableSlot::RESTORE_ALL,
320     };
321     // Erase existing save/clip/restore before re-generating
322     for (auto& slot : globalSlotsToErase) {
323         drawableVec[static_cast<size_t>(slot)] = nullptr;
324     }
325 
326     // Parent will do canvas save/restore, we don't need to do it again
327     uint8_t saveType = RSPaintFilterCanvas::SaveType::kNone;
328     if (flags & DrawableVecStatus::ENV_CHANGED) {
329         // If we change env(fg color, effect, blendMode etc), we need to save env
330         saveType |= RSPaintFilterCanvas::SaveType::kEnv;
331     }
332 
333     if (saveType == RSPaintFilterCanvas::SaveType::kNone) {
334         return;
335     }
336     // add save/restore with needed type
337     SaveRestoreHelper(drawableVec, RSDrawableSlot::SAVE_ALL, RSDrawableSlot::RESTORE_ALL,
338         static_cast<RSPaintFilterCanvas::SaveType>(saveType));
339 }
340 
341 constexpr std::array boundsDirtyTypes = {
342     RSDrawableSlot::MASK,
343     RSDrawableSlot::SHADOW,
344     RSDrawableSlot::OUTLINE,
345     RSDrawableSlot::FOREGROUND_FILTER,
346     RSDrawableSlot::CLIP_TO_BOUNDS,
347     RSDrawableSlot::BACKGROUND_COLOR,
348     RSDrawableSlot::BACKGROUND_SHADER,
349     RSDrawableSlot::BACKGROUND_IMAGE,
350     RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY,
351     RSDrawableSlot::FRAME_OFFSET,
352     RSDrawableSlot::FG_CLIP_TO_BOUNDS,
353     RSDrawableSlot::FOREGROUND_COLOR,
354     RSDrawableSlot::POINT_LIGHT,
355     RSDrawableSlot::BORDER,
356     RSDrawableSlot::PIXEL_STRETCH,
357     RSDrawableSlot::RESTORE_FOREGROUND_FILTER,
358 };
359 constexpr std::array frameDirtyTypes = {
360     RSDrawableSlot::CLIP_TO_FRAME,
361     RSDrawableSlot::COMPOSITING_FILTER,
362 };
363 constexpr std::array borderDirtyTypes = {
364     RSDrawableSlot::BACKGROUND_COLOR,
365     RSDrawableSlot::BACKGROUND_SHADER,
366     RSDrawableSlot::BACKGROUND_IMAGE,
367 };
368 constexpr std::array bgfilterDirtyTypes = {
369     RSDrawableSlot::PIXEL_STRETCH,
370 };
371 constexpr std::array stretchDirtyTypes = {
372     RSDrawableSlot::BACKGROUND_FILTER,
373 };
374 const std::unordered_set<RSDrawableSlot> fuzeStretchBlurSafeList = {
375     RSDrawableSlot::BG_RESTORE_BOUNDS,
376     RSDrawableSlot::SAVE_FRAME,
377     RSDrawableSlot::RESTORE_FRAME,
378     RSDrawableSlot::FG_SAVE_BOUNDS,
379     RSDrawableSlot::FG_RESTORE_BOUNDS,
380 };
381 template<std::size_t SIZE>
MarkAffectedSlots(const std::array<RSDrawableSlot,SIZE> & affectedSlots,const RSDrawable::Vec & drawableVec,std::unordered_set<RSDrawableSlot> & dirtySlots)382 inline void MarkAffectedSlots(const std::array<RSDrawableSlot, SIZE>& affectedSlots, const RSDrawable::Vec& drawableVec,
383     std::unordered_set<RSDrawableSlot>& dirtySlots)
384 {
385     for (auto slot : affectedSlots) {
386         if (drawableVec[static_cast<size_t>(slot)]) {
387             dirtySlots.emplace(slot);
388         }
389     }
390 }
391 } // namespace
392 
CalculateDirtySlotsNG(const ModifierNG::ModifierDirtyTypes & dirtyTypes,const Vec & drawableVec)393 std::unordered_set<RSDrawableSlot> RSDrawable::CalculateDirtySlotsNG(
394     const ModifierNG::ModifierDirtyTypes& dirtyTypes, const Vec& drawableVec)
395 {
396     // Step 1.1: calculate dirty slots by looking up g_propertyToDrawableLut
397     std::unordered_set<RSDrawableSlot> dirtySlots;
398     for (const auto& [modifierType, drawableSlot] : g_propertyToDrawableLutNG) {
399         if (dirtyTypes.test(static_cast<size_t>(modifierType)) && drawableSlot != RSDrawableSlot::INVALID) {
400             dirtySlots.emplace(drawableSlot);
401         }
402     }
403 
404     // Step 1.2: expand dirty slots by rules
405     // if bounds or cornerRadius changed, mark affected drawables as dirty
406     if (dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::BOUNDS)) ||
407         dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::CLIP_TO_BOUNDS))) {
408         MarkAffectedSlots(boundsDirtyTypes, drawableVec, dirtySlots);
409     }
410 
411     if (dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::SHADOW))) {
412         dirtySlots.emplace(RSDrawableSlot::FOREGROUND_FILTER);
413         // adapt to USE_SHADOW_BATCHING
414         dirtySlots.emplace(RSDrawableSlot::CHILDREN);
415     }
416 
417     if (dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::FRAME))) {
418         dirtySlots.emplace(RSDrawableSlot::CONTENT_STYLE);
419         dirtySlots.emplace(RSDrawableSlot::FOREGROUND_STYLE);
420     }
421 
422     if (dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::COMPOSITING_FILTER))) {
423         dirtySlots.emplace(RSDrawableSlot::LIGHT_UP_EFFECT);
424         dirtySlots.emplace(RSDrawableSlot::BINARIZATION);
425         dirtySlots.emplace(RSDrawableSlot::DYNAMIC_DIM);
426         dirtySlots.emplace(RSDrawableSlot::COLOR_FILTER);
427     }
428 
429     if (dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::ENV_FOREGROUND_COLOR))) {
430         dirtySlots.emplace(RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY);
431     }
432 
433     if (dirtyTypes.test(static_cast<size_t>(ModifierNG::RSModifierType::CLIP_TO_FRAME))) {
434         dirtySlots.emplace(RSDrawableSlot::CUSTOM_CLIP_TO_FRAME);
435         dirtySlots.emplace(RSDrawableSlot::FRAME_OFFSET);
436         // CONTENT_STYLE and FOREGROUND_STYLE are used to adapt to FRAME_GRAVITY.
437         dirtySlots.emplace(RSDrawableSlot::CONTENT_STYLE);
438         dirtySlots.emplace(RSDrawableSlot::FOREGROUND_STYLE);
439     }
440 
441     // if frame changed, mark affected drawables as dirty
442     if (dirtySlots.count(RSDrawableSlot::FRAME_OFFSET)) {
443         MarkAffectedSlots(frameDirtyTypes, drawableVec, dirtySlots);
444     }
445 
446     // if border changed, mark affected drawables as dirty
447     if (dirtySlots.count(RSDrawableSlot::BORDER)) {
448         MarkAffectedSlots(borderDirtyTypes, drawableVec, dirtySlots);
449     }
450 
451     // PLANNING: merge these restore operations with RESTORE_ALL drawable
452     if (dirtySlots.count(RSDrawableSlot::FOREGROUND_FILTER)) {
453         dirtySlots.emplace(RSDrawableSlot::RESTORE_FOREGROUND_FILTER);
454     }
455 
456     // if pixel-stretch changed, mark affected drawables as dirty
457     if (dirtySlots.count(RSDrawableSlot::PIXEL_STRETCH)) {
458         MarkAffectedSlots(stretchDirtyTypes, drawableVec, dirtySlots);
459     }
460     // if background filter changed, mark affected drawables as dirty
461     if (dirtySlots.count(RSDrawableSlot::BACKGROUND_FILTER)) {
462         MarkAffectedSlots(bgfilterDirtyTypes, drawableVec, dirtySlots);
463     }
464 
465     return dirtySlots;
466 }
467 
UpdateDirtySlots(const RSRenderNode & node,Vec & drawableVec,std::unordered_set<RSDrawableSlot> & dirtySlots)468 bool RSDrawable::UpdateDirtySlots(
469     const RSRenderNode& node, Vec& drawableVec, std::unordered_set<RSDrawableSlot>& dirtySlots)
470 {
471     // Step 2: Update or generate all dirty slots
472     bool drawableAddedOrRemoved = false;
473 
474     for (const auto& slot : dirtySlots) {
475         if (auto& drawable = drawableVec[static_cast<size_t>(slot)]) {
476             // If the slot is already created, call OnUpdate
477             if (!drawable->OnUpdate(node)) {
478                 // If the slot is no longer needed, destroy it
479                 drawable.reset();
480                 drawableAddedOrRemoved = true;
481             }
482         } else if (auto& generator = g_drawableGeneratorLut[static_cast<int>(slot)]) {
483             // If the slot is not created, call OnGenerate
484             if (auto drawable = generator(node)) {
485                 drawableVec[static_cast<size_t>(slot)] = std::move(drawable);
486                 drawableAddedOrRemoved = true;
487             }
488         }
489     }
490     // If at this point the child node happens to be null, and the scenario involves deleting the child node
491     // when the parent node is not on the tree, it is necessary to manually mark drawableAddedOrRemoved as true.
492     if (!drawableAddedOrRemoved && dirtySlots.count(RSDrawableSlot::CHILDREN) &&
493         drawableVec[static_cast<int8_t>(RSDrawableSlot::CHILDREN)] == nullptr) {
494         drawableAddedOrRemoved = true;
495     }
496 
497     return drawableAddedOrRemoved;
498 }
499 
ResetPixelStretchSlot(const RSRenderNode & node,Vec & drawableVec)500 void RSDrawable::ResetPixelStretchSlot(const RSRenderNode &node, Vec &drawableVec)
501 {
502     auto &stretchDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)];
503     if (stretchDrawable) {
504         auto pixelStretchDrawable = std::static_pointer_cast<RSPixelStretchDrawable>(stretchDrawable);
505         pixelStretchDrawable->OnUpdate(node);
506         float INFTY = std::numeric_limits<float>::infinity();
507         pixelStretchDrawable->SetPixelStretch(Vector4f{INFTY, INFTY, INFTY, INFTY});
508     }
509 }
510 
CanFusePixelStretch(Vec & drawableVec)511 bool RSDrawable::CanFusePixelStretch(Vec &drawableVec)
512 {
513     if (!drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)] ||
514         !drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)]) {
515             return false;
516     }
517 
518     size_t start = static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER) + 1;
519     size_t end = static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH);
520     // we do not fuze if drawableSlots between BACKGROUND_FILTER and PIXEL_STRETCH exist
521     for (size_t ptr = start; ptr < end; ptr++) {
522         if (!fuzeStretchBlurSafeList.count(static_cast<RSDrawableSlot>(ptr)) && drawableVec[ptr]) {
523             return false;
524         }
525     }
526     return true;
527 }
528 
FuzeDrawableSlots(const RSRenderNode & node,Vec & drawableVec)529 bool RSDrawable::FuzeDrawableSlots(const RSRenderNode& node, Vec& drawableVec)
530 {
531     // fuze the pixel stretch with MESA blur
532     if (!RSSystemProperties::GetMESABlurFuzedEnabled() ||
533         !drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)] ||
534         !drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)]) {
535         return false;
536     }
537 
538     auto &filterDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)];
539     auto bgFilterDrawable = std::static_pointer_cast<RSBackgroundFilterDrawable>(filterDrawable);
540     bgFilterDrawable->RemovePixelStretch();
541 
542     auto &stretchDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)];
543     auto pixelStretchDrawable = std::static_pointer_cast<RSPixelStretchDrawable>(stretchDrawable);
544     pixelStretchDrawable->OnUpdate(node);
545 
546     size_t start = static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER) + 1;
547     size_t end = static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH);
548     // We do not fuze if drawableSlots between BACKGROUND_FILTER and PIXEL_STRETCH exist
549     for (size_t ptr = start; ptr < end; ptr++) {
550         if (!fuzeStretchBlurSafeList.count(static_cast<RSDrawableSlot>(ptr)) && drawableVec[ptr]) {
551             return false;
552         }
553     }
554     if (bgFilterDrawable->FuzePixelStretch(node)) {
555         float INFTY = std::numeric_limits<float>::infinity();
556         pixelStretchDrawable->SetPixelStretch(Vector4f{ INFTY, INFTY, INFTY, INFTY });
557         return true;
558     }
559 
560     return false;
561 }
562 
UpdateSaveRestore(RSRenderNode & node,Vec & drawableVec,uint8_t & drawableVecStatus)563 void RSDrawable::UpdateSaveRestore(RSRenderNode& node, Vec& drawableVec, uint8_t& drawableVecStatus)
564 {
565     // ====================================================================
566     // Step 3: Universal save/clip/restore optimization
567 
568     // Step 3.1: calculate new drawable map status
569     auto drawableVecStatusNew = CalculateDrawableVecStatus(node, drawableVec);
570 
571     uint8_t changedBits = drawableVecStatus ^ drawableVecStatusNew;
572     if (changedBits == 0) {
573         // nothing to do
574         return;
575     }
576 
577     // Step 3.2: update save/clip/restore for changed types
578     if (changedBits & BOUNDS_MASK) {
579         // update bounds save/clip if need
580         OptimizeBoundsSaveRestore(node, drawableVec, drawableVecStatusNew);
581     }
582     if (changedBits & FRAME_MASK) {
583         // update frame save/clip if need
584         OptimizeFrameSaveRestore(node, drawableVec, drawableVecStatusNew);
585     }
586     if (changedBits & OTHER_MASK) {
587         // update global save/clip if need
588         OptimizeGlobalSaveRestore(node, drawableVec, drawableVecStatusNew);
589     }
590 
591     drawableVecStatus = drawableVecStatusNew;
592 }
593 } // namespace OHOS::Rosen
594