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 ¶m, 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 ¶m)
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