• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "modifier_render_thread/rs_modifiers_draw_thread.h"
17 
18 #ifdef ACCESSIBILITY_ENABLE
19 #include "transaction/rs_render_service_client.h"
20 #endif
21 #include "modifier_render_thread/rs_modifiers_draw.h"
22 #include "platform/common/rs_log.h"
23 #include "qos.h"
24 #include "render_context/shader_cache.h"
25 #include "concurrent_task_client.h"
26 
27 namespace OHOS {
28 namespace Rosen {
29 std::atomic<bool> RSModifiersDrawThread::isStarted_ = false;
30 std::recursive_mutex RSModifiersDrawThread::transactionDataMutex_;
31 std::shared_mutex RSModifiersDrawThread::cacheDirMtx_;
32 bool RSModifiersDrawThread::isFirstFrame_ = true;
33 std::string RSModifiersDrawThread::cacheDir_ = "";
34 
RSModifiersDrawThread()35 RSModifiersDrawThread::RSModifiersDrawThread()
36 {
37     ::atexit(&RSModifiersDrawThread::Destroy);
38 }
39 
~RSModifiersDrawThread()40 RSModifiersDrawThread::~RSModifiersDrawThread()
41 {
42     if (!RSModifiersDrawThread::isStarted_) {
43         return;
44     }
45     if (handler_ != nullptr) {
46         handler_->RemoveAllEvents();
47         handler_ = nullptr;
48     }
49     if (runner_ != nullptr) {
50         runner_->Stop();
51         runner_ = nullptr;
52     }
53 #ifdef ACCESSIBILITY_ENABLE
54     UnsubscribeHighContrastChange();
55 #endif
56 }
57 
Destroy()58 void RSModifiersDrawThread::Destroy()
59 {
60     if (!RSModifiersDrawThread::isStarted_) {
61         return;
62     }
63     auto task = []() {
64         RSModifiersDrawThread::Instance().ClearEventResource();
65     };
66     RSModifiersDrawThread::Instance().PostSyncTask(task);
67 }
68 
ClearEventResource()69 void RSModifiersDrawThread::ClearEventResource()
70 {
71     RSModifiersDraw::ClearBackGroundMemory();
72     if (handler_ != nullptr) {
73         handler_->RemoveAllEvents();
74         handler_ = nullptr;
75     }
76     if (runner_ != nullptr) {
77         runner_->Stop();
78         runner_ = nullptr;
79     }
80 }
81 
Instance()82 RSModifiersDrawThread& RSModifiersDrawThread::Instance()
83 {
84     static RSModifiersDrawThread instance;
85     return instance;
86 }
87 
SetCacheDir(const std::string & path)88 void RSModifiersDrawThread::SetCacheDir(const std::string& path)
89 {
90     auto& cache = ShaderCache::Instance();
91     cache.SetFilePath(path);
92 
93     std::unique_lock<std::shared_mutex> lock(cacheDirMtx_);
94     cacheDir_ = path;
95 }
96 
GetCacheDir()97 std::string RSModifiersDrawThread::GetCacheDir()
98 {
99     std::shared_lock<std::shared_mutex> lock(cacheDirMtx_);
100     return cacheDir_;
101 }
102 
103 #ifdef ACCESSIBILITY_ENABLE
SubscribeHighContrastChange()104 void RSModifiersDrawThread::SubscribeHighContrastChange()
105 {
106     if (!RSSystemProperties::GetHybridRenderEnabled() || highContrastObserver_ != nullptr) {
107         return;
108     }
109     auto& config = AccessibilityConfig::AccessibilityConfig::GetInstance();
110     if (!config.InitializeContext()) {
111         RS_LOGE("%{public}s AccessibilityConfig InitializeContext fail", __func__);
112         return;
113     }
114     highContrastObserver_ = std::make_shared<Detail::HighContrastObserver>(highContrast_);
115     // Non-system app, the first highContrast value in highContrastObserver_ is incorrect, so get it from RS.
116     if (!highContrastObserver_->IsSystemApp()) {
117         auto renderServiceClient =
118             std::static_pointer_cast<RSRenderServiceClient>(RSIRenderClient::CreateRenderServiceClient());
119         if (renderServiceClient != nullptr) {
120             highContrast_ = renderServiceClient->GetHighContrastTextState();
121         } else {
122             RS_LOGE("%{public}s GetHighContrastTextState, renderServiceClient is null", __func__);
123         }
124     }
125     config.SubscribeConfigObserver(AccessibilityConfig::CONFIG_ID::CONFIG_HIGH_CONTRAST_TEXT, highContrastObserver_);
126 }
127 
UnsubscribeHighContrastChange()128 void RSModifiersDrawThread::UnsubscribeHighContrastChange()
129 {
130     if (highContrastObserver_ == nullptr) {
131         return;
132     }
133     auto& config = AccessibilityConfig::AccessibilityConfig::GetInstance();
134     if (!config.InitializeContext()) {
135         RS_LOGE("%{public}s AccessibilityConfig InitializeContext fail", __func__);
136     }
137     config.UnsubscribeConfigObserver(AccessibilityConfig::CONFIG_ID::CONFIG_HIGH_CONTRAST_TEXT, highContrastObserver_);
138     highContrastObserver_ = nullptr;
139 }
140 
GetHighContrast() const141 bool RSModifiersDrawThread::GetHighContrast() const
142 {
143     return highContrast_;
144 }
145 #endif
146 
GetIsStarted() const147 bool RSModifiersDrawThread::GetIsStarted() const
148 {
149     return RSModifiersDrawThread::isStarted_;
150 }
151 
Start()152 void RSModifiersDrawThread::Start()
153 {
154     std::lock_guard<std::mutex> lock(mutex_);
155     if (RSModifiersDrawThread::isStarted_) {
156         return;
157     }
158     runner_ = AppExecFwk::EventRunner::Create("ModifiersDraw");
159     handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
160     runner_->Run();
161 #ifdef ACCESSIBILITY_ENABLE
162     SubscribeHighContrastChange();
163 #endif
164     RSModifiersDrawThread::isStarted_ = true;
165     PostTask([] {
166         OHOS::ConcurrentTask::IntervalReply reply;
167         reply.tid = gettid();
168         OHOS::ConcurrentTask::ConcurrentTaskClient::GetInstance().QueryInterval(
169             OHOS::ConcurrentTask::QUERY_MODIFIER_DRAW, reply);
170         SetThreadQos(QOS::QosLevel::QOS_USER_INTERACTIVE);
171         // Init shader cache, shader save delay time differs between uni-render and hybrid-render.
172         std::string vkVersion = std::to_string(VK_API_VERSION_1_2);
173         auto size = vkVersion.size();
174         auto& cache = ShaderCache::Instance();
175         cache.InitShaderCache(vkVersion.c_str(), size, false);
176     });
177     RS_LOGI("%{public}s RSModifiersDrawThread started", __func__);
178 }
179 
PostTask(const std::function<void ()> && task,const std::string & name,int64_t delayTime)180 void RSModifiersDrawThread::PostTask(const std::function<void()>&& task, const std::string& name, int64_t delayTime)
181 {
182     if (!RSModifiersDrawThread::isStarted_) {
183         Start();
184     }
185     if (handler_ != nullptr) {
186         handler_->PostTask(task, name, delayTime, AppExecFwk::EventQueue::Priority::IMMEDIATE);
187     }
188 }
189 
RemoveTask(const std::string & name)190 void RSModifiersDrawThread::RemoveTask(const std::string& name)
191 {
192     if (handler_) {
193         handler_->RemoveTask(name);
194     }
195 }
196 
PostSyncTask(const std::function<void ()> && task)197 void RSModifiersDrawThread::PostSyncTask(const std::function<void()>&& task)
198 {
199     if (!RSModifiersDrawThread::isStarted_) {
200         Start();
201     }
202     if (handler_ != nullptr) {
203         handler_->PostSyncTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
204     }
205 }
206 
GetIsFirstFrame()207 bool RSModifiersDrawThread::GetIsFirstFrame()
208 {
209     return isFirstFrame_;
210 }
211 
SetIsFirstFrame(bool isFirstFrame)212 void RSModifiersDrawThread::SetIsFirstFrame(bool isFirstFrame)
213 {
214     isFirstFrame_ = isFirstFrame;
215 }
216 
ConvertTransaction(std::unique_ptr<RSTransactionData> & transactionData,std::shared_ptr<RSIRenderClient> renderServiceClient,bool & isNeedCommit)217 std::unique_ptr<RSTransactionData>& RSModifiersDrawThread::ConvertTransaction(
218     std::unique_ptr<RSTransactionData>& transactionData,
219     std::shared_ptr<RSIRenderClient> renderServiceClient,
220     bool& isNeedCommit)
221 {
222     // 1. extract the drawCmdList that enable hybrid render
223     std::vector<DrawOpInfo> targetCmds;
224     uint32_t enableHybridTextOpCnt = 0;
225     bool isEnableHybridByOpCnt =
226         RSModifiersDraw::SeperateHybridRenderCmdList(transactionData, targetCmds, enableHybridTextOpCnt);
227     if (targetCmds.empty()) {
228         return transactionData;
229     }
230 
231     // 2. check if the number of op exceeds the limit
232     bool isFirstFrame = RSModifiersDrawThread::GetIsFirstFrame();
233     if (!isEnableHybridByOpCnt) {
234         if (isFirstFrame) {
235             RS_TRACE_NAME_FMT("the first frame's op exceeds the limit, commit original transactionData");
236             renderServiceClient->CommitTransaction(transactionData);
237             // still need playback when firstFrame is true
238             isNeedCommit = false;
239         } else {
240             return transactionData;
241         }
242     }
243 
244     // 3. convert drawCmdList
245     RS_TRACE_NAME_FMT("%s opCnt=%zu, textOpCnt=%" PRIu32 ", isEnableHybridByOpCnt=%d, isFirstFrame=%d",
246         __func__, targetCmds.size(), enableHybridTextOpCnt, isEnableHybridByOpCnt, isFirstFrame);
247     RSModifiersDraw::MergeOffTreeNodeSet();
248     if (RSSystemProperties::GetHybridRenderParallelConvertEnabled()) {
249         RSModifiersDraw::ConvertTransactionWithFFRT(transactionData, renderServiceClient, isNeedCommit, targetCmds);
250     } else {
251         RSModifiersDraw::ConvertTransactionWithoutFFRT(transactionData, targetCmds);
252     }
253 
254     // 4. get fence from semaphore and add pixelMap to drawOp
255     RSModifiersDraw::GetFenceAndAddDrawOp(targetCmds);
256     return transactionData;
257 }
258 } // namespace Rosen
259 } // namespace OHOS
260