1 /*
2  * Copyright (c) 2021 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 "hello_composer.h"
17 
18 #include <vsync_generator.h>
19 #include <vsync_controller.h>
20 #include <vsync_distributor.h>
21 #include <vsync_receiver.h>
22 #include <securec.h>
23 #include <sync_fence.h>
24 
25 using namespace OHOS;
26 using namespace OHOS::Rosen;
27 
28 namespace {
29 #define LOGI(fmt, ...) ::OHOS::HiviewDFX::HiLog::Info(            \
30     ::OHOS::HiviewDFX::HiLogLabel {LOG_CORE, 0, "HelloComposer"}, \
31     "%{public}s: " fmt, __func__, ##__VA_ARGS__)
32 
33 #define LOGE(fmt, ...) ::OHOS::HiviewDFX::HiLog::Error(           \
34     ::OHOS::HiviewDFX::HiLogLabel {LOG_CORE, 0, "HelloComposer"}, \
35     "%{public}s: " fmt, __func__, ##__VA_ARGS__)
36 
37 sptr<VSyncReceiver> g_receiver = nullptr;
38 }
39 
Run(const std::vector<std::string> & runArgs)40 void HelloComposer::Run(const std::vector<std::string> &runArgs)
41 {
42     auto generator = CreateVSyncGenerator();
43     sptr<VSyncController> vsyncController = new VSyncController(generator, 0);
44     sptr<VSyncDistributor> vsyncDistributor = new VSyncDistributor(vsyncController, "HelloComposer");
45     sptr<VSyncConnection> vsyncConnection = new VSyncConnection(vsyncDistributor, "HelloComposer");
46     vsyncDistributor->AddConnection(vsyncConnection);
47 
48     LOGI("start to run hello composer");
49     backend_ = OHOS::Rosen::HdiBackend::GetInstance();
50     if (backend_ == nullptr) {
51         LOGE("HdiBackend::GetInstance fail");
52         return;
53     }
54 
55     backend_->RegScreenHotplug(HelloComposer::OnScreenPlug, this);
56     while (1) {
57         if (!outputMap_.empty()) {
58             break;
59         }
60     }
61 
62     if (!initDeviceFinished_) {
63         if (deviceConnected_) {
64             CreateLayers();
65         }
66         initDeviceFinished_ = true;
67     }
68     LOGI("Init screen succeed");
69 
70     backend_->RegPrepareComplete(HelloComposer::OnPrepareCompleted, this);
71 
72     ParseArgs(runArgs);
73 
74     sleep(1);
75     std::shared_ptr<OHOS::AppExecFwk::EventRunner> runner = OHOS::AppExecFwk::EventRunner::Create(false);
76     mainThreadHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
77     g_receiver = new VSyncReceiver(vsyncConnection, nullptr, mainThreadHandler_);
78     g_receiver->Init();
79     mainThreadHandler_->PostTask([this] { this->RequestSync(); });
80     runner->Run();
81 }
82 
ParseArgs(const std::vector<std::string> & runArgs)83 void HelloComposer::ParseArgs(const std::vector<std::string> &runArgs)
84 {
85     for (const std::string &arg : runArgs) {
86         if (arg == "--dump") {
87             dump_ = true;
88         } else if (arg == "--testClient") {
89             testClient_ = true;
90         } else if (arg == "--testLayerRotate") {
91             testLayerRotate_ = true;
92         } else if (arg == "--YUV") {
93             yuvFormat_ = true;
94         } else if (arg == "--testLayerColor") {
95             testLayerColor_ = true;
96         }
97     }
98 }
99 
OnScreenPlug(std::shared_ptr<HdiOutput> & output,bool connected,void * data)100 void HelloComposer::OnScreenPlug(std::shared_ptr<HdiOutput> &output, bool connected, void* data)
101 {
102     LOGI("enter OnScreenPlug, connected is %{public}d", connected);
103     auto* thisPtr = static_cast<HelloComposer *>(data);
104     thisPtr->OnHotPlugEvent(output, connected);
105 }
106 
OnPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param,void * data)107 void HelloComposer::OnPrepareCompleted(
108     sptr<Surface> &surface, const struct PrepareCompleteParam &param, void* data)
109 {
110     if (!param.needFlushFramebuffer) {
111         return;
112     }
113 
114     if (surface == nullptr) {
115         LOGE("surface is null");
116         return;
117     }
118 
119     if (data == nullptr) {
120         LOGE("data ptr is null");
121         return;
122     }
123 
124     auto* thisPtr = static_cast<HelloComposer *>(data);
125     thisPtr->DoPrepareCompleted(surface, param);
126 }
127 
CreateLayers()128 void HelloComposer::CreateLayers()
129 {
130     for (auto iter = outputMap_.begin(); iter != outputMap_.end(); ++iter) {
131         currScreenId_ = iter->first;
132         CreateShowLayers();
133     }
134 }
135 
CreateShowLayers()136 void HelloComposer::CreateShowLayers()
137 {
138     if (screensMap_.count(currScreenId_) != 0) {
139         LOGI("Screen[%{public}d] has already created", currScreenId_);
140         return;
141     }
142 
143     uint32_t screenId = CreatePhysicalScreen();
144 
145     LOGI("Create screen[%{public}d], and created a total of %{public}zu screens", screenId, screensMap_.size());
146 
147     InitLayers(screenId);
148 }
149 
RequestSync()150 void HelloComposer::RequestSync()
151 {
152     Sync(0, nullptr);
153 }
154 
InitLayers(uint32_t screenId)155 void HelloComposer::InitLayers(uint32_t screenId)
156 {
157     LOGI("Init layers, screenId is %{public}d", screenId);
158     uint32_t displayWidth = displayWidthsMap_[screenId];
159     uint32_t displayHeight = displayHeightsMap_[screenId];
160 
161     std::vector<std::unique_ptr<LayerContext>> &drawLayers = drawLayersMap_[screenId];
162 
163     uint32_t statusHeight = displayHeight / 10; // statusHeight is 1 / 10 displayHeight
164     uint32_t launcherHeight = displayHeight - statusHeight * 2; // index 1, cal launcher height 2
165     uint32_t navigationY = displayHeight - statusHeight;
166     LOGI("displayWidth[%{public}d], displayHeight[%{public}d], statusHeight[%{public}d], "
167          "launcherHeight[%{public}d], navigationY[%{public}d]", displayWidth, displayHeight,
168          statusHeight, launcherHeight, navigationY);
169 
170     // status bar
171     drawLayers.emplace_back(std::make_unique<LayerContext>(
172         GraphicIRect { 0, 0, displayWidth, statusHeight },
173         GraphicIRect { 0, 0, displayWidth, statusHeight },
174         1, LayerType::LAYER_STATUS));
175 
176     // launcher
177     drawLayers.emplace_back(std::make_unique<LayerContext>(
178         GraphicIRect { 0, statusHeight, displayWidth, launcherHeight },
179         GraphicIRect { 0, 0, displayWidth, launcherHeight },
180         0, LayerType::LAYER_LAUNCHER));
181 
182     // navigation bar
183     drawLayers.emplace_back(std::make_unique<LayerContext>(
184         GraphicIRect { 0, navigationY, displayWidth, statusHeight },
185         GraphicIRect { 0, 0, displayWidth, statusHeight },
186         1, LayerType::LAYER_NAVIGATION));
187 
188     uint32_t layerWidth = displayWidth / 4; // layer width is 1/4 displayWidth
189     uint32_t layerHeight = displayHeight / 4; // layer height is 1/4 of displayHeight
190     uint32_t layerPositionX = displayWidth / 2 - layerWidth / 2; // x is (displayWidth - layerWidth) / 2
191     uint32_t layerPositionY = displayHeight / 2 - layerHeight / 2; // y is (displayHeight - layerHeight) / 2
192     LOGI("Layer position is: [x, y, w, h: [%{public}d, %{public}d, %{public}d, %{public}d]]",
193           layerPositionX, layerPositionY, layerWidth, layerHeight);
194 
195     // extra layer 1
196     drawLayers.emplace_back(std::make_unique<LayerContext>(
197         GraphicIRect { layerPositionX, layerPositionY, layerWidth, layerHeight },
198         GraphicIRect { 0, 0, layerWidth, layerHeight },
199         1, LayerType::LAYER_EXTRA)); // 2 is zorder
200 }
201 
Sync(int64_t,void * data)202 void HelloComposer::Sync(int64_t, void *data)
203 {
204     VSyncReceiver::FrameCallback fcb = {
205         .userData_ = data,
206         .callback_ = [this] { this->Sync(::std::placeholders::_1, ::std::placeholders::_2); },
207     };
208 
209     if (g_receiver != nullptr) {
210         g_receiver->RequestNextVSync(fcb);
211     }
212 
213     if (!ready_) {
214         LOGE("hdi screen is not ready");
215         return;
216     }
217 
218     Draw();
219 }
220 
SetRunArgs(const std::unique_ptr<LayerContext> & drawLayer) const221 void HelloComposer::SetRunArgs(const std::unique_ptr<LayerContext> &drawLayer) const
222 {
223     LayerType type = drawLayer->GetLayerType();
224     if (testLayerColor_) {
225         drawLayer->SetTestLayerColor(true);
226     }
227 
228     if (type < LayerType::LAYER_EXTRA) {
229         return;
230     }
231 
232     if (testClient_) {
233         drawLayer->SetTestClientStatus(true);
234     }
235 
236     if (testLayerRotate_) {
237         drawLayer->SetTestRotateStatus(true);
238     }
239 
240     if (yuvFormat_) {
241         drawLayer->SetTestYUVStatus(true);
242     }
243 }
244 
Draw()245 void HelloComposer::Draw()
246 {
247     for (auto iter = drawLayersMap_.begin(); iter != drawLayersMap_.end(); ++iter) {
248         uint32_t screenId = iter->first;
249         std::vector<std::unique_ptr<LayerContext>> &drawLayers = drawLayersMap_[screenId];
250         std::vector<LayerInfoPtr> layerVec;
251         for (auto &drawLayer : drawLayers) { // producer
252             SetRunArgs(drawLayer);
253             drawLayer->DrawBufferColor();
254         }
255 
256         for (auto &drawLayer : drawLayers) { // consumer
257             drawLayer->FillHDIBuffer();
258             drawLayer->FillHDILayer();
259             layerVec.emplace_back(drawLayer->GetHdiLayer());
260         }
261 
262         curOutput_ = outputMap_[screenId];
263         curOutput_->SetLayerInfo(layerVec);
264 
265         GraphicIRect damageRect;
266         damageRect.x = 0;
267         damageRect.y = 0;
268         damageRect.w = static_cast<int32_t>(displayWidthsMap_[screenId]);
269         damageRect.h = static_cast<int32_t>(displayHeightsMap_[screenId]);
270         std::vector<GraphicIRect> outputDamages;
271         outputDamages.emplace_back(damageRect);
272         curOutput_->SetOutputDamages(outputDamages);
273 
274         if (dump_) {
275             std::string result;
276             curOutput_->Dump(result);
277             LOGI("Dump layer result after ReleaseBuffer : %{public}s", result.c_str());
278         }
279 
280         backend_->Repaint(curOutput_);
281         auto layersReleaseFence = curOutput_->GetLayersReleaseFence();
282         for (auto& layerContext : drawLayers) {
283             auto preBuffer = layerContext->GetPreBuffer();
284             int32_t releaseFence = -1;
285             sptr<SyncFence> tempFence = new SyncFence(releaseFence);
286             layerContext->GetHdiLayer()->GetSurface()->ReleaseBuffer(preBuffer, tempFence);
287             tempFence->Wait(100); // 100 ms
288         }
289     }
290 }
291 
CreatePhysicalScreen()292 uint32_t HelloComposer::CreatePhysicalScreen()
293 {
294     std::vector<GraphicDisplayModeInfo> displayModeInfos;
295     uint32_t screenId = currScreenId_;
296     std::unique_ptr<HdiScreen> screen = HdiScreen::CreateHdiScreen(screenId);
297     screen->Init();
298     screen->GetScreenSupportedModes(displayModeInfos);
299     size_t supportModeNum = displayModeInfos.size();
300     if (supportModeNum > 0) {
301         uint32_t currentModeIndex = 0;
302         screen->GetScreenMode(currentModeIndex);
303         LOGI("currentModeIndex:%{public}d", currentModeIndex);
304         for (size_t i = 0; i < supportModeNum; i++) {
305             LOGI("modes(%{public}d) %{public}dx%{public}d freq:%{public}d",
306                 displayModeInfos[i].id, displayModeInfos[i].width,
307                 displayModeInfos[i].height, displayModeInfos[i].freshRate);
308             if (displayModeInfos[i].id == static_cast<int32_t>(currentModeIndex)) {
309                 freq_ = 30; // 30 freq
310                 displayWidthsMap_[screenId] = static_cast<uint32_t>(displayModeInfos[i].width);
311                 displayHeightsMap_[screenId] = static_cast<uint32_t>(displayModeInfos[i].height);
312                 break;
313             }
314         }
315         screen->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
316         screen->SetScreenMode(currentModeIndex);
317         LOGI("SetScreenMode: currentModeIndex(%{public}d)", currentModeIndex);
318 
319         GraphicDispPowerStatus powerState;
320         screen->GetScreenPowerStatus(powerState);
321         LOGI("get poweState:%{public}d", powerState);
322     }
323 
324     GraphicDisplayCapability info;
325     screen->GetScreenCapability(info);
326     LOGI("ScreenCapability: name(%{public}s), type(%{public}d), phyWidth(%{public}d), "
327          "phyHeight(%{public}d)", info.name.c_str(), info.type, info.phyWidth, info.phyHeight);
328     LOGI("ScreenCapability: supportLayers(%{public}d), virtualDispCount(%{public}d), "
329          "supportWriteBack(%{public}d), propertyCount(%{public}d)", info.supportLayers,
330          info.virtualDispCount, info.supportWriteBack, info.propertyCount);
331 
332     ready_ = true;
333 
334     screensMap_[screenId] = std::move(screen);
335 
336     LOGI("CreatePhysicalScreen, screenId is %{public}d", screenId);
337 
338     return screenId;
339 }
340 
OnHotPlugEvent(std::shared_ptr<HdiOutput> & output,bool connected)341 void HelloComposer::OnHotPlugEvent(std::shared_ptr<HdiOutput> &output, bool connected)
342 {
343     if (mainThreadHandler_ == nullptr) {
344         LOGI("In main thread, call OnHotPlug directly");
345         OnHotPlug(output, connected);
346     } else {
347         LOGI("In sub thread, post msg to main thread");
348         mainThreadHandler_->PostTask([this] { this->OnHotPlug(output, connected); });
349     }
350 }
351 
OnHotPlug(std::shared_ptr<HdiOutput> & output,bool connected)352 void HelloComposer::OnHotPlug(std::shared_ptr<HdiOutput> &output, bool connected)
353 {
354     /*
355      * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
356      * initiated only after the initialization of the device is complete.
357      */
358     currScreenId_ = output->GetScreenId();
359     outputMap_[currScreenId_] = output;
360     deviceConnected_ = connected;
361 
362     if (!connected) {
363         RemoveOffScreenData(currScreenId_);
364     }
365 
366     if (!initDeviceFinished_) {
367         LOGI("Init the device has not finished yet");
368         return;
369     }
370 
371     LOGI("Callback HotPlugEvent, screenId is %{public}d, connected is %{public}u", currScreenId_, connected);
372 
373     if (connected) {
374         CreateShowLayers();
375     }
376 }
377 
RemoveOffScreenData(uint32_t offScreenId)378 void HelloComposer::RemoveOffScreenData(uint32_t offScreenId)
379 {
380     LOGI("Screen[%{public}d] is unplugged, and remove data", offScreenId);
381 
382     auto widthIter = displayWidthsMap_.begin();
383     while (widthIter != displayWidthsMap_.end()) {
384         uint32_t screenId = widthIter->first;
385         if (screenId == offScreenId) {
386             displayWidthsMap_.erase(widthIter++);
387         } else {
388             ++widthIter;
389         }
390     }
391 
392     auto heightIter = displayHeightsMap_.begin();
393     while (heightIter != displayHeightsMap_.end()) {
394         uint32_t screenId = heightIter->first;
395         if (screenId == offScreenId) {
396             displayHeightsMap_.erase(heightIter++);
397         } else {
398             ++heightIter;
399         }
400     }
401 
402     auto outputIter = outputMap_.begin();
403     while (outputIter != outputMap_.end()) {
404         uint32_t screenId = outputIter->first;
405         if (screenId == offScreenId) {
406             outputMap_.erase(outputIter++);
407         } else {
408             ++outputIter;
409         }
410     }
411 
412     auto screenIter = screensMap_.begin();
413     while (screenIter != screensMap_.end()) {
414         uint32_t screenId = screenIter->first;
415         if (screenId == offScreenId) {
416             screensMap_.erase(screenIter++);
417         } else {
418             ++screenIter;
419         }
420     }
421 
422     auto layerIter = drawLayersMap_.begin();
423     while (layerIter != drawLayersMap_.end()) {
424         uint32_t screenId = layerIter->first;
425         if (screenId == offScreenId) {
426             drawLayersMap_.erase(layerIter++);
427         } else {
428             ++layerIter;
429         }
430     }
431 }
432 
433 namespace {
DrawFrameBufferData(void * image,uint32_t width,uint32_t height)434 void DrawFrameBufferData(void *image, uint32_t width, uint32_t height)
435 {
436     static uint32_t value = 0x00;
437     value++;
438 
439     uint32_t *pixel = static_cast<uint32_t *>(image);
440     for (uint32_t x = 0; x < width; x++) {
441         for (uint32_t y = 0;  y < height; y++) {
442             *pixel++ = value;
443         }
444     }
445 }
446 }
447 
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)448 void HelloComposer::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam &param)
449 {
450     uint32_t screenId = curOutput_->GetScreenId();
451     uint32_t displayWidth = displayWidthsMap_[screenId];
452     uint32_t displayHeight = displayHeightsMap_[screenId];
453 
454     BufferRequestConfig requestConfig = {
455         .width = displayWidth,  // need display width
456         .height = displayHeight, // need display height
457         .strideAlignment = 0x8,
458         .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
459         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
460         .timeout = 0,
461     };
462 
463     int32_t releaseFence = -1;
464     sptr<SurfaceBuffer> fbBuffer = nullptr;
465     SurfaceError ret = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
466     if (ret != 0) {
467         LOGE("RequestBuffer failed: %{public}s", SurfaceErrorStr(ret).c_str());
468         return;
469     }
470 
471     sptr<SyncFence> tempFence = new SyncFence(releaseFence);
472     tempFence->Wait(100); // 100 ms
473 
474     bool hasClient = false;
475     const std::vector<LayerInfoPtr> &layers = param.layers;
476     for (const LayerInfoPtr &layer : layers) {
477         if (layer->GetCompositionType() == GraphicCompositionType::GRAPHIC_COMPOSITION_CLIENT) {
478             hasClient = true;
479         }
480     }
481 
482     auto addr = static_cast<uint8_t *>(fbBuffer->GetVirAddr());
483     if (hasClient) {
484         DrawFrameBufferData(addr, static_cast<uint32_t>(fbBuffer->GetWidth()),
485             static_cast<uint32_t>(fbBuffer->GetHeight()));
486     } else {
487         int32_t memsetRet = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
488         if (memsetRet != 0) {
489             LOGE("memset_s failed");
490         }
491     }
492 
493     BufferFlushConfig flushConfig = {
494         .damage = {
495             .w = displayWidth,
496             .h = displayHeight,
497         }
498     };
499 
500     /*
501      * if use GPU produce data, flush with gpu fence
502      */
503     ret = surface->FlushBuffer(fbBuffer, -1, flushConfig);
504     if (ret != 0) {
505         LOGE("FlushBuffer failed: %{public}s", SurfaceErrorStr(ret).c_str());
506     }
507 }
508