diff --git a/adapter/ohos/osal/system_properties.cpp b/adapter/ohos/osal/system_properties.cpp index 5d3599d61be34115ec542b2566f4e5a881a3df54..76d7ad14e88614710290e7906fa4b3cc5e6f5b22 100644 --- a/adapter/ohos/osal/system_properties.cpp +++ b/adapter/ohos/osal/system_properties.cpp @@ -1441,6 +1441,11 @@ int32_t SystemProperties::getFormSharedImageCacheThreshold() return formSharedImageCacheThreshold_; } +bool SystemProperties::IsReleaseRenderNodeEnabled() +{ + return system::GetBoolParameter("persist.ace.release_render_node.enable", false); +} + bool SystemProperties::IsWhiteBlockEnabled() { return whiteBlockEnabled_; diff --git a/adapter/preview/osal/system_properties.cpp b/adapter/preview/osal/system_properties.cpp index 3795e89e7359f00260a5be20885a69e19dd18201..5ed683534e89d0cf5c03b31d173b0da1b08d94b9 100644 --- a/adapter/preview/osal/system_properties.cpp +++ b/adapter/preview/osal/system_properties.cpp @@ -492,6 +492,11 @@ void SystemProperties::SetMultiInstanceEnabled(bool enabled) { } +bool SystemProperties::IsReleaseRenderNodeEnabled() +{ + return false; +} + bool SystemProperties::IsWhiteBlockEnabled() { return false; diff --git a/frameworks/base/utils/system_properties.h b/frameworks/base/utils/system_properties.h index 50b65264eab3dd0cfaf2a740d97d14c469e2f253..74ce364acd6b0a740343e2d50659abf47afca95f 100644 --- a/frameworks/base/utils/system_properties.h +++ b/frameworks/base/utils/system_properties.h @@ -802,6 +802,7 @@ public: static int32_t getFormSharedImageCacheThreshold(); + static bool IsReleaseRenderNodeEnabled(); static bool IsWhiteBlockEnabled(); static bool IsWhiteBlockIdleChange(); static int32_t GetWhiteBlockIndexValue(); diff --git a/frameworks/core/components_ng/manager/memory/memory_manager.cpp b/frameworks/core/components_ng/manager/memory/memory_manager.cpp index 82c6053aa780aa1f0eb244aa19c62df2ef34ddb8..f26dd0a286f7f5f0b2c7679ef44fc70967f4e8fe 100644 --- a/frameworks/core/components_ng/manager/memory/memory_manager.cpp +++ b/frameworks/core/components_ng/manager/memory/memory_manager.cpp @@ -21,6 +21,61 @@ namespace { constexpr int32_t BACKGROUND_RECYCLE_WAIT_TIME_MS = 500; constexpr int32_t RECYCLE_PAGE_IMAGE_NUM = 20; + +using namespace OHOS::Ace; + +void ReleaseRenderNodes(const RefPtr& element) +{ + auto frameNode = AceType::DynamicCast(element); + if (!frameNode) { + return; + } + auto pipeline = NG::PipelineContext::GetCurrentContext(); + if (frameNode->GetContextRefPtr() && frameNode->GetContextRefPtr() != pipeline) { + return; + } + auto renderContent = frameNode->GetRenderContext(); + if (!renderContent) { + return; + } + renderContent->ReleaseRenderNode(); +} + +void ReleaseRenderNodesTask() +{ + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto window = pipeline->GetWindow(); + CHECK_NULL_VOID(window); + if (pipeline->GetOnShow()) { + return; + } + ElementRegister::GetInstance()->IterateElements([](ElementIdType t, const RefPtr& e) { + ReleaseRenderNodes(e); + return false; + }); + window->SetForceVsyncRequests(true); + window->RequestFrame(); +} + +void PostReleaseRenderNodesTask() +{ + if (!SystemProperties::IsReleaseRenderNodeEnabled()) { + return; + } + auto container = Container::Current(); + if (container && container->IsSceneBoardWindow()) { + return; + } + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto taskExecutor = pipeline->GetTaskExecutor(); + CHECK_NULL_VOID(taskExecutor); + taskExecutor->PostDelayedTask(ReleaseRenderNodesTask, + TaskExecutor::TaskType::UI, + BACKGROUND_RECYCLE_WAIT_TIME_MS, + "ReleaseRenderNodesTask"); +} } namespace OHOS::Ace::NG { MemoryManager::MemoryManager() @@ -118,6 +173,7 @@ void MemoryManager::RebuildImage(const RefPtr& node) void MemoryManager::PostMemRecycleTask() { + PostReleaseRenderNodesTask(); auto container = Container::Current(); if (!isTrimMemWork_ || (container && container->IsSceneBoardWindow())) { return; diff --git a/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp b/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp index b6354470ec88eba23cf035d683384ae0e5d189d2..63c88e5b6a13cf1193408fcf5b0a3279a3cf13f3 100755 --- a/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp +++ b/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp @@ -5308,6 +5308,14 @@ void RosenRenderContext::SetClipBoundsWithCommands(const std::string& commands) rsNode_->SetClipBounds(Rosen::RSPath::CreateRSPath(rsPath)); } +void RosenRenderContext::ReleaseRenderNode() +{ + if (!rsNode_ || rsNode_->GetIsOnTheTree()) { + return; + } + rsNode_->ReleaseRenderNode(); +} + void RosenRenderContext::ClipWithRect(const RectF& rectF) { CHECK_NULL_VOID(rsNode_); diff --git a/frameworks/core/components_ng/render/adapter/rosen_render_context.h b/frameworks/core/components_ng/render/adapter/rosen_render_context.h index 12560952d99bf914a0c18e5563e9f4a6ab9e0ef8..5148a267432191dcae2d866d5a2f7522518eb78f 100755 --- a/frameworks/core/components_ng/render/adapter/rosen_render_context.h +++ b/frameworks/core/components_ng/render/adapter/rosen_render_context.h @@ -380,6 +380,7 @@ public: void BuildPositionInfo(std::unique_ptr& json); void BuildShadowInfo(std::unique_ptr& json); void SetClipBoundsWithCommands(const std::string& commands) override; + void ReleaseRenderNode() override; void SetNeedDebugBoundary(bool flag) override { needDebugBoundary_ = flag; diff --git a/frameworks/core/components_ng/render/render_context.h b/frameworks/core/components_ng/render/render_context.h index a42986e5c949fdbb4ab438f4e1d8596ab28affb5..b5c6c684a71073ecafd53347f98949c669c158bb 100644 --- a/frameworks/core/components_ng/render/render_context.h +++ b/frameworks/core/components_ng/render/render_context.h @@ -109,6 +109,7 @@ public: virtual void SetHostNode(const WeakPtr& host); RefPtr GetHost() const; + virtual void ReleaseRenderNode() {} virtual void SetNeedDebugBoundary(bool flag) {} virtual bool NeedDebugBoundary() const { diff --git a/frameworks/core/pipeline/base/element_register.cpp b/frameworks/core/pipeline/base/element_register.cpp index 0f8a5dfcdc2c188836a8f8086166cf6f976caa47..8c8fadd0d35fbc4c2b815defd631d56566903b00 100644 --- a/frameworks/core/pipeline/base/element_register.cpp +++ b/frameworks/core/pipeline/base/element_register.cpp @@ -35,6 +35,15 @@ ElementRegister* ElementRegister::GetInstance() return (ElementRegister::instance_); } +void ElementRegister::IterateElements(const std::function&)>& visitor) const +{ + for (auto& [k, v] : itemMap_) { + if (visitor(k, v.Upgrade())) { + break; + } + } +} + ElementIdType ElementRegister::MakeUniqueId() { return ElementRegister::nextUniqueElementId_++; diff --git a/frameworks/core/pipeline/base/element_register.h b/frameworks/core/pipeline/base/element_register.h index 165a5f7419870f47e9d7b2bb9c986b906926b504..ea6c907805e51e02c9d56ef21af069b90e3f73a8 100644 --- a/frameworks/core/pipeline/base/element_register.h +++ b/frameworks/core/pipeline/base/element_register.h @@ -47,6 +47,7 @@ public: static constexpr ElementIdType UndefinedElementId = static_cast(-1); ACE_FORCE_EXPORT static ElementRegister* GetInstance(); + void IterateElements(const std::function&)>& visitor) const; RefPtr GetElementById(ElementIdType elementId); RefPtr GetElementProxyById(ElementIdType elementId); diff --git a/test/mock/base/mock_system_properties.cpp b/test/mock/base/mock_system_properties.cpp index c5ee61f1299e6e3e465ab8533a27bd0b6c74df45..5428f6b8b9fe08153ac674c5a8a9aadb176858a7 100644 --- a/test/mock/base/mock_system_properties.cpp +++ b/test/mock/base/mock_system_properties.cpp @@ -379,6 +379,11 @@ int32_t SystemProperties::getFormSharedImageCacheThreshold() return formSharedImageCacheThreshold_; } +bool SystemProperties::IsReleaseRenderNodeEnabled() +{ + return false; +} + bool SystemProperties::IsWhiteBlockEnabled() { return false; diff --git a/test/mock/core/common/mock_window.cpp b/test/mock/core/common/mock_window.cpp index 4552f9037d90e1c0ae1ad40b3d0e08add46d57f5..ef13f6e937db0a2e81eac2d17ba251d9175b4cb4 100644 --- a/test/mock/core/common/mock_window.cpp +++ b/test/mock/core/common/mock_window.cpp @@ -22,6 +22,8 @@ void Window::OnVsync(uint64_t nanoTimestamp, uint64_t frameCount) {} void Window::RequestFrame() {} +void Window::SetForceVsyncRequests(bool forceVsyncRequests) {} + void Window::SetRootRenderNode(const RefPtr& root) {} void Window::SetVsyncCallback(AceVsyncCallback&& callback) {} diff --git a/test/mock/core/pipeline/mock_element_register.cpp b/test/mock/core/pipeline/mock_element_register.cpp index 9cc020ae344a84ac162ec2dfa25be7b417ea1318..a8f7d07103893ea50263aa324510081f05ed4c96 100644 --- a/test/mock/core/pipeline/mock_element_register.cpp +++ b/test/mock/core/pipeline/mock_element_register.cpp @@ -36,6 +36,15 @@ ElementRegister* ElementRegister::GetInstance() return (ElementRegister::instance_); } +void ElementRegister::IterateElements(const std::function&)>& visitor) const +{ + for (auto& [k, v] : itemMap_) { + if (visitor(k, v.Upgrade())) { + break; + } + } +} + ElementIdType ElementRegister::MakeUniqueId() { return ElementRegister::nextUniqueElementId_++;