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