1 /*
2 * Copyright (c) 2023 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 "rs_round_corner_display.h"
17
18 #include "common/rs_optional_trace.h"
19 #include "common/rs_singleton.h"
20 #include "platform/common/rs_system_properties.h"
21 #include "pipeline/round_corner_display/rs_message_bus.h"
22 #include "rs_trace.h"
23
24 namespace OHOS {
25 namespace Rosen {
RoundCornerDisplay(NodeId id)26 RoundCornerDisplay::RoundCornerDisplay(NodeId id) : renderTargetId_{id}
27 {
28 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Created with render target %{public}" PRIu64 " \n", __func__,
29 renderTargetId_);
30 }
31
~RoundCornerDisplay()32 RoundCornerDisplay::~RoundCornerDisplay()
33 {
34 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Destroy for render target %{public}" PRIu64 " \n", __func__,
35 renderTargetId_);
36 }
37
Init()38 bool RoundCornerDisplay::Init()
39 {
40 std::unique_lock<std::shared_mutex> lock(resourceMut_);
41 LoadConfigFile();
42 SeletedLcdModel(rs_rcd::ATTR_DEFAULT);
43 LoadImgsbyResolution(displayWidth_, displayHeight_);
44 RS_LOGI("[%{public}s] RoundCornerDisplay init \n", __func__);
45 return true;
46 }
47
InitOnce()48 void RoundCornerDisplay::InitOnce()
49 {
50 if (!isInit) {
51 Init();
52 isInit = true;
53 }
54 }
55
SeletedLcdModel(const char * lcdModelName)56 bool RoundCornerDisplay::SeletedLcdModel(const char* lcdModelName)
57 {
58 auto& rcdCfg = RSSingleton<rs_rcd::RCDConfig>::GetInstance();
59 lcdModel_ = rcdCfg.GetLcdModel(std::string(lcdModelName));
60 if (lcdModel_ == nullptr) {
61 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] No lcdModel found in config file with name %{public}s \n", __func__,
62 lcdModelName);
63 return false;
64 }
65 supportTopSurface_ = lcdModel_->surfaceConfig.topSurface.support;
66 supportBottomSurface_ = lcdModel_->surfaceConfig.bottomSurface.support;
67 supportHardware_ = lcdModel_->hardwareConfig.hardwareComposer.support;
68 RS_LOGI("[%{public}s] Selected model: %{public}s, supported: top->%{public}d, bottom->%{public}d,"
69 "hardware->%{public}d \n", __func__, lcdModelName, static_cast<int>(supportTopSurface_),
70 static_cast<int>(supportBottomSurface_), static_cast<int>(supportHardware_));
71 return true;
72 }
73
LoadConfigFile()74 bool RoundCornerDisplay::LoadConfigFile()
75 {
76 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] LoadConfigFile \n", __func__);
77 auto& rcdCfg = RSSingleton<rs_rcd::RCDConfig>::GetInstance();
78 return rcdCfg.Load(std::string(rs_rcd::PATH_CONFIG_FILE));
79 }
80
LoadImg(const char * path,std::shared_ptr<Drawing::Image> & img)81 bool RoundCornerDisplay::LoadImg(const char* path, std::shared_ptr<Drawing::Image>& img)
82 {
83 std::string filePath = std::string(rs_rcd::PATH_CONFIG_DIR) + "/" + path;
84 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Read Img(%{public}s) \n", __func__, filePath.c_str());
85 std::shared_ptr<Drawing::Data> drData = Drawing::Data::MakeFromFileName(filePath.c_str());
86 if (drData == nullptr) {
87 RS_LOGE("[%{public}s] Open picture file failed! \n", __func__);
88 return false;
89 }
90 img = std::make_shared<Drawing::Image>();
91 if (!img->MakeFromEncoded(drData)) {
92 img = nullptr;
93 RS_LOGE("[%{public}s] Decode picture file failed! \n", __func__);
94 return false;
95 }
96 return true;
97 }
98
DecodeBitmap(std::shared_ptr<Drawing::Image> image,Drawing::Bitmap & bitmap)99 bool RoundCornerDisplay::DecodeBitmap(std::shared_ptr<Drawing::Image> image, Drawing::Bitmap &bitmap)
100 {
101 if (image == nullptr) {
102 RS_LOGE("[%{public}s] No image found \n", __func__);
103 return false;
104 }
105 if (!image->AsLegacyBitmap(bitmap)) {
106 RS_LOGE("[%{public}s] Create bitmap from drImage failed \n", __func__);
107 return false;
108 }
109 return true;
110 }
111
SetHardwareLayerSize()112 bool RoundCornerDisplay::SetHardwareLayerSize()
113 {
114 if (hardInfo_.topLayer == nullptr) {
115 RS_LOGE("[%{public}s] No topLayer found in hardInfo \n", __func__);
116 return false;
117 }
118 if (hardInfo_.bottomLayer == nullptr) {
119 RS_LOGE("[%{public}s] No bottomLayer found in hardInfo \n", __func__);
120 return false;
121 }
122 hardInfo_.topLayer->layerWidth = displayWidth_;
123 hardInfo_.topLayer->layerHeight = displayHeight_;
124 hardInfo_.bottomLayer->layerWidth = displayWidth_;
125 hardInfo_.bottomLayer->layerHeight = displayHeight_;
126 return true;
127 }
128
GetTopSurfaceSource()129 bool RoundCornerDisplay::GetTopSurfaceSource()
130 {
131 RS_TRACE_NAME("RoundCornerDisplay::GetTopSurfaceSource");
132 if (rog_ == nullptr) {
133 RS_LOGE("[%{public}s] No rog found in config file \n", __func__);
134 return false;
135 }
136 rs_rcd::RCDConfig::PrintParseRog(rog_);
137
138 auto portrait = rog_->GetPortrait(std::string(rs_rcd::NODE_PORTRAIT));
139 if (portrait == std::nullopt) {
140 RS_LOGE("[%{public}s] PORTRAIT layerUp do not configured \n", __func__);
141 return false;
142 }
143 LoadImg(portrait->layerUp.fileName.c_str(), imgTopPortrait_);
144 LoadImg(portrait->layerHide.fileName.c_str(), imgTopHidden_);
145
146 auto landscape = rog_->GetLandscape(std::string(rs_rcd::NODE_LANDSCAPE));
147 if (landscape == std::nullopt) {
148 RS_LOGE("[%{public}s] LANDSACPE layerUp do not configured \n", __func__);
149 return false;
150 }
151 LoadImg(landscape->layerUp.fileName.c_str(), imgTopLadsOrit_);
152
153 if (supportHardware_) {
154 DecodeBitmap(imgTopPortrait_, bitmapTopPortrait_);
155 DecodeBitmap(imgTopLadsOrit_, bitmapTopLadsOrit_);
156 DecodeBitmap(imgTopHidden_, bitmapTopHidden_);
157 }
158 return true;
159 }
160
GetBottomSurfaceSource()161 bool RoundCornerDisplay::GetBottomSurfaceSource()
162 {
163 RS_TRACE_NAME("RoundCornerDisplay::GetBottomSurfaceSource");
164 if (rog_ == nullptr) {
165 RS_LOGE("[%{public}s] No rog found in config file \n", __func__);
166 return false;
167 }
168 auto portrait = rog_->GetPortrait(std::string(rs_rcd::NODE_PORTRAIT));
169 if (portrait == std::nullopt) {
170 RS_LOGE("[%{public}s] PORTRAIT layerDown do not configured \n", __func__);
171 return false;
172 }
173 LoadImg(portrait->layerDown.fileName.c_str(), imgBottomPortrait_);
174 if (supportHardware_) {
175 DecodeBitmap(imgBottomPortrait_, bitmapBottomPortrait_);
176 }
177 return true;
178 }
179
LoadImgsbyResolution(uint32_t width,uint32_t height)180 bool RoundCornerDisplay::LoadImgsbyResolution(uint32_t width, uint32_t height)
181 {
182 RS_TRACE_NAME("RoundCornerDisplay::LoadImgsbyResolution");
183
184 if (lcdModel_ == nullptr) {
185 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] No lcdModel selected in config file \n", __func__);
186 return false;
187 }
188 auto rog = lcdModel_->GetRog(width, height);
189 if (rog == nullptr) {
190 RS_LOGI("[%{public}s] Can't find resolution (%{public}u x %{public}u) in config file \n",
191 __func__, width, height);
192 return false;
193 }
194 rog_ = rog;
195 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Get rog resolution (%{public}u x %{public}u) in config file \n", __func__,
196 width, height);
197 if (supportTopSurface_ && supportHardware_) {
198 if (!GetTopSurfaceSource()) {
199 RS_LOGE("[%{public}s] Top surface support configured, but resources is missing! \n", __func__);
200 return false;
201 }
202 }
203 if (supportBottomSurface_ && supportHardware_) {
204 if (!GetBottomSurfaceSource()) {
205 RS_LOGE("[%{public}s] Bottom surface support configured, but resources is missing! \n", __func__);
206 return false;
207 }
208 }
209 return true;
210 }
211
UpdateDisplayParameter(uint32_t width,uint32_t height)212 void RoundCornerDisplay::UpdateDisplayParameter(uint32_t width, uint32_t height)
213 {
214 std::unique_lock<std::shared_mutex> lock(resourceMut_);
215 if (width == displayWidth_ && height == displayHeight_) {
216 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] DisplayParameter do not change \n", __func__);
217 return;
218 }
219 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] displayWidth_ updated from %{public}u -> %{public}u,"
220 "displayHeight_ updated from %{public}u -> %{public}u \n", __func__,
221 displayWidth_, width, displayHeight_, height);
222 if (LoadImgsbyResolution(width, height)) {
223 updateFlag_["display"] = true;
224 displayWidth_ = width;
225 displayHeight_ = height;
226 }
227 }
228
UpdateNotchStatus(int status)229 void RoundCornerDisplay::UpdateNotchStatus(int status)
230 {
231 std::unique_lock<std::shared_mutex> lock(resourceMut_);
232 // Update surface when surface status changed
233 if (status < 0 || status > 1) {
234 RS_LOGE("[%{public}s] notchStatus won't be over 1 or below 0 \n", __func__);
235 return;
236 }
237 if (notchStatus_ == status) {
238 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] NotchStatus do not change \n", __func__);
239 return;
240 }
241 RS_LOGI("[%{public}s] notchStatus change from %{public}d to %{public}d \n", __func__,
242 notchStatus_, status);
243 notchStatus_ = status;
244 updateFlag_["notch"] = true;
245 }
246
UpdateOrientationStatus(ScreenRotation orientation)247 void RoundCornerDisplay::UpdateOrientationStatus(ScreenRotation orientation)
248 {
249 std::unique_lock<std::shared_mutex> lock(resourceMut_);
250 if (orientation == curOrientation_) {
251 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] OrientationStatus do not change \n", __func__);
252 return;
253 }
254 lastOrientation_ = curOrientation_;
255 curOrientation_ = orientation;
256 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] curOrientation_ = %{public}d, lastOrientation_ = %{public}d \n",
257 __func__, curOrientation_, lastOrientation_);
258 updateFlag_["orientation"] = true;
259 }
260
UpdateHardwareResourcePrepared(bool prepared)261 void RoundCornerDisplay::UpdateHardwareResourcePrepared(bool prepared)
262 {
263 std::unique_lock<std::shared_mutex> lock(resourceMut_);
264 if (hardInfo_.resourcePreparing) {
265 hardInfo_.resourcePreparing = false;
266 hardInfo_.resourceChanged = !prepared;
267 }
268 }
269
UpdateParameter(std::map<std::string,bool> & updateFlag)270 void RoundCornerDisplay::UpdateParameter(std::map<std::string, bool>& updateFlag)
271 {
272 std::unique_lock<std::shared_mutex> lock(resourceMut_);
273 for (auto item = updateFlag.begin(); item != updateFlag.end(); item++) {
274 if (item->second == true) {
275 resourceChanged = true;
276 item->second = false; // reset
277 }
278 }
279 if (resourceChanged) {
280 RcdChooseTopResourceType();
281 RcdChooseRSResource();
282 if (supportHardware_) {
283 RcdChooseHardwareResource();
284 SetHardwareLayerSize();
285 }
286 hardInfo_.resourceChanged = resourceChanged; // output
287 hardInfo_.resourcePreparing = false; // output
288 resourceChanged = false; // reset
289 } else {
290 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Status is not changed \n", __func__);
291 }
292 }
293
294 // Choose the approriate resource type according to orientation and notch status
RcdChooseTopResourceType()295 void RoundCornerDisplay::RcdChooseTopResourceType()
296 {
297 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Choose surface \n", __func__);
298 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] curOrientation is %{public}d \n", __func__, curOrientation_);
299 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] notchStatus is %{public}d \n", __func__, notchStatus_);
300 switch (curOrientation_) {
301 case ScreenRotation::ROTATION_0:
302 case ScreenRotation::ROTATION_180:
303 if (notchStatus_ == WINDOW_NOTCH_HIDDEN) {
304 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] prepare TOP_HIDDEN show resource \n", __func__);
305 showResourceType_ = TOP_HIDDEN;
306 } else {
307 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] prepare TOP_PORTRAIT show resource \n", __func__);
308 showResourceType_ = TOP_PORTRAIT;
309 }
310 break;
311 case ScreenRotation::ROTATION_90:
312 case ScreenRotation::ROTATION_270:
313 if (notchStatus_ == WINDOW_NOTCH_HIDDEN) {
314 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] prepare TOP_LADS_ORIT show resource \n", __func__);
315 showResourceType_ = TOP_LADS_ORIT;
316 } else {
317 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] prepare TOP_PORTRAIT show resource \n", __func__);
318 showResourceType_ = TOP_PORTRAIT;
319 }
320 break;
321 default:
322 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Unknow orientation, use default type \n", __func__);
323 showResourceType_ = TOP_PORTRAIT;
324 break;
325 }
326 }
327
RcdChooseRSResource()328 void RoundCornerDisplay::RcdChooseRSResource()
329 {
330 switch (showResourceType_) {
331 case TOP_PORTRAIT:
332 curTop_ = imgTopPortrait_;
333 RS_LOGD_IF(DEBUG_PIPELINE, "prepare imgTopPortrait_ resource \n");
334 break;
335 case TOP_HIDDEN:
336 curTop_ = imgTopHidden_;
337 RS_LOGD_IF(DEBUG_PIPELINE, "prepare imgTopHidden_ resource \n");
338 break;
339 case TOP_LADS_ORIT:
340 curTop_ = imgTopLadsOrit_;
341 RS_LOGD_IF(DEBUG_PIPELINE, "prepare imgTopLadsOrit_ resource \n");
342 break;
343 default:
344 RS_LOGE("[%{public}s] No showResourceType found with type %{public}d \n", __func__, showResourceType_);
345 break;
346 }
347 curBottom_ = imgBottomPortrait_;
348 }
349
RcdChooseHardwareResource()350 void RoundCornerDisplay::RcdChooseHardwareResource()
351 {
352 if (rog_ == nullptr) {
353 RS_LOGE("[%{public}s] No rog info \n", __func__);
354 return;
355 }
356 auto portrait = rog_->GetPortrait(std::string(rs_rcd::NODE_PORTRAIT));
357 auto landscape = rog_->GetLandscape(std::string(rs_rcd::NODE_LANDSCAPE));
358 switch (showResourceType_) {
359 case TOP_PORTRAIT:
360 if (portrait == std::nullopt) {
361 break;
362 }
363 hardInfo_.topLayer = std::make_shared<rs_rcd::RoundCornerLayer>(portrait->layerUp);
364 hardInfo_.topLayer->curBitmap = &bitmapTopPortrait_;
365 break;
366 case TOP_HIDDEN:
367 if (portrait == std::nullopt) {
368 break;
369 }
370 hardInfo_.topLayer = std::make_shared<rs_rcd::RoundCornerLayer>(portrait->layerHide);
371 hardInfo_.topLayer->curBitmap = &bitmapTopHidden_;
372 break;
373 case TOP_LADS_ORIT:
374 if (landscape == std::nullopt) {
375 break;
376 }
377 hardInfo_.topLayer = std::make_shared<rs_rcd::RoundCornerLayer>(landscape->layerUp);
378 hardInfo_.topLayer->curBitmap = &bitmapTopLadsOrit_;
379 break;
380 default:
381 RS_LOGE("[%{public}s] No showResourceType found with type %{public}d \n", __func__, showResourceType_);
382 break;
383 }
384 if (portrait == std::nullopt) {
385 return;
386 }
387 hardInfo_.bottomLayer = std::make_shared<rs_rcd::RoundCornerLayer>(portrait->layerDown);
388 hardInfo_.bottomLayer->curBitmap = &bitmapBottomPortrait_;
389 }
390
DrawOneRoundCorner(RSPaintFilterCanvas * canvas,int surfaceType)391 void RoundCornerDisplay::DrawOneRoundCorner(RSPaintFilterCanvas* canvas, int surfaceType)
392 {
393 RS_TRACE_BEGIN("RCD::DrawOneRoundCorner : surfaceType" + std::to_string(surfaceType));
394 if (canvas == nullptr) {
395 RS_LOGE("[%{public}s] Canvas is null \n", __func__);
396 RS_TRACE_END();
397 return;
398 }
399 UpdateParameter(updateFlag_);
400 if (surfaceType == TOP_SURFACE) {
401 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] draw TopSurface start \n", __func__);
402 if (curTop_ != nullptr) {
403 Drawing::Brush brush;
404 canvas->AttachBrush(brush);
405 canvas->DrawImage(*curTop_, 0, 0, Drawing::SamplingOptions());
406 canvas->DetachBrush();
407 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Draw top \n", __func__);
408 }
409 } else if (surfaceType == BOTTOM_SURFACE) {
410 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] BottomSurface supported \n", __func__);
411 if (curBottom_ != nullptr) {
412 Drawing::Brush brush;
413 canvas->AttachBrush(brush);
414 canvas->DrawImage(*curBottom_, 0, displayHeight_ - curBottom_->GetHeight(), Drawing::SamplingOptions());
415 canvas->DetachBrush();
416 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Draw Bottom \n", __func__);
417 }
418 } else {
419 RS_LOGD_IF(DEBUG_PIPELINE, "[%{public}s] Surface Type is not valid \n", __func__);
420 }
421 RS_TRACE_END();
422 }
423
DrawTopRoundCorner(RSPaintFilterCanvas * canvas)424 void RoundCornerDisplay::DrawTopRoundCorner(RSPaintFilterCanvas* canvas)
425 {
426 DrawOneRoundCorner(canvas, TOP_SURFACE);
427 }
428
DrawBottomRoundCorner(RSPaintFilterCanvas * canvas)429 void RoundCornerDisplay::DrawBottomRoundCorner(RSPaintFilterCanvas* canvas)
430 {
431 DrawOneRoundCorner(canvas, BOTTOM_SURFACE);
432 }
433 } // namespace Rosen
434 } // namespace OHOS
435