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 // NOTE: This LUT should always the same size and order as RSModifierType
32 // key = RSModifierType, value = RSDrawableSlot
33 constexpr int DIRTY_LUT_SIZE = static_cast<int>(RSModifierType::MAX_RS_MODIFIER_TYPE);
34 static constexpr std::array<RSDrawableSlot, DIRTY_LUT_SIZE> g_propertyToDrawableLut = {
35 RSDrawableSlot::INVALID, // INVALID
36 RSDrawableSlot::CLIP_TO_BOUNDS, // BOUNDS
37 RSDrawableSlot::FRAME_OFFSET, // FRAME
38 RSDrawableSlot::INVALID, // POSITION_Z
39 RSDrawableSlot::INVALID, // PIVOT
40 RSDrawableSlot::INVALID, // PIVOT_Z
41 RSDrawableSlot::INVALID, // QUATERNION
42 RSDrawableSlot::INVALID, // ROTATION
43 RSDrawableSlot::INVALID, // ROTATION_X
44 RSDrawableSlot::INVALID, // ROTATION_Y
45 RSDrawableSlot::INVALID, // CAMERA_DISTANCE
46 RSDrawableSlot::INVALID, // SCALE
47 RSDrawableSlot::INVALID, // SKEW
48 RSDrawableSlot::INVALID, // PERSP
49 RSDrawableSlot::INVALID, // TRANSLATE
50 RSDrawableSlot::INVALID, // TRANSLATE_Z
51 RSDrawableSlot::INVALID, // SUBLAYER_TRANSFORM
52 RSDrawableSlot::CLIP_TO_BOUNDS, // CORNER_RADIUS
53 RSDrawableSlot::INVALID, // ALPHA
54 RSDrawableSlot::INVALID, // ALPHA_OFFSCREEN
55 RSDrawableSlot::FOREGROUND_COLOR, // FOREGROUND_COLOR
56 RSDrawableSlot::BACKGROUND_COLOR, // BACKGROUND_COLOR
57 RSDrawableSlot::BACKGROUND_SHADER, // BACKGROUND_SHADER
58 RSDrawableSlot::BACKGROUND_IMAGE, // BG_IMAGE
59 RSDrawableSlot::BACKGROUND_IMAGE, // BG_IMAGE_INNER_RECT
60 RSDrawableSlot::BACKGROUND_IMAGE, // BG_IMAGE_WIDTH
61 RSDrawableSlot::BACKGROUND_IMAGE, // BG_IMAGE_HEIGHT
62 RSDrawableSlot::BACKGROUND_IMAGE, // BG_IMAGE_POSITION_X
63 RSDrawableSlot::BACKGROUND_IMAGE, // BG_IMAGE_POSITION_Y
64 RSDrawableSlot::INVALID, // SURFACE_BG_COLOR
65 RSDrawableSlot::BORDER, // BORDER_COLOR
66 RSDrawableSlot::BORDER, // BORDER_WIDTH
67 RSDrawableSlot::BORDER, // BORDER_STYLE
68 RSDrawableSlot::BORDER, // BORDER_DASH_WIDTH
69 RSDrawableSlot::BORDER, // BORDER_DASH_GAP
70 RSDrawableSlot::COMPOSITING_FILTER, // FILTER
71 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_FILTER
72 RSDrawableSlot::COMPOSITING_FILTER, // LINEAR_GRADIENT_BLUR_PARA
73 RSDrawableSlot::DYNAMIC_LIGHT_UP, // DYNAMIC_LIGHT_UP_RATE
74 RSDrawableSlot::DYNAMIC_LIGHT_UP, // DYNAMIC_LIGHT_UP_DEGREE
75 RSDrawableSlot::BLENDER, // FG_BRIGHTNESS_RATES
76 RSDrawableSlot::BLENDER, // FG_BRIGHTNESS_SATURATION
77 RSDrawableSlot::BLENDER, // FG_BRIGHTNESS_POSCOEFF
78 RSDrawableSlot::BLENDER, // FG_BRIGHTNESS_NEGCOEFF
79 RSDrawableSlot::BLENDER, // FG_BRIGHTNESS_FRACTION
80 RSDrawableSlot::BACKGROUND_COLOR, // BG_BRIGHTNESS_RATES
81 RSDrawableSlot::BACKGROUND_COLOR, // BG_BRIGHTNESS_SATURATION
82 RSDrawableSlot::BACKGROUND_COLOR, // BG_BRIGHTNESS_POSCOEFF
83 RSDrawableSlot::BACKGROUND_COLOR, // BG_BRIGHTNESS_NEGCOEFF
84 RSDrawableSlot::BACKGROUND_COLOR, // BG_BRIGHTNESS_FRACTION
85 RSDrawableSlot::FRAME_OFFSET, // FRAME_GRAVITY
86 RSDrawableSlot::CLIP_TO_BOUNDS, // CLIP_RRECT
87 RSDrawableSlot::CLIP_TO_BOUNDS, // CLIP_BOUNDS
88 RSDrawableSlot::CLIP_TO_BOUNDS, // CLIP_TO_BOUNDS
89 RSDrawableSlot::CLIP_TO_FRAME, // CLIP_TO_FRAME
90 RSDrawableSlot::INVALID, // VISIBLE
91 RSDrawableSlot::SHADOW, // SHADOW_COLOR
92 RSDrawableSlot::SHADOW, // SHADOW_OFFSET_X
93 RSDrawableSlot::SHADOW, // SHADOW_OFFSET_Y
94 RSDrawableSlot::SHADOW, // SHADOW_ALPHA
95 RSDrawableSlot::SHADOW, // SHADOW_ELEVATION
96 RSDrawableSlot::SHADOW, // SHADOW_RADIUS
97 RSDrawableSlot::SHADOW, // SHADOW_PATH
98 RSDrawableSlot::SHADOW, // SHADOW_MASK
99 RSDrawableSlot::SHADOW, // SHADOW_COLOR_STRATEGY
100 RSDrawableSlot::MASK, // MASK
101 RSDrawableSlot::FOREGROUND_FILTER, // SPHERIZE
102 RSDrawableSlot::LIGHT_UP_EFFECT, // LIGHT_UP_EFFECT
103 RSDrawableSlot::PIXEL_STRETCH, // PIXEL_STRETCH
104 RSDrawableSlot::PIXEL_STRETCH, // PIXEL_STRETCH_PERCENT
105 RSDrawableSlot::PIXEL_STRETCH, // PIXEL_STRETCH_TILE_MODE
106 RSDrawableSlot::USE_EFFECT, // USE_EFFECT
107 RSDrawableSlot::BLENDER, // COLOR_BLEND_MODE
108 RSDrawableSlot::BLENDER, // COLOR_BLEND_APPLY_TYPE
109 RSDrawableSlot::INVALID, // SANDBOX
110 RSDrawableSlot::COLOR_FILTER, // GRAY_SCALE
111 RSDrawableSlot::COLOR_FILTER, // BRIGHTNESS
112 RSDrawableSlot::COLOR_FILTER, // CONTRAST
113 RSDrawableSlot::COLOR_FILTER, // SATURATE
114 RSDrawableSlot::COLOR_FILTER, // SEPIA
115 RSDrawableSlot::COLOR_FILTER, // INVERT
116 RSDrawableSlot::BINARIZATION, // AIINVERT
117 RSDrawableSlot::BACKGROUND_FILTER, // SYSTEMBAREFFECT
118 RSDrawableSlot::BACKGROUND_FILTER, // WATER_RIPPLE_PROGRESS
119 RSDrawableSlot::BACKGROUND_FILTER, // WATER_RIPPLE_EFFECT
120 RSDrawableSlot::COLOR_FILTER, // HUE_ROTATE
121 RSDrawableSlot::COLOR_FILTER, // COLOR_BLEND
122 RSDrawableSlot::PARTICLE_EFFECT, // PARTICLE
123 RSDrawableSlot::SHADOW, // SHADOW_IS_FILLED
124 RSDrawableSlot::OUTLINE, // OUTLINE_COLOR
125 RSDrawableSlot::OUTLINE, // OUTLINE_WIDTH
126 RSDrawableSlot::OUTLINE, // OUTLINE_STYLE
127 RSDrawableSlot::OUTLINE, // OUTLINE_DASH_WIDTH
128 RSDrawableSlot::OUTLINE, // OUTLINE_DASH_GAP
129 RSDrawableSlot::OUTLINE, // OUTLINE_RADIUS
130 RSDrawableSlot::CHILDREN, // USE_SHADOW_BATCHING
131 RSDrawableSlot::INVALID, // GREY_COEF
132 RSDrawableSlot::POINT_LIGHT, // LIGHT_INTENSITY
133 RSDrawableSlot::POINT_LIGHT, // LIGHT_COLOR
134 RSDrawableSlot::POINT_LIGHT, // LIGHT_POSITION
135 RSDrawableSlot::POINT_LIGHT, // ILLUMINATED_BORDER_WIDTH
136 RSDrawableSlot::POINT_LIGHT, // ILLUMINATED_TYPE
137 RSDrawableSlot::POINT_LIGHT, // BLOOM
138 RSDrawableSlot::PARTICLE_EFFECT, // PARTICLE_EMITTER_UPDATER
139 RSDrawableSlot::PARTICLE_EFFECT, // PARTICLE_NOISE_FIELD
140 RSDrawableSlot::FOREGROUND_FILTER, // FOREGROUND_EFFECT_RADIUS
141 RSDrawableSlot::FOREGROUND_FILTER, // MOTION_BLUR_PARA
142 RSDrawableSlot::FOREGROUND_FILTER, // FLY_OUT_DEGREE
143 RSDrawableSlot::FOREGROUND_FILTER, // FLY_OUT_PARAMS
144 RSDrawableSlot::FOREGROUND_FILTER, // DISTORTION_K
145 RSDrawableSlot::DYNAMIC_DIM, // DYNAMIC_DIM
146 RSDrawableSlot::BACKGROUND_FILTER, // MAGNIFIER_PARA,
147 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_RADIUS
148 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_SATURATION
149 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_BRIGHTNESS
150 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_MASK_COLOR
151 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_COLOR_MODE
152 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_RADIUS_X
153 RSDrawableSlot::BACKGROUND_FILTER, // BACKGROUND_BLUR_RADIUS_Y
154 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_RADIUS
155 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_SATURATION
156 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_BRIGHTNESS
157 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_MASK_COLOR
158 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_COLOR_MODE
159 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_RADIUS_X
160 RSDrawableSlot::COMPOSITING_FILTER, // FOREGROUND_BLUR_RADIUS_Y
161 RSDrawableSlot::INVALID, // CUSTOM
162 RSDrawableSlot::INVALID, // EXTENDED
163 RSDrawableSlot::TRANSITION, // TRANSITION
164 RSDrawableSlot::BACKGROUND_STYLE, // BACKGROUND_STYLE
165 RSDrawableSlot::CONTENT_STYLE, // CONTENT_STYLE
166 RSDrawableSlot::FOREGROUND_STYLE, // FOREGROUND_STYLE
167 RSDrawableSlot::OVERLAY, // OVERLAY_STYLE
168 RSDrawableSlot::INVALID, // NODE_MODIFIER
169 RSDrawableSlot::ENV_FOREGROUND_COLOR, // ENV_FOREGROUND_COLOR
170 RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY, // ENV_FOREGROUND_COLOR_STRATEGY
171 RSDrawableSlot::INVALID, // GEOMETRYTRANS
172 RSDrawableSlot::CHILDREN, // CHILDREN
173 };
174
175 // Check if g_propertyToDrawableLut size match and is fully initialized (the last element should not be default value)
176 static_assert(g_propertyToDrawableLut.size() == static_cast<size_t>(RSModifierType::MAX_RS_MODIFIER_TYPE));
177 static_assert(g_propertyToDrawableLut.back() != RSDrawableSlot {});
178
179 // Randomly check some LUT index and value
180 static_assert(g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::USE_EFFECT)] == RSDrawableSlot::USE_EFFECT);
181 static_assert(
182 g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::FOREGROUND_COLOR)] == RSDrawableSlot::FOREGROUND_COLOR);
183 static_assert(
184 g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::CLIP_TO_FRAME)] == RSDrawableSlot::CLIP_TO_FRAME);
185 static_assert(
186 g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::USE_SHADOW_BATCHING)] == RSDrawableSlot::CHILDREN);
187 static_assert(g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::TRANSITION)] == RSDrawableSlot::TRANSITION);
188 static_assert(g_propertyToDrawableLut[static_cast<size_t>(RSModifierType::CHILDREN)] == RSDrawableSlot::CHILDREN);
189
190 template<RSModifierType type>
ModifierGenerator(const RSRenderNode & node)191 static inline RSDrawable::Ptr ModifierGenerator(const RSRenderNode& node)
192 {
193 return RSCustomModifierDrawable::OnGenerate(node, type);
194 }
195
196 // NOTE: This LUT should always the same size as RSDrawableSlot
197 // index = RSDrawableSlotType, value = DrawableGenerator
198 constexpr int GEN_LUT_SIZE = static_cast<int>(RSDrawableSlot::MAX);
199 static const std::array<RSDrawable::Generator, GEN_LUT_SIZE> g_drawableGeneratorLut = {
200 nullptr, // SAVE_ALL
201
202 // Bounds Geometry
203 RSMaskDrawable::OnGenerate, // MASK,
204 ModifierGenerator<RSModifierType::TRANSITION>, // TRANSITION,
205 RSEnvFGColorDrawable::OnGenerate, // ENV_FOREGROUND_COLOR,
206 RSShadowDrawable::OnGenerate, // SHADOW,
207 RSForegroundFilterDrawable::OnGenerate, // FOREGROUND_FILTER
208 RSOutlineDrawable::OnGenerate, // OUTLINE,
209
210 // BG properties in Bounds Clip
211 nullptr, // BG_SAVE_BOUNDS,
212 nullptr, // CLIP_TO_BOUNDS,
213 RSBeginBlenderDrawable::OnGenerate, // BLENDER,
214 RSBackgroundColorDrawable::OnGenerate, // BACKGROUND_COLOR,
215 RSBackgroundShaderDrawable::OnGenerate, // BACKGROUND_SHADER,
216 RSBackgroundImageDrawable::OnGenerate, // BACKGROUND_IMAGE,
217 RSBackgroundFilterDrawable::OnGenerate, // BACKGROUND_FILTER,
218 RSUseEffectDrawable::OnGenerate, // USE_EFFECT,
219 ModifierGenerator<RSModifierType::BACKGROUND_STYLE>, // BACKGROUND_STYLE,
220 RSDynamicLightUpDrawable::OnGenerate, // DYNAMIC_LIGHT_UP,
221 RSEnvFGColorStrategyDrawable::OnGenerate, // ENV_FOREGROUND_COLOR_STRATEGY,
222 nullptr, // BG_RESTORE_BOUNDS,
223
224 // Frame Geometry
225 nullptr, // SAVE_FRAME,
226 RSFrameOffsetDrawable::OnGenerate, // FRAME_OFFSET,
227 RSClipToFrameDrawable::OnGenerate, // CLIP_TO_FRAME,
228 ModifierGenerator<RSModifierType::CONTENT_STYLE>, // CONTENT_STYLE,
229 RSChildrenDrawable::OnGenerate, // CHILDREN,
230 ModifierGenerator<RSModifierType::FOREGROUND_STYLE>, // FOREGROUND_STYLE,
231 nullptr, // RESTORE_FRAME,
232
233 // FG properties in Bounds clip
234 nullptr, // FG_SAVE_BOUNDS,
235 nullptr, // FG_CLIP_TO_BOUNDS,
236 RSBinarizationDrawable::OnGenerate, // BINARIZATION,
237 RSColorFilterDrawable::OnGenerate, // COLOR_FILTER,
238 RSLightUpEffectDrawable::OnGenerate, // LIGHT_UP_EFFECT,
239 RSDynamicDimDrawable::OnGenerate, // DYNAMIC_DIM,
240 RSCompositingFilterDrawable::OnGenerate, // COMPOSITING_FILTER,
241 RSForegroundColorDrawable::OnGenerate, // FOREGROUND_COLOR,
242 nullptr, // FG_RESTORE_BOUNDS,
243
244 // No clip (unless ClipToBounds is set)
245 RSPointLightDrawable::OnGenerate, // POINT_LIGHT,
246 RSBorderDrawable::OnGenerate, // BORDER,
247 ModifierGenerator<RSModifierType::OVERLAY_STYLE>, // OVERLAY,
248 RSParticleDrawable::OnGenerate, // PARTICLE_EFFECT,
249 RSPixelStretchDrawable::OnGenerate, // PIXEL_STRETCH,
250
251 // Restore state
252 RSEndBlenderDrawable::OnGenerate, // RESTORE_BLENDER,
253 RSForegroundFilterRestoreDrawable::OnGenerate, // RESTORE_FOREGROUND_FILTER
254 nullptr, // RESTORE_ALL,
255 };
256
257 enum DrawableVecStatus : uint8_t {
258 CLIP_TO_BOUNDS = 1 << 0,
259 BG_BOUNDS_PROPERTY = 1 << 1,
260 FG_BOUNDS_PROPERTY = 1 << 2,
261 ENV_CHANGED = 1 << 3,
262 // Used by skip logic in RSRenderNode::UpdateDisplayList
263 FRAME_NOT_EMPTY = 1 << 4,
264 NODE_NOT_EMPTY = 1 << 5,
265
266 // masks
267 BOUNDS_MASK = CLIP_TO_BOUNDS | BG_BOUNDS_PROPERTY | FG_BOUNDS_PROPERTY,
268 FRAME_MASK = FRAME_NOT_EMPTY,
269 OTHER_MASK = ENV_CHANGED,
270 };
271
HasPropertyDrawableInRange(const RSDrawable::Vec & drawableVec,RSDrawableSlot begin,RSDrawableSlot end)272 inline static bool HasPropertyDrawableInRange(
273 const RSDrawable::Vec& drawableVec, RSDrawableSlot begin, RSDrawableSlot end) noexcept
274 {
275 // Note: the loop range is [begin, end], both end is included.
276 auto beginIt = drawableVec.begin() + static_cast<size_t>(begin);
277 auto endIt = drawableVec.begin() + static_cast<size_t>(end) + 1;
278 return std::any_of(beginIt, endIt, [](const auto& Ptr) { return Ptr != nullptr; });
279 }
280
CalculateDrawableVecStatus(RSRenderNode & node,const RSDrawable::Vec & drawableVec)281 static uint8_t CalculateDrawableVecStatus(RSRenderNode& node, const RSDrawable::Vec& drawableVec)
282 {
283 uint8_t result = 0;
284 bool nodeNotEmpty = false;
285 auto& properties = node.GetRenderProperties();
286
287 // ClipToBounds if either 1. is surface node, 2. has explicit clip properties, 3. has blend mode
288 bool shouldClipToBounds = node.IsInstanceOf<RSSurfaceRenderNode>() || properties.GetClipToBounds() ||
289 properties.GetClipToRRect() || properties.GetClipBounds() != nullptr ||
290 properties.GetColorBlendMode() != static_cast<int>(RSColorBlendMode::NONE) ||
291 properties.IsFgBrightnessValid();
292 if (shouldClipToBounds) {
293 result |= DrawableVecStatus::CLIP_TO_BOUNDS;
294 }
295
296 if (HasPropertyDrawableInRange(
297 drawableVec, RSDrawableSlot::CONTENT_BEGIN, RSDrawableSlot::CONTENT_END)) {
298 nodeNotEmpty = true;
299 result |= DrawableVecStatus::FRAME_NOT_EMPTY;
300 }
301
302 if (HasPropertyDrawableInRange(
303 drawableVec, RSDrawableSlot::BG_PROPERTIES_BEGIN, RSDrawableSlot::BG_PROPERTIES_END)) {
304 result |= DrawableVecStatus::BG_BOUNDS_PROPERTY;
305 nodeNotEmpty = true;
306 }
307 if (HasPropertyDrawableInRange(
308 drawableVec, RSDrawableSlot::FG_PROPERTIES_BEGIN, RSDrawableSlot::FG_PROPERTIES_END)) {
309 result |= DrawableVecStatus::FG_BOUNDS_PROPERTY;
310 nodeNotEmpty = true;
311 }
312
313 nodeNotEmpty = nodeNotEmpty ||
314 HasPropertyDrawableInRange(
315 drawableVec, RSDrawableSlot::TRANSITION_PROPERTIES_BEGIN, RSDrawableSlot::TRANSITION_PROPERTIES_END) ||
316 HasPropertyDrawableInRange(
317 drawableVec, RSDrawableSlot::EXTRA_PROPERTIES_BEGIN, RSDrawableSlot::EXTRA_PROPERTIES_END);
318 if (nodeNotEmpty) {
319 // Set NODE_NOT_EMPTY flag if any drawable (include frame/bg/fg/transition/extra) is set
320 result |= DrawableVecStatus::NODE_NOT_EMPTY;
321 }
322
323 // Foreground color & Background Effect & Blend Mode should be processed here
324 if (drawableVec[static_cast<size_t>(RSDrawableSlot::ENV_FOREGROUND_COLOR)] ||
325 drawableVec[static_cast<size_t>(RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY)] ||
326 drawableVec[static_cast<size_t>(RSDrawableSlot::BLENDER)] ||
327 (node.GetType() == RSRenderNodeType::EFFECT_NODE &&
328 drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)])) {
329 result |= DrawableVecStatus::ENV_CHANGED;
330 }
331
332 return result;
333 }
334
SaveRestoreHelper(RSDrawable::Vec & drawableVec,RSDrawableSlot slot1,RSDrawableSlot slot2,RSPaintFilterCanvas::SaveType type=RSPaintFilterCanvas::kCanvas)335 inline static void SaveRestoreHelper(RSDrawable::Vec& drawableVec, RSDrawableSlot slot1, RSDrawableSlot slot2,
336 RSPaintFilterCanvas::SaveType type = RSPaintFilterCanvas::kCanvas)
337 {
338 if (type == RSPaintFilterCanvas::kNone) {
339 return;
340 }
341 if (type == RSPaintFilterCanvas::kCanvas) {
342 auto count = std::make_shared<uint32_t>(std::numeric_limits<uint32_t>::max());
343 drawableVec[static_cast<size_t>(slot1)] = std::make_unique<RSSaveDrawable>(count);
344 drawableVec[static_cast<size_t>(slot2)] = std::make_unique<RSRestoreDrawable>(count);
345 } else {
346 auto status = std::make_shared<RSPaintFilterCanvas::SaveStatus>();
347 drawableVec[static_cast<size_t>(slot1)] = std::make_unique<RSCustomSaveDrawable>(status, type);
348 drawableVec[static_cast<size_t>(slot2)] = std::make_unique<RSCustomRestoreDrawable>(status);
349 }
350 }
351
OptimizeBoundsSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)352 static void OptimizeBoundsSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
353 {
354 // Erase existing save/clip/restore before re-generating
355 constexpr static std::array boundsSlotsToErase = {
356 RSDrawableSlot::BG_SAVE_BOUNDS,
357 RSDrawableSlot::CLIP_TO_BOUNDS,
358 RSDrawableSlot::BG_RESTORE_BOUNDS,
359 RSDrawableSlot::FG_SAVE_BOUNDS,
360 RSDrawableSlot::FG_CLIP_TO_BOUNDS,
361 RSDrawableSlot::FG_RESTORE_BOUNDS,
362 };
363 for (auto& slot : boundsSlotsToErase) {
364 drawableVec[static_cast<size_t>(slot)] = nullptr;
365 }
366
367 if (flags & DrawableVecStatus::CLIP_TO_BOUNDS) {
368 // case 1: ClipToBounds set.
369 // add one clip, and reuse SAVE_ALL and RESTORE_ALL.
370 drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
371 return;
372 }
373
374 if ((flags & DrawableVecStatus::BG_BOUNDS_PROPERTY) && (flags & DrawableVecStatus::FG_BOUNDS_PROPERTY)) {
375 // case 2: ClipToBounds not set and we have bounds properties both BG and FG.
376 // add two sets of save/clip/restore before & after content.
377
378 // part 1: before children
379 SaveRestoreHelper(drawableVec, RSDrawableSlot::BG_SAVE_BOUNDS, RSDrawableSlot::BG_RESTORE_BOUNDS,
380 RSPaintFilterCanvas::kCanvas);
381 drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
382
383 // part 2: after children, add aliases
384 drawableVec[static_cast<size_t>(RSDrawableSlot::FG_SAVE_BOUNDS)] =
385 drawableVec[static_cast<size_t>(RSDrawableSlot::BG_SAVE_BOUNDS)];
386 drawableVec[static_cast<size_t>(RSDrawableSlot::FG_CLIP_TO_BOUNDS)] =
387 drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)];
388 drawableVec[static_cast<size_t>(RSDrawableSlot::FG_RESTORE_BOUNDS)] =
389 drawableVec[static_cast<size_t>(RSDrawableSlot::BG_RESTORE_BOUNDS)];
390 return;
391 }
392
393 if (flags & DrawableVecStatus::BG_BOUNDS_PROPERTY) {
394 // case 3: ClipToBounds not set and we have background bounds properties.
395 SaveRestoreHelper(drawableVec, RSDrawableSlot::BG_SAVE_BOUNDS, RSDrawableSlot::BG_RESTORE_BOUNDS,
396 RSPaintFilterCanvas::kCanvas);
397
398 drawableVec[static_cast<size_t>(RSDrawableSlot::CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
399 return;
400 }
401
402 if (flags & DrawableVecStatus::FG_BOUNDS_PROPERTY) {
403 // case 4: ClipToBounds not set and we have foreground bounds properties.
404 SaveRestoreHelper(drawableVec, RSDrawableSlot::FG_SAVE_BOUNDS, RSDrawableSlot::FG_RESTORE_BOUNDS,
405 RSPaintFilterCanvas::kCanvas);
406
407 drawableVec[static_cast<size_t>(RSDrawableSlot::FG_CLIP_TO_BOUNDS)] = RSClipToBoundsDrawable::OnGenerate(node);
408 return;
409 }
410 // case 5: ClipToBounds not set and no bounds properties, no need to save/clip/restore.
411 // nothing to do
412 }
413
OptimizeFrameSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)414 static void OptimizeFrameSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
415 {
416 constexpr static std::array frameSlotsToErase = {
417 RSDrawableSlot::SAVE_FRAME,
418 RSDrawableSlot::RESTORE_FRAME,
419 };
420 // Erase existing save/clip/restore before re-generating
421 for (auto& slot : frameSlotsToErase) {
422 drawableVec[static_cast<size_t>(slot)] = nullptr;
423 }
424
425 if (flags & DrawableVecStatus::FRAME_NOT_EMPTY) {
426 SaveRestoreHelper(
427 drawableVec, RSDrawableSlot::SAVE_FRAME, RSDrawableSlot::RESTORE_FRAME, RSPaintFilterCanvas::kCanvas);
428 }
429 }
430
OptimizeGlobalSaveRestore(RSRenderNode & node,RSDrawable::Vec & drawableVec,uint8_t flags)431 static void OptimizeGlobalSaveRestore(RSRenderNode& node, RSDrawable::Vec& drawableVec, uint8_t flags)
432 {
433 constexpr static std::array globalSlotsToErase = {
434 RSDrawableSlot::SAVE_ALL,
435 RSDrawableSlot::RESTORE_ALL,
436 };
437 // Erase existing save/clip/restore before re-generating
438 for (auto& slot : globalSlotsToErase) {
439 drawableVec[static_cast<size_t>(slot)] = nullptr;
440 }
441
442 // Parent will do canvas save/restore, we don't need to do it again
443 uint8_t saveType = RSPaintFilterCanvas::SaveType::kNone;
444 if (flags & DrawableVecStatus::ENV_CHANGED) {
445 // If we change env(fg color, effect, blendMode etc), we need to save env
446 saveType |= RSPaintFilterCanvas::SaveType::kEnv;
447 }
448
449 if (saveType == RSPaintFilterCanvas::SaveType::kNone) {
450 return;
451 }
452 // add save/restore with needed type
453 SaveRestoreHelper(drawableVec, RSDrawableSlot::SAVE_ALL, RSDrawableSlot::RESTORE_ALL,
454 static_cast<RSPaintFilterCanvas::SaveType>(saveType));
455 }
456
457 constexpr std::array boundsDirtyTypes = {
458 RSDrawableSlot::MASK,
459 RSDrawableSlot::SHADOW,
460 RSDrawableSlot::OUTLINE,
461 RSDrawableSlot::FOREGROUND_FILTER,
462 RSDrawableSlot::CLIP_TO_BOUNDS,
463 RSDrawableSlot::BACKGROUND_COLOR,
464 RSDrawableSlot::BACKGROUND_SHADER,
465 RSDrawableSlot::BACKGROUND_IMAGE,
466 RSDrawableSlot::ENV_FOREGROUND_COLOR_STRATEGY,
467 RSDrawableSlot::FRAME_OFFSET,
468 RSDrawableSlot::FG_CLIP_TO_BOUNDS,
469 RSDrawableSlot::FOREGROUND_COLOR,
470 RSDrawableSlot::POINT_LIGHT,
471 RSDrawableSlot::BORDER,
472 RSDrawableSlot::PIXEL_STRETCH,
473 RSDrawableSlot::RESTORE_FOREGROUND_FILTER,
474 };
475 constexpr std::array frameDirtyTypes = {
476 RSDrawableSlot::CLIP_TO_FRAME,
477 RSDrawableSlot::COMPOSITING_FILTER,
478 };
479 constexpr std::array borderDirtyTypes = {
480 RSDrawableSlot::BACKGROUND_COLOR,
481 RSDrawableSlot::BACKGROUND_SHADER,
482 RSDrawableSlot::BACKGROUND_IMAGE,
483 };
484 constexpr std::array bgfilterDirtyTypes = {
485 RSDrawableSlot::PIXEL_STRETCH,
486 };
487 constexpr std::array stretchDirtyTypes = {
488 RSDrawableSlot::BACKGROUND_FILTER,
489 };
490 const std::unordered_set<RSDrawableSlot> fuzeStretchBlurSafeList = {
491 RSDrawableSlot::BG_RESTORE_BOUNDS,
492 RSDrawableSlot::SAVE_FRAME,
493 RSDrawableSlot::RESTORE_FRAME,
494 RSDrawableSlot::FG_SAVE_BOUNDS,
495 RSDrawableSlot::FG_RESTORE_BOUNDS,
496 };
497 template<std::size_t SIZE>
MarkAffectedSlots(const std::array<RSDrawableSlot,SIZE> & affectedSlots,const RSDrawable::Vec & drawableVec,std::unordered_set<RSDrawableSlot> & dirtySlots)498 inline void MarkAffectedSlots(const std::array<RSDrawableSlot, SIZE>& affectedSlots, const RSDrawable::Vec& drawableVec,
499 std::unordered_set<RSDrawableSlot>& dirtySlots)
500 {
501 for (auto slot : affectedSlots) {
502 if (drawableVec[static_cast<size_t>(slot)]) {
503 dirtySlots.emplace(slot);
504 }
505 }
506 }
507 } // namespace
508
CalculateDirtySlots(const ModifierDirtyTypes & dirtyTypes,const Vec & drawableVec)509 std::unordered_set<RSDrawableSlot> RSDrawable::CalculateDirtySlots(
510 const ModifierDirtyTypes& dirtyTypes, const Vec& drawableVec)
511 {
512 // Step 1.1: calculate dirty slots by looking up g_propertyToDrawableLut
513 std::unordered_set<RSDrawableSlot> dirtySlots;
514 for (size_t type = 0; type < static_cast<size_t>(RSModifierType::MAX_RS_MODIFIER_TYPE); type++) {
515 if (!dirtyTypes.test(type)) {
516 continue;
517 }
518 auto dirtySlot = g_propertyToDrawableLut[type];
519 if (dirtySlot != RSDrawableSlot::INVALID) {
520 dirtySlots.emplace(dirtySlot);
521 }
522 }
523
524 // Step 1.2: expand dirty slots by rules
525 // if bounds or cornerRadius changed, mark affected drawables as dirty
526 if (dirtyTypes.test(static_cast<size_t>(RSModifierType::BOUNDS)) ||
527 dirtyTypes.test(static_cast<size_t>(RSModifierType::CORNER_RADIUS)) ||
528 dirtyTypes.test(static_cast<size_t>(RSModifierType::CLIP_BOUNDS))) {
529 MarkAffectedSlots(boundsDirtyTypes, drawableVec, dirtySlots);
530 }
531
532 if (dirtyTypes.test(static_cast<size_t>(RSModifierType::SHADOW_MASK)) || dirtySlots.count(RSDrawableSlot::SHADOW)) {
533 dirtySlots.emplace(RSDrawableSlot::SHADOW);
534 dirtySlots.emplace(RSDrawableSlot::FOREGROUND_FILTER);
535 }
536
537 if (dirtyTypes.test(static_cast<size_t>(RSModifierType::FRAME_GRAVITY))) {
538 dirtySlots.emplace(RSDrawableSlot::CONTENT_STYLE);
539 dirtySlots.emplace(RSDrawableSlot::FOREGROUND_STYLE);
540 }
541
542 // if frame changed, mark affected drawables as dirty
543 if (dirtySlots.count(RSDrawableSlot::FRAME_OFFSET)) {
544 MarkAffectedSlots(frameDirtyTypes, drawableVec, dirtySlots);
545 }
546
547 // if border changed, mark affected drawables as dirty
548 if (dirtySlots.count(RSDrawableSlot::BORDER)) {
549 MarkAffectedSlots(borderDirtyTypes, drawableVec, dirtySlots);
550 }
551
552 // PLANNING: merge these restore operations with RESTORE_ALL drawable
553 if (dirtySlots.count(RSDrawableSlot::FOREGROUND_FILTER)) {
554 dirtySlots.emplace(RSDrawableSlot::RESTORE_FOREGROUND_FILTER);
555 }
556
557 // if pixel stretch changed, mark affected drawables as dirty
558 if (dirtySlots.count(RSDrawableSlot::PIXEL_STRETCH)) {
559 MarkAffectedSlots(stretchDirtyTypes, drawableVec, dirtySlots);
560 }
561 // if background filter changed, mark affected drawables as dirty
562 if (dirtySlots.count(RSDrawableSlot::BACKGROUND_FILTER)) {
563 MarkAffectedSlots(bgfilterDirtyTypes, drawableVec, dirtySlots);
564 }
565
566 return dirtySlots;
567 }
568
UpdateDirtySlots(const RSRenderNode & node,Vec & drawableVec,std::unordered_set<RSDrawableSlot> & dirtySlots)569 bool RSDrawable::UpdateDirtySlots(
570 const RSRenderNode& node, Vec& drawableVec, std::unordered_set<RSDrawableSlot>& dirtySlots)
571 {
572 // Step 2: Update or generate all dirty slots
573 bool drawableAddedOrRemoved = false;
574 for (const auto& slot : dirtySlots) {
575 if (auto& drawable = drawableVec[static_cast<size_t>(slot)]) {
576 // If the slot is already created, call OnUpdate
577 if (!drawable->OnUpdate(node)) {
578 // If the slot is no longer needed, destroy it
579 drawable.reset();
580 drawableAddedOrRemoved = true;
581 }
582 } else if (auto& generator = g_drawableGeneratorLut[static_cast<int>(slot)]) {
583 // If the slot is not created, call OnGenerate
584 if (auto drawable = generator(node)) {
585 drawableVec[static_cast<size_t>(slot)] = std::move(drawable);
586 drawableAddedOrRemoved = true;
587 }
588 }
589 }
590 // If at this point the child node happens to be null, and the scenario involves deleting the child node
591 // when the parent node is not on the tree, it is necessary to manually mark drawableAddedOrRemoved as true.
592 if (!drawableAddedOrRemoved && dirtySlots.count(RSDrawableSlot::CHILDREN) &&
593 drawableVec[static_cast<int8_t>(RSDrawableSlot::CHILDREN)] == nullptr) {
594 drawableAddedOrRemoved = true;
595 }
596
597 return drawableAddedOrRemoved;
598 }
599
FuzeDrawableSlots(const RSRenderNode & node,Vec & drawableVec)600 bool RSDrawable::FuzeDrawableSlots(const RSRenderNode& node, Vec& drawableVec)
601 {
602 // fuze the pixel stretch with MESA blur
603 if (!RSSystemProperties::GetMESABlurFuzedEnabled() ||
604 !drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)] ||
605 !drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)]) {
606 return false;
607 }
608
609 auto &filterDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER)];
610 auto bgFilterDrawable = std::static_pointer_cast<RSBackgroundFilterDrawable>(filterDrawable);
611 bgFilterDrawable->RemovePixelStretch();
612
613 auto &stretchDrawable = drawableVec[static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH)];
614 auto pixelStretchDrawable = std::static_pointer_cast<RSPixelStretchDrawable>(stretchDrawable);
615 pixelStretchDrawable->OnUpdate(node);
616
617 size_t start = static_cast<size_t>(RSDrawableSlot::BACKGROUND_FILTER) + 1;
618 size_t end = static_cast<size_t>(RSDrawableSlot::PIXEL_STRETCH);
619 // We do not fuze if drawableSlots between BACKGROUND_FILTER and PIXEL_STRETCH exist
620 for (size_t ptr = start; ptr < end; ptr++) {
621 if (!fuzeStretchBlurSafeList.count(static_cast<RSDrawableSlot>(ptr)) && drawableVec[ptr]) {
622 return false;
623 }
624 }
625 if (bgFilterDrawable->FuzePixelStretch(node)) {
626 pixelStretchDrawable->SetPixelStretch(std::nullopt);
627 return true;
628 }
629
630 return false;
631 }
632
UpdateSaveRestore(RSRenderNode & node,Vec & drawableVec,uint8_t & drawableVecStatus)633 void RSDrawable::UpdateSaveRestore(RSRenderNode& node, Vec& drawableVec, uint8_t& drawableVecStatus)
634 {
635 // ====================================================================
636 // Step 3: Universal save/clip/restore optimization
637
638 // Step 3.1: calculate new drawable map status
639 auto drawableVecStatusNew = CalculateDrawableVecStatus(node, drawableVec);
640
641 uint8_t changedBits = drawableVecStatus ^ drawableVecStatusNew;
642 if (changedBits == 0) {
643 // nothing to do
644 return;
645 }
646
647 // Step 3.2: update save/clip/restore for changed types
648 if (changedBits & BOUNDS_MASK) {
649 // update bounds save/clip if need
650 OptimizeBoundsSaveRestore(node, drawableVec, drawableVecStatusNew);
651 }
652 if (changedBits & FRAME_MASK) {
653 // update frame save/clip if need
654 OptimizeFrameSaveRestore(node, drawableVec, drawableVecStatusNew);
655 }
656 if (changedBits & OTHER_MASK) {
657 // update global save/clip if need
658 OptimizeGlobalSaveRestore(node, drawableVec, drawableVecStatusNew);
659 }
660
661 drawableVecStatus = drawableVecStatusNew;
662 }
663 } // namespace OHOS::Rosen
664