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_property_drawable_foreground.h"
17
18 #include "common/rs_obj_abs_geometry.h"
19 #include "drawable/rs_property_drawable_utils.h"
20 #include "effect/rs_render_filter_base.h"
21 #include "effect/rs_render_shader_base.h"
22 #include "ge_render.h"
23 #include "ge_visual_effect.h"
24 #include "ge_visual_effect_container.h"
25 #include "memory/rs_tag_tracker.h"
26 #include "pipeline/rs_recording_canvas.h"
27 #include "pipeline/rs_render_node.h"
28 #include "platform/common/rs_log.h"
29 #include "property/rs_point_light_manager.h"
30
31 namespace OHOS::Rosen {
32 namespace DrawableV2 {
33 namespace {
34 constexpr int PARAM_TWO = 2;
35 } // namespace
36
37 const bool FOREGROUND_FILTER_ENABLED = RSSystemProperties::GetForegroundFilterEnabled();
38
39 // ====================================
40 // Binarization
OnGenerate(const RSRenderNode & node)41 RSDrawable::Ptr RSBinarizationDrawable::OnGenerate(const RSRenderNode& node)
42 {
43 if (auto ret = std::make_shared<RSBinarizationDrawable>(); ret->OnUpdate(node)) {
44 return std::move(ret);
45 }
46 return nullptr;
47 }
48
OnUpdate(const RSRenderNode & node)49 bool RSBinarizationDrawable::OnUpdate(const RSRenderNode& node)
50 {
51 auto& aiInvert = node.GetRenderProperties().GetAiInvert();
52 if (!aiInvert.has_value()) {
53 return false;
54 }
55 needSync_ = true;
56 stagingAiInvert_ = aiInvert;
57 return true;
58 }
59
OnSync()60 void RSBinarizationDrawable::OnSync()
61 {
62 if (!needSync_) {
63 return;
64 }
65 aiInvert_ = std::move(stagingAiInvert_);
66 needSync_ = false;
67 }
68
CreateDrawFunc() const69 Drawing::RecordingCanvas::DrawFunc RSBinarizationDrawable::CreateDrawFunc() const
70 {
71 auto ptr = std::static_pointer_cast<const RSBinarizationDrawable>(shared_from_this());
72 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
73 #ifdef RS_ENABLE_GPU
74 RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
75 RSTagTracker::SOURCETYPE::SOURCE_RSBINARIZATIONDRAWABLE);
76 #endif
77 RSPropertyDrawableUtils::DrawBinarization(canvas, ptr->aiInvert_);
78 };
79 }
80
OnGenerate(const RSRenderNode & node)81 RSDrawable::Ptr RSColorFilterDrawable::OnGenerate(const RSRenderNode& node)
82 {
83 if (auto ret = std::make_shared<RSColorFilterDrawable>(); ret->OnUpdate(node)) {
84 return std::move(ret);
85 }
86 return nullptr;
87 }
88
OnUpdate(const RSRenderNode & node)89 bool RSColorFilterDrawable::OnUpdate(const RSRenderNode& node)
90 {
91 auto& colorFilter = node.GetRenderProperties().GetColorFilter();
92 if (colorFilter == nullptr) {
93 return false;
94 }
95 needSync_ = true;
96 stagingFilter_ = colorFilter;
97 return true;
98 }
99
OnSync()100 void RSColorFilterDrawable::OnSync()
101 {
102 if (!needSync_) {
103 return;
104 }
105 filter_ = std::move(stagingFilter_);
106 needSync_ = false;
107 }
108
CreateDrawFunc() const109 Drawing::RecordingCanvas::DrawFunc RSColorFilterDrawable::CreateDrawFunc() const
110 {
111 auto ptr = std::static_pointer_cast<const RSColorFilterDrawable>(shared_from_this());
112 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
113 #ifdef RS_ENABLE_GPU
114 RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
115 RSTagTracker::SOURCETYPE::SOURCE_RSCOLORFILTERDRAWABLE);
116 #endif
117 RSPropertyDrawableUtils::DrawColorFilter(canvas, ptr->filter_);
118 };
119 }
OnGenerate(const RSRenderNode & node)120 RSDrawable::Ptr RSLightUpEffectDrawable::OnGenerate(const RSRenderNode& node)
121 {
122 if (auto ret = std::make_shared<RSLightUpEffectDrawable>(); ret->OnUpdate(node)) {
123 return std::move(ret);
124 }
125 return nullptr;
126 }
127
OnUpdate(const RSRenderNode & node)128 bool RSLightUpEffectDrawable::OnUpdate(const RSRenderNode& node)
129 {
130 if (!node.GetRenderProperties().IsLightUpEffectValid()) {
131 return false;
132 }
133 needSync_ = true;
134 stagingLightUpEffectDegree_ = node.GetRenderProperties().GetLightUpEffect();
135 return true;
136 }
137
OnSync()138 void RSLightUpEffectDrawable::OnSync()
139 {
140 if (!needSync_) {
141 return;
142 }
143 lightUpEffectDegree_ = stagingLightUpEffectDegree_;
144 stagingLightUpEffectDegree_ = 1.0f;
145 needSync_ = false;
146 }
147
CreateDrawFunc() const148 Drawing::RecordingCanvas::DrawFunc RSLightUpEffectDrawable::CreateDrawFunc() const
149 {
150 auto ptr = std::static_pointer_cast<const RSLightUpEffectDrawable>(shared_from_this());
151 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
152 #ifdef RS_ENABLE_GPU
153 RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
154 RSTagTracker::SOURCETYPE::SOURCE_RSLIGHTUPEFFECTDRAWABLE);
155 #endif
156 RSPropertyDrawableUtils::DrawLightUpEffect(canvas, ptr->lightUpEffectDegree_);
157 };
158 }
159
OnGenerate(const RSRenderNode & node)160 RSDrawable::Ptr RSDynamicDimDrawable::OnGenerate(const RSRenderNode& node)
161 {
162 if (auto ret = std::make_shared<RSDynamicDimDrawable>(); ret->OnUpdate(node)) {
163 return std::move(ret);
164 }
165 return nullptr;
166 }
167
OnUpdate(const RSRenderNode & node)168 bool RSDynamicDimDrawable::OnUpdate(const RSRenderNode& node)
169 {
170 if (!node.GetRenderProperties().IsDynamicDimValid()) {
171 return false;
172 }
173 needSync_ = true;
174 stagingDynamicDimDegree_ = node.GetRenderProperties().GetDynamicDimDegree().value();
175 return true;
176 }
177
OnSync()178 void RSDynamicDimDrawable::OnSync()
179 {
180 if (!needSync_) {
181 return;
182 }
183 dynamicDimDegree_ = stagingDynamicDimDegree_;
184 needSync_ = false;
185 }
186
CreateDrawFunc() const187 Drawing::RecordingCanvas::DrawFunc RSDynamicDimDrawable::CreateDrawFunc() const
188 {
189 auto ptr = std::static_pointer_cast<const RSDynamicDimDrawable>(shared_from_this());
190 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
191 #ifdef RS_ENABLE_GPU
192 RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
193 RSTagTracker::SOURCETYPE::SOURCE_RSDYNAMICDIMDRAWABLE);
194 #endif
195 RSPropertyDrawableUtils::DrawDynamicDim(canvas, ptr->dynamicDimDegree_);
196 };
197 }
198
OnGenerate(const RSRenderNode & node)199 RSDrawable::Ptr RSForegroundColorDrawable::OnGenerate(const RSRenderNode& node)
200 {
201 if (auto ret = std::make_shared<RSForegroundColorDrawable>(); ret->OnUpdate(node)) {
202 return std::move(ret);
203 }
204 return nullptr;
205 };
206
OnUpdate(const RSRenderNode & node)207 bool RSForegroundColorDrawable::OnUpdate(const RSRenderNode& node)
208 {
209 const RSProperties& properties = node.GetRenderProperties();
210 auto fgColor = properties.GetForegroundColor();
211 if (fgColor == RgbPalette::Transparent()) {
212 return false;
213 }
214
215 RSPropertyDrawCmdListUpdater updater(0, 0, this);
216 Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
217 Drawing::Brush brush;
218 brush.SetColor(Drawing::Color(fgColor.AsArgbInt()));
219 brush.SetAntiAlias(true);
220 canvas.AttachBrush(brush);
221 canvas.DrawRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetRRect()));
222 canvas.DetachBrush();
223 return true;
224 }
225
OnGenerate(const RSRenderNode & node)226 RSDrawable::Ptr RSForegroundShaderDrawable::OnGenerate(const RSRenderNode& node)
227 {
228 if (auto ret = std::make_shared<RSForegroundShaderDrawable>(); ret->OnUpdate(node)) {
229 return std::move(ret);
230 }
231 return nullptr;
232 };
233
PostUpdate(const RSRenderNode & node)234 void RSForegroundShaderDrawable::PostUpdate(const RSRenderNode& node)
235 {
236 enableEDREffect_ = RSNGRenderShaderHelper::CheckEnableEDR(stagingShader_);
237 if (enableEDREffect_) {
238 screenNodeId_ = node.GetScreenNodeId();
239 }
240 }
241
OnUpdate(const RSRenderNode & node)242 bool RSForegroundShaderDrawable::OnUpdate(const RSRenderNode& node)
243 {
244 const RSProperties& properties = node.GetRenderProperties();
245 const auto& shader = properties.GetForegroundShader();
246 if (!shader) {
247 return false;
248 }
249 needSync_ = true;
250 stagingShader_ = shader;
251 PostUpdate(node);
252 return true;
253 }
254
OnSync()255 void RSForegroundShaderDrawable::OnSync()
256 {
257 if (needSync_ && stagingShader_) {
258 auto visualEffectContainer = std::make_shared<Drawing::GEVisualEffectContainer>();
259 stagingShader_->AppendToGEContainer(visualEffectContainer);
260 visualEffectContainer->UpdateCacheDataFrom(visualEffectContainer_);
261 visualEffectContainer_ = visualEffectContainer;
262 needSync_ = false;
263 }
264 }
265
CreateDrawFunc() const266 Drawing::RecordingCanvas::DrawFunc RSForegroundShaderDrawable::CreateDrawFunc() const
267 {
268 auto ptr = std::static_pointer_cast<const RSForegroundShaderDrawable>(shared_from_this());
269 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
270 auto geRender = std::make_shared<GraphicsEffectEngine::GERender>();
271 if (canvas == nullptr || ptr->visualEffectContainer_ == nullptr || rect == nullptr) {
272 return;
273 }
274 geRender->DrawShaderEffect(*canvas, *(ptr->visualEffectContainer_), *rect);
275 };
276 }
277
OnGenerate(const RSRenderNode & node)278 RSDrawable::Ptr RSCompositingFilterDrawable::OnGenerate(const RSRenderNode& node)
279 {
280 if (auto ret = std::make_shared<RSCompositingFilterDrawable>(); ret->OnUpdate(node)) {
281 return std::move(ret);
282 }
283 return nullptr;
284 }
285
OnUpdate(const RSRenderNode & node)286 bool RSCompositingFilterDrawable::OnUpdate(const RSRenderNode& node)
287 {
288 stagingNodeId_ = node.GetId();
289 stagingNodeName_ = node.GetNodeName();
290 auto& rsFilter = node.GetRenderProperties().GetFilter();
291 if (rsFilter == nullptr) {
292 return false;
293 }
294 RecordFilterInfos(rsFilter);
295 needSync_ = true;
296 stagingFilter_ = rsFilter;
297 PostUpdate(node);
298 return true;
299 }
300
301 // foregroundFilter
OnGenerate(const RSRenderNode & node)302 RSDrawable::Ptr RSForegroundFilterDrawable::OnGenerate(const RSRenderNode& node)
303 {
304 if (!FOREGROUND_FILTER_ENABLED) {
305 ROSEN_LOGD("RSForegroundFilterDrawable::OnGenerate close blur.");
306 return nullptr;
307 }
308 auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
309 if (rsFilter == nullptr) {
310 return nullptr;
311 }
312
313 if (auto ret = std::make_shared<RSForegroundFilterDrawable>(); ret->OnUpdate(node)) {
314 return std::move(ret);
315 }
316 return nullptr;
317 }
318
OnUpdate(const RSRenderNode & node)319 bool RSForegroundFilterDrawable::OnUpdate(const RSRenderNode& node)
320 {
321 auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
322 if (rsFilter == nullptr) {
323 return false;
324 }
325 needSync_ = true;
326 stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
327 return true;
328 }
329
CreateDrawFunc() const330 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterDrawable::CreateDrawFunc() const
331 {
332 auto ptr = std::static_pointer_cast<const RSForegroundFilterDrawable>(shared_from_this());
333 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
334 auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
335 #ifdef RS_ENABLE_GPU
336 RSTagTracker tagTracker(paintFilterCanvas ? paintFilterCanvas->GetGPUContext() : nullptr,
337 RSTagTracker::SOURCETYPE::SOURCE_RSFOREGROUNDFILTERDRAWABLE);
338 #endif
339 RSPropertyDrawableUtils::BeginForegroundFilter(*paintFilterCanvas, ptr->boundsRect_);
340 };
341 }
342
OnSync()343 void RSForegroundFilterDrawable::OnSync()
344 {
345 if (needSync_ == false) {
346 return;
347 }
348 boundsRect_ = stagingBoundsRect_;
349 needSync_ = false;
350 }
351
352 // Restore RSForegroundFilter
OnGenerate(const RSRenderNode & node)353 RSDrawable::Ptr RSForegroundFilterRestoreDrawable::OnGenerate(const RSRenderNode& node)
354 {
355 if (!FOREGROUND_FILTER_ENABLED) {
356 ROSEN_LOGD("RSForegroundFilterRestoreDrawable::OnGenerate close blur.");
357 return nullptr;
358 }
359 auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
360 if (rsFilter == nullptr) {
361 return nullptr;
362 }
363
364 if (auto ret = std::make_shared<RSForegroundFilterRestoreDrawable>(); ret->OnUpdate(node)) {
365 return std::move(ret);
366 }
367 return nullptr;
368 }
369
OnUpdate(const RSRenderNode & node)370 bool RSForegroundFilterRestoreDrawable::OnUpdate(const RSRenderNode& node)
371 {
372 auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
373 if (rsFilter == nullptr) {
374 return false;
375 }
376 needSync_ = true;
377 stagingForegroundFilter_ = rsFilter;
378 return true;
379 }
380
CreateDrawFunc() const381 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterRestoreDrawable::CreateDrawFunc() const
382 {
383 auto ptr = std::static_pointer_cast<const RSForegroundFilterRestoreDrawable>(shared_from_this());
384 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
385 auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
386 #ifdef RS_ENABLE_GPU
387 RSTagTracker tagTracker(paintFilterCanvas ? paintFilterCanvas->GetGPUContext() : nullptr,
388 RSTagTracker::SOURCETYPE::SOURCE_RSFOREGROUNDFILTERRESTOREDRAWABLE);
389 #endif
390 RSPropertyDrawableUtils::DrawForegroundFilter(*paintFilterCanvas, ptr->foregroundFilter_);
391 };
392 }
393
OnSync()394 void RSForegroundFilterRestoreDrawable::OnSync()
395 {
396 if (needSync_ == false) {
397 return;
398 }
399 foregroundFilter_ = std::move(stagingForegroundFilter_);
400 if (foregroundFilter_) {
401 foregroundFilter_->OnSync();
402 }
403 needSync_ = false;
404 }
405
OnGenerate(const RSRenderNode & node)406 RSDrawable::Ptr RSPixelStretchDrawable::OnGenerate(const RSRenderNode& node)
407 {
408 if (auto ret = std::make_shared<RSPixelStretchDrawable>(); ret->OnUpdate(node)) {
409 return std::move(ret);
410 }
411 return nullptr;
412 }
413
OnUpdate(const RSRenderNode & node)414 bool RSPixelStretchDrawable::OnUpdate(const RSRenderNode& node)
415 {
416 auto& pixelStretch = node.GetRenderProperties().GetPixelStretch();
417 if (!pixelStretch.has_value()) {
418 return false;
419 }
420 needSync_ = true;
421 stagingNodeId_ = node.GetId();
422 stagingPixelStretch_ = pixelStretch;
423 stagePixelStretchTileMode_ = node.GetRenderProperties().GetPixelStretchTileMode();
424 const auto& boundsGeo = node.GetRenderProperties().GetBoundsGeometry();
425 stagingBoundsGeoValid_ = boundsGeo && !boundsGeo->IsEmpty();
426 stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
427 return true;
428 }
429
SetPixelStretch(const std::optional<Vector4f> & pixelStretch)430 void RSPixelStretchDrawable::SetPixelStretch(const std::optional<Vector4f>& pixelStretch)
431 {
432 stagingPixelStretch_ = pixelStretch;
433 }
434
OnSync()435 void RSPixelStretchDrawable::OnSync()
436 {
437 if (!needSync_) {
438 return;
439 }
440 renderNodeId_ = stagingNodeId_;
441 pixelStretch_ = std::move(stagingPixelStretch_);
442 pixelStretchTileMode_ = stagePixelStretchTileMode_;
443 boundsGeoValid_ = stagingBoundsGeoValid_;
444 stagingBoundsGeoValid_ = false;
445 boundsRect_ = stagingBoundsRect_;
446 stagingBoundsRect_.Clear();
447 needSync_ = false;
448 }
449
CreateDrawFunc() const450 Drawing::RecordingCanvas::DrawFunc RSPixelStretchDrawable::CreateDrawFunc() const
451 {
452 auto ptr = std::static_pointer_cast<const RSPixelStretchDrawable>(shared_from_this());
453 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
454 #ifdef RS_ENABLE_GPU
455 RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
456 RSTagTracker::SOURCETYPE::SOURCE_RSPIXELSTRETCHDRAWABLE);
457 #endif
458 RSPropertyDrawableUtils::DrawPixelStretch(canvas, ptr->pixelStretch_, ptr->boundsRect_, ptr->boundsGeoValid_,
459 static_cast<Drawing::TileMode>(ptr->pixelStretchTileMode_));
460 };
461 }
462
OnGenerate(const RSRenderNode & node)463 RSDrawable::Ptr RSBorderDrawable::OnGenerate(const RSRenderNode& node)
464 {
465 if (auto ret = std::make_shared<RSBorderDrawable>(); ret->OnUpdate(node)) {
466 return std::move(ret);
467 }
468 return nullptr;
469 };
470
OnUpdate(const RSRenderNode & node)471 bool RSBorderDrawable::OnUpdate(const RSRenderNode& node)
472 {
473 const RSProperties& properties = node.GetRenderProperties();
474 auto& border = properties.GetBorder();
475 if (!border || !border->HasBorder()) {
476 return false;
477 }
478 // regenerate stagingDrawCmdList_
479 RSPropertyDrawCmdListUpdater updater(0, 0, this);
480 DrawBorder(properties, *updater.GetRecordingCanvas(), border, false);
481 return true;
482 }
483
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool & isOutline)484 void RSBorderDrawable::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas,
485 const std::shared_ptr<RSBorder>& border, const bool& isOutline)
486 {
487 Drawing::Brush brush;
488 Drawing::Pen pen;
489 brush.SetAntiAlias(true);
490 pen.SetAntiAlias(true);
491 if (border->ApplyFillStyle(brush)) {
492 auto roundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
493 RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
494 auto innerRoundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
495 RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
496 canvas.AttachBrush(brush);
497 canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
498 canvas.DetachBrush();
499 return;
500 }
501 bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
502 if (isZero && border->ApplyFourLine(pen)) {
503 RectF rectf =
504 isOutline ? properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
505 border->PaintFourLine(canvas, pen, rectf);
506 return;
507 }
508 if (border->ApplyPathStyle(pen)) {
509 auto borderWidth = border->GetWidth();
510 RRect rrect = RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline);
511 rrect.rect_.width_ -= borderWidth;
512 rrect.rect_.height_ -= borderWidth;
513 rrect.rect_.Move(borderWidth / PARAM_TWO, borderWidth / PARAM_TWO);
514 Drawing::Path borderPath;
515 borderPath.AddRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(rrect));
516 canvas.AttachPen(pen);
517 canvas.DrawPath(borderPath);
518 canvas.DetachPen();
519 return;
520 }
521
522 RSBorderGeo borderGeo;
523 borderGeo.rrect = RSPropertyDrawableUtils::RRect2DrawingRRect(
524 RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
525 borderGeo.innerRRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
526 RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
527 auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
528 auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
529 borderGeo.center = { centerX, centerY };
530 auto rect = borderGeo.rrect.GetRect();
531 Drawing::AutoCanvasRestore acr(canvas, false);
532 Drawing::SaveLayerOps slr(&rect, nullptr);
533 canvas.SaveLayer(slr);
534 border->DrawBorders(canvas, pen, borderGeo);
535 }
536
OnGenerate(const RSRenderNode & node)537 RSDrawable::Ptr RSOutlineDrawable::OnGenerate(const RSRenderNode& node)
538 {
539 if (auto ret = std::make_shared<RSOutlineDrawable>(); ret->OnUpdate(node)) {
540 return std::move(ret);
541 }
542 return nullptr;
543 };
544
OnUpdate(const RSRenderNode & node)545 bool RSOutlineDrawable::OnUpdate(const RSRenderNode& node)
546 {
547 const RSProperties& properties = node.GetRenderProperties();
548 auto& outline = properties.GetOutline();
549 if (!outline || !outline->HasBorder()) {
550 return false;
551 }
552 // regenerate stagingDrawCmdList_
553 RSPropertyDrawCmdListUpdater updater(0, 0, this);
554 RSBorderDrawable::DrawBorder(properties, *updater.GetRecordingCanvas(), outline, true);
555 return true;
556 }
557
OnGenerate(const RSRenderNode & node)558 RSDrawable::Ptr RSPointLightDrawable::OnGenerate(const RSRenderNode& node)
559 {
560 if (auto ret = std::make_shared<RSPointLightDrawable>(node.GetRenderProperties()); ret->OnUpdate(node)) {
561 return std::move(ret);
562 }
563 return nullptr;
564 };
565
CreateDrawFunc() const566 Drawing::RecordingCanvas::DrawFunc RSPointLightDrawable::CreateDrawFunc() const
567 {
568 auto ptr = std::static_pointer_cast<const RSPointLightDrawable>(shared_from_this());
569 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
570 #ifdef RS_ENABLE_GPU
571 RSTagTracker tagTracker(canvas ? canvas->GetGPUContext() : nullptr,
572 RSTagTracker::SOURCETYPE::SOURCE_RSPOINTLIGHTDRAWABLE);
573 #endif
574 ptr->DrawLight(canvas);
575 };
576 }
577
OnUpdate(const RSRenderNode & node)578 bool RSPointLightDrawable::OnUpdate(const RSRenderNode& node)
579 {
580 const auto& illuminatedPtr = properties_.GetIlluminated();
581 if (!illuminatedPtr || !illuminatedPtr->IsIlluminatedValid()) {
582 return false;
583 }
584 return true;
585 }
586
OnSync()587 void RSPointLightDrawable::OnSync()
588 {
589 lightSourcesAndPosVec_.clear();
590 const auto& lightSourcesAndPosMap = properties_.GetIlluminated()->GetLightSourcesAndPosMap();
591 for (auto &pair : lightSourcesAndPosMap) {
592 lightSourcesAndPosVec_.push_back(pair);
593 }
594 properties_.GetIlluminated()->ClearLightSourcesAndPosMap();
595 if (lightSourcesAndPosVec_.empty()) {
596 return;
597 }
598 if (lightSourcesAndPosVec_.size() > MAX_LIGHT_SOURCES) {
599 std::sort(lightSourcesAndPosVec_.begin(), lightSourcesAndPosVec_.end(), [](const auto& x, const auto& y) {
600 return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
601 y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
602 });
603 }
604 illuminatedType_ = properties_.GetIlluminated()->GetIlluminatedType();
605 borderWidth_ = std::ceil(properties_.GetIlluminatedBorderWidth());
606 auto& rrect = properties_.GetRRect();
607 if (illuminatedType_ == IlluminatedType::BORDER_CONTENT ||
608 illuminatedType_ == IlluminatedType::BORDER ||
609 illuminatedType_ == IlluminatedType::BLEND_BORDER ||
610 illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT ||
611 illuminatedType_ == IlluminatedType::FEATHERING_BORDER) {
612 // half width and half height requires divide by 2.0f
613 Vector4f width = { borderWidth_ / 2.0f };
614 auto borderRRect = rrect.Inset(width);
615 borderRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(borderRRect);
616 }
617 if (illuminatedType_ == IlluminatedType::BORDER_CONTENT ||
618 illuminatedType_ == IlluminatedType::CONTENT ||
619 illuminatedType_ == IlluminatedType::BLEND_CONTENT ||
620 illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT ||
621 illuminatedType_ == IlluminatedType::FEATHERING_BORDER) {
622 contentRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(rrect);
623 }
624 if (properties_.GetBoundsGeometry()) {
625 rect_ = properties_.GetBoundsGeometry()->GetAbsRect();
626 }
627 }
628
DrawLight(Drawing::Canvas * canvas) const629 void RSPointLightDrawable::DrawLight(Drawing::Canvas* canvas) const
630 {
631 if (lightSourcesAndPosVec_.empty()) {
632 return;
633 }
634 auto phongShaderBuilder = GetPhongShaderBuilder();
635 if (!phongShaderBuilder) {
636 return;
637 }
638 if (illuminatedType_ == IlluminatedType::FEATHERING_BORDER) {
639 phongShaderBuilder = GetFeatheringBoardLightShaderBuilder();
640 float rectWidth = contentRRect_.GetRect().GetWidth();
641 float rectHeight = contentRRect_.GetRect().GetHeight();
642 phongShaderBuilder->SetUniform("iResolution", rectWidth, rectHeight);
643 phongShaderBuilder->SetUniform("contentBorderRadius",
644 contentRRect_.GetCornerRadius(Drawing::RoundRect::CornerPos::TOP_LEFT_POS).GetX());
645 }
646 constexpr int vectorLen = 4;
647 float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
648 float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
649 float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
650 std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
651
652 auto iter = lightSourcesAndPosVec_.begin();
653 auto cnt = 0;
654 while (iter != lightSourcesAndPosVec_.end() && cnt < MAX_LIGHT_SOURCES) {
655 auto lightPos = iter->second;
656 auto lightIntensity = iter->first->GetLightIntensity();
657 auto lightColor = iter->first->GetLightColor();
658 Vector4f lightColorVec =
659 Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
660 for (int i = 0; i < vectorLen; i++) {
661 lightPosArray[cnt * vectorLen + i] = lightPos[i];
662 viewPosArray[cnt * vectorLen + i] = lightPos[i];
663 lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
664 }
665 lightIntensityArray[cnt] = lightIntensity;
666 iter++;
667 cnt++;
668 }
669 phongShaderBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
670 phongShaderBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
671 phongShaderBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
672 Drawing::Pen pen;
673 Drawing::Brush brush;
674 pen.SetAntiAlias(true);
675 brush.SetAntiAlias(true);
676 ROSEN_LOGD("RSPointLightDrawable::DrawLight illuminatedType:%{public}d", illuminatedType_);
677 if ((illuminatedType_ == IlluminatedType::BORDER_CONTENT) ||
678 (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
679 DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
680 DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
681 } else if ((illuminatedType_ == IlluminatedType::CONTENT) ||
682 (illuminatedType_ == IlluminatedType::BLEND_CONTENT)) {
683 DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
684 } else if ((illuminatedType_ == IlluminatedType::BORDER) ||
685 (illuminatedType_ == IlluminatedType::BLEND_BORDER) ||
686 (illuminatedType_ == IlluminatedType::FEATHERING_BORDER)) {
687 DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
688 }
689 }
690
GetPhongShaderBuilder()691 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPointLightDrawable::GetPhongShaderBuilder()
692 {
693 thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder;
694 if (phongShaderBuilder) {
695 return phongShaderBuilder;
696 }
697 std::shared_ptr<Drawing::RuntimeEffect> lightEffect;
698 const static std::string lightString(R"(
699 uniform vec4 lightPos[12];
700 uniform vec4 viewPos[12];
701 uniform vec4 specularLightColor[12];
702 uniform float specularStrength[12];
703
704 mediump vec4 main(vec2 drawing_coord) {
705 vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
706 float ambientStrength = 0.0;
707 vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
708 float diffuseStrength = 0.0;
709 float shininess = 8.0;
710 mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
711 vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
712 // ambient
713 vec4 ambient = lightColor * ambientStrength;
714 vec3 norm = normalize(NormalMap.rgb);
715
716 for (int i = 0; i < 12; i++) {
717 if (abs(specularStrength[i]) > 0.01) {
718 vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
719 float diff = max(dot(norm, lightDir), 0.0);
720 vec4 diffuse = diff * lightColor;
721 vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
722 vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
723 float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
724 vec4 specular = lightColor * spec; // multiply color of incident light
725 vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
726 vec4 specularColor = specularLightColor[i];
727 fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
728 }
729 }
730 return fragColor;
731 }
732 )");
733 std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(lightString);
734 if (!effect) {
735 ROSEN_LOGE("light effect error");
736 return phongShaderBuilder;
737 }
738 lightEffect = std::move(effect);
739 phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect);
740 return phongShaderBuilder;
741 }
742
GetFeatheringBoardLightShaderBuilder()743 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPointLightDrawable::GetFeatheringBoardLightShaderBuilder()
744 {
745 thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> featheringBoardLightShaderBuilder;
746 if (featheringBoardLightShaderBuilder) {
747 return featheringBoardLightShaderBuilder;
748 }
749 std::shared_ptr<Drawing::RuntimeEffect> lightEffect;
750 const static std::string lightString(R"(
751 uniform vec2 iResolution;
752 uniform float contentBorderRadius;
753 uniform vec4 lightPos[12];
754 uniform vec4 viewPos[12];
755 uniform vec4 specularLightColor[12];
756 uniform float specularStrength[12];
757 uniform float borderWidth;
758
759 float sdRoundedBox(vec2 p, vec2 b, float r)
760 {
761 vec2 q = abs(p) - b + r;
762 return (min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r);
763 }
764
765 vec2 sdRoundedBoxGradient(vec2 p, vec2 b, float r)
766 {
767 vec2 signs = vec2(p.x >= 0.0 ? 1.0 : -1.0, p.y >= 0.0 ? 1.0 : -1.0);
768 vec2 q = abs(p) - b + r;
769 vec2 nor = (q.y > q.x) ? vec2(0.0, 1.0) : vec2(1.0, 0.0);
770 nor = (q.x > 0.0 && q.y > 0.0) ? normalize(q) : nor;
771 return signs * nor;
772 }
773
774 mediump vec4 main(vec2 drawing_coord)
775 {
776 float shininess = 8.0;
777 mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
778 vec2 halfResolution = iResolution.xy * 0.5;
779
780 float gradRadius = min(max(contentBorderRadius, abs(borderWidth) * 3.0), iResolution.y * 0.5);
781 float drawRadius = min(max(contentBorderRadius, abs(borderWidth) * 1.1), iResolution.y * 0.5);
782 float realRoundedBoxSDF =
783 sdRoundedBox(drawing_coord.xy - halfResolution, halfResolution, contentBorderRadius);
784 float virtualRoundedBoxSDF = sdRoundedBox(drawing_coord.xy - halfResolution, halfResolution, drawRadius);
785 vec2 grad = sdRoundedBoxGradient(drawing_coord.xy - halfResolution, halfResolution, gradRadius);
786 for (int i = 0; i < 12; i++) {
787 if (abs(specularStrength[i]) > 0.01) {
788 vec2 lightGrad = sdRoundedBoxGradient(lightPos[i].xy - halfResolution,
789 halfResolution,
790 contentBorderRadius); // lightGrad could be pre-computed
791 float angleEfficient = dot(grad, lightGrad);
792 if (angleEfficient > 0.0) {
793 vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
794 vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
795 vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
796 // exponential relationship of angle
797 float spec = pow(max(halfwayDir.z, 0.0), shininess); // norm is (0.0, 0.0, 1.0)
798 spec *= specularStrength[i];
799 spec *= smoothstep(-borderWidth, 0.0, virtualRoundedBoxSDF);
800 spec *= (smoothstep(1.0, 0.0, spec) * 0.2 + 0.8);
801 vec4 specularColor = specularLightColor[i];
802 fragColor += specularColor * (spec * angleEfficient);
803 }
804 }
805 }
806 return vec4(fragColor.rgb, clamp(fragColor.a, 0.0, 1.0));
807 }
808 )");
809 std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(lightString);
810 if (!effect) {
811 ROSEN_LOGE("light effect error");
812 return featheringBoardLightShaderBuilder;
813 }
814 featheringBoardLightShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(effect);
815 return featheringBoardLightShaderBuilder;
816 }
817
DrawContentLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const818 void RSPointLightDrawable::DrawContentLight(Drawing::Canvas& canvas,
819 std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
820 const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
821 {
822 constexpr float contentIntensityCoefficient = 0.3f;
823 float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
824 for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
825 specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
826 }
827 lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
828 std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
829 brush.SetShaderEffect(shader);
830 if ((illuminatedType_ == IlluminatedType::BLEND_CONTENT) ||
831 (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
832 brush.SetAntiAlias(true);
833 brush.SetBlendMode(Drawing::BlendMode::OVERLAY);
834 Drawing::SaveLayerOps slo(&contentRRect_.GetRect(), &brush);
835 canvas.SaveLayer(slo);
836 canvas.AttachBrush(brush);
837 canvas.DrawRoundRect(contentRRect_);
838 canvas.DetachBrush();
839 canvas.Restore();
840 } else {
841 canvas.AttachBrush(brush);
842 canvas.DrawRoundRect(contentRRect_);
843 canvas.DetachBrush();
844 }
845 }
846
DrawBorderLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const847 void RSPointLightDrawable::DrawBorderLight(Drawing::Canvas& canvas,
848 std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
849 const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
850 {
851 float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
852 for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
853 specularStrengthArr[i] = lightIntensityArray[i];
854 }
855 lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
856 std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
857 pen.SetShaderEffect(shader);
858 float borderWidth = std::ceil(borderWidth_);
859 pen.SetWidth(borderWidth);
860 if ((illuminatedType_ == IlluminatedType::BLEND_BORDER) ||
861 (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
862 Drawing::Brush maskPaint;
863 pen.SetBlendMode(Drawing::BlendMode::OVERLAY);
864 Drawing::SaveLayerOps slo(&borderRRect_.GetRect(), &maskPaint);
865 canvas.SaveLayer(slo);
866 canvas.AttachPen(pen);
867 canvas.DrawRoundRect(borderRRect_);
868 canvas.DetachPen();
869 canvas.Restore();
870 } else {
871 canvas.AttachPen(pen);
872 canvas.DrawRoundRect(borderRRect_);
873 canvas.DetachPen();
874 }
875 }
876
OnGenerate(const RSRenderNode & node)877 RSDrawable::Ptr RSParticleDrawable::OnGenerate(const RSRenderNode& node)
878 {
879 if (auto ret = std::make_shared<RSParticleDrawable>(); ret->OnUpdate(node)) {
880 return std::move(ret);
881 }
882 return nullptr;
883 };
884
OnUpdate(const RSRenderNode & node)885 bool RSParticleDrawable::OnUpdate(const RSRenderNode& node)
886 {
887 const RSProperties& properties = node.GetRenderProperties();
888 const auto& particleVector = properties.GetParticles();
889 if (particleVector.GetParticleSize() == 0) {
890 return false;
891 }
892
893 RSPropertyDrawCmdListUpdater updater(0, 0, this);
894 Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
895 const auto& particles = particleVector.GetParticleVector();
896 auto bounds = properties.GetDrawRegion();
897 auto imageCount = particleVector.GetParticleImageCount();
898 auto imageVector = particleVector.GetParticleImageVector();
899 auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
900 if (particleDrawable != nullptr) {
901 particleDrawable->Draw(canvas, bounds);
902 }
903 return true;
904 }
905 } // namespace DrawableV2
906 } // namespace OHOS::Rosen
907