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