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