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