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