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 #include <vsync_generator.h>
18 #include <vsync_controller.h>
19 #include <vsync_distributor.h>
20 #include <vsync_receiver.h>
21 #include <securec.h>
22 #include <sync_fence.h>
23
24 using namespace OHOS;
25 using namespace OHOS::Rosen;
26
27 namespace {
28 #define LOGI(fmt, ...) ::OHOS::HiviewDFX::HiLog::Info( \
29 ::OHOS::HiviewDFX::HiLogLabel {LOG_CORE, 0, "HelloComposer"}, \
30 "%{public}s: " fmt, __func__, ##__VA_ARGS__)
31 #define LOGE(fmt, ...) ::OHOS::HiviewDFX::HiLog::Error( \
32 ::OHOS::HiviewDFX::HiLogLabel {LOG_CORE, 0, "HelloComposer"}, \
33 "%{public}s: " fmt, __func__, ##__VA_ARGS__)
34
35 sptr<VSyncReceiver> g_receiver = nullptr;
36 }
37
Run(std::vector<std::string> & runArgs)38 void HelloComposer::Run(std::vector<std::string> &runArgs)
39 {
40 auto generator = CreateVSyncGenerator();
41 sptr<VSyncController> vsyncController = new VSyncController(generator, 0);
42 sptr<VSyncDistributor> vsyncDistributor = new VSyncDistributor(vsyncController, "HelloComposer");
43 sptr<VSyncConnection> vsyncConnection = new VSyncConnection(vsyncDistributor, "HelloComposer");
44 vsyncDistributor->AddConnection(vsyncConnection);
45
46 LOGI("start to run hello composer");
47 backend_ = OHOS::Rosen::HdiBackend::GetInstance();
48 if (backend_ == nullptr) {
49 LOGE("HdiBackend::GetInstance fail");
50 return;
51 }
52
53 backend_->RegScreenHotplug(HelloComposer::OnScreenPlug, this);
54 while (1) {
55 if (!outputMap_.empty()) {
56 break;
57 }
58 }
59
60 if (!initDeviceFinished_) {
61 if (deviceConnected_) {
62 CreateShowLayers();
63 }
64 initDeviceFinished_ = true;
65 }
66 LOGI("Init screen succeed");
67
68 backend_->RegPrepareComplete(HelloComposer::OnPrepareCompleted, this);
69
70 for (std::string &arg : runArgs) {
71 if (arg == "--dump") {
72 dump_ = true;
73 }
74 }
75
76 sleep(1);
77 std::shared_ptr<OHOS::AppExecFwk::EventRunner> runner = OHOS::AppExecFwk::EventRunner::Create(false);
78 mainThreadHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
79 g_receiver = new VSyncReceiver(vsyncConnection, mainThreadHandler_);
80 g_receiver->Init();
81 mainThreadHandler_->PostTask(std::bind(&HelloComposer::RequestSync, this));
82 runner->Run();
83 }
84
OnScreenPlug(std::shared_ptr<HdiOutput> & output,bool connected,void * data)85 void HelloComposer::OnScreenPlug(std::shared_ptr<HdiOutput> &output, bool connected, void* data)
86 {
87 LOGI("enter OnScreenPlug, connected is %{public}d", connected);
88 auto* thisPtr = static_cast<HelloComposer *>(data);
89 thisPtr->OnHotPlugEvent(output, connected);
90 }
91
OnPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param,void * data)92 void HelloComposer::OnPrepareCompleted(sptr<Surface> &surface, const struct PrepareCompleteParam ¶m, void* data)
93 {
94 if (!param.needFlushFramebuffer) {
95 return;
96 }
97
98 if (surface == nullptr) {
99 LOGE("surface is null");
100 return;
101 }
102
103 if (data == nullptr) {
104 LOGE("data ptr is null");
105 return;
106 }
107
108 auto* thisPtr = static_cast<HelloComposer *>(data);
109 thisPtr->DoPrepareCompleted(surface, param);
110 }
111
CreateShowLayers()112 void HelloComposer::CreateShowLayers()
113 {
114 uint32_t screenId = CreatePhysicalScreen();
115
116 LOGI("Create %{public}zu screens", screens_.size());
117
118 InitLayers(screenId);
119 }
120
RequestSync()121 void HelloComposer::RequestSync()
122 {
123 Sync(0, nullptr);
124 }
125
InitLayers(uint32_t screenId)126 void HelloComposer::InitLayers(uint32_t screenId)
127 {
128 LOGI("Init layers, screenId is %{public}d", screenId);
129 uint32_t displayWidth = displayWidthsMap_[screenId];
130 uint32_t displayHeight = displayHeightsMap_[screenId];
131
132 std::vector<std::unique_ptr<LayerContext>> &drawLayers = drawLayersMap_[screenId];
133
134 uint32_t statusHeight = displayHeight / 10; // statusHeight is 1 / 10 displayHeight
135 uint32_t launcherHeight = displayHeight - statusHeight * 2; // index 1, cal launcher height 2
136 uint32_t navigationY = displayHeight - statusHeight;
137 LOGI("displayWidth[%{public}d], displayHeight[%{public}d], statusHeight[%{public}d], "
138 "launcherHeight[%{public}d], navigationY[%{public}d]", displayWidth, displayHeight,
139 statusHeight, launcherHeight, navigationY);
140
141 // status bar
142 drawLayers.emplace_back(std::make_unique<LayerContext>(
143 IRect { 0, 0, displayWidth, statusHeight },
144 IRect { 0, 0, displayWidth, statusHeight },
145 1, LayerType::LAYER_STATUS));
146
147 // launcher
148 drawLayers.emplace_back(std::make_unique<LayerContext>(
149 IRect { 0, statusHeight, displayWidth, launcherHeight },
150 IRect { 0, 0, displayWidth, launcherHeight },
151 0, LayerType::LAYER_LAUNCHER));
152
153 // navigation bar
154 drawLayers.emplace_back(std::make_unique<LayerContext>(
155 IRect { 0, navigationY, displayWidth, statusHeight },
156 IRect { 0, 0, displayWidth, statusHeight },
157 1, LayerType::LAYER_NAVIGATION));
158
159 uint32_t extraLayerWidth = displayWidth / 4; // layer width is 1 / 4 displayWidth
160 uint32_t extraLayerHeight = displayHeight / 4; // layer height is 1 / 4 of displayHeight
161 LOGI("extraLayerWidth[%{public}d], extraLayerHeight[%{public}d]", extraLayerWidth, extraLayerHeight);
162
163 // extra layer 1
164 drawLayers.emplace_back(std::make_unique<LayerContext>(
165 IRect { 300, 300, extraLayerWidth, extraLayerHeight }, // 300 is position
166 IRect { 0, 0, extraLayerWidth, extraLayerHeight },
167 1, LayerType::LAYER_EXTRA)); // 2 is zorder
168 }
169
Sync(int64_t,void * data)170 void HelloComposer::Sync(int64_t, void *data)
171 {
172 VSyncReceiver::FrameCallback fcb = {
173 .userData_ = data,
174 .callback_ = std::bind(&HelloComposer::Sync, this, ::std::placeholders::_1, ::std::placeholders::_2),
175 };
176 if (g_receiver != nullptr) {
177 g_receiver->RequestNextVSync(fcb);
178 }
179 if (!ready_) {
180 return;
181 }
182
183 Draw();
184 }
185
Draw()186 void HelloComposer::Draw()
187 {
188 for (auto iter = drawLayersMap_.begin(); iter != drawLayersMap_.end(); ++iter) {
189 std::vector<std::shared_ptr<HdiOutput>> outputs;
190 uint32_t screenId = iter->first;
191 std::vector<std::unique_ptr<LayerContext>> &drawLayers = drawLayersMap_[screenId];
192 std::vector<LayerInfoPtr> layerVec;
193 for (auto &drawLayer : drawLayers) { // producer
194 drawLayer->DrawBufferColor();
195 }
196
197 for (auto &drawLayer : drawLayers) { // consumer
198 drawLayer->FillHDILayer();
199 layerVec.emplace_back(drawLayer->GetHdiLayer());
200 }
201
202 curOutput_ = outputMap_[screenId];
203 outputs.emplace_back(curOutput_);
204 curOutput_->SetLayerInfo(layerVec);
205
206 IRect damageRect;
207 damageRect.x = 0;
208 damageRect.y = 0;
209 damageRect.w = static_cast<int32_t>(displayWidthsMap_[screenId]);
210 damageRect.h = static_cast<int32_t>(displayHeightsMap_[screenId]);
211 curOutput_->SetOutputDamage(1, damageRect);
212
213 if (dump_) {
214 std::string result;
215 curOutput_->Dump(result);
216 LOGI("Dump layer result after ReleaseBuffer : %{public}s", result.c_str());
217 }
218
219 backend_->Repaint(outputs);
220 }
221 }
222
CreatePhysicalScreen()223 uint32_t HelloComposer::CreatePhysicalScreen()
224 {
225 uint32_t screenId = currScreenId_;
226 std::unique_ptr<HdiScreen> screen = HdiScreen::CreateHdiScreen(screenId);
227 screen->Init();
228 screen->GetScreenSupportedModes(displayModeInfos_);
229 size_t supportModeNum = displayModeInfos_.size();
230 if (supportModeNum > 0) {
231 screen->GetScreenMode(currentModeIndex_);
232 LOGI("currentModeIndex:%{public}d", currentModeIndex_);
233 for (size_t i = 0; i < supportModeNum; i++) {
234 LOGI("modes(%{public}d) %{public}dx%{public}d freq:%{public}d",
235 displayModeInfos_[i].id, displayModeInfos_[i].width,
236 displayModeInfos_[i].height, displayModeInfos_[i].freshRate);
237 if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
238 freq_ = 30; // 30 freq
239 displayWidthsMap_[screenId] = static_cast<uint32_t>(displayModeInfos_[i].width);
240 displayHeightsMap_[screenId] = static_cast<uint32_t>(displayModeInfos_[i].height);
241 break;
242 }
243 }
244 screen->SetScreenPowerStatus(DispPowerStatus::POWER_STATUS_ON);
245 screen->SetScreenMode(currentModeIndex_);
246 LOGI("SetScreenMode: currentModeIndex(%{public}d)", currentModeIndex_);
247
248 DispPowerStatus powerState;
249 screen->GetScreenPowerStatus(powerState);
250 LOGI("get poweState:%{public}d", powerState);
251 }
252
253 DisplayCapability info;
254 screen->GetScreenCapability(info);
255 LOGI("ScreenCapability: name(%{public}s), type(%{public}d), phyWidth(%{public}d), "
256 "phyHeight(%{public}d)", info.name, info.type, info.phyWidth, info.phyHeight);
257 LOGI("ScreenCapability: supportLayers(%{public}d), virtualDispCount(%{public}d), "
258 "supportWriteBack(%{public}d), propertyCount(%{public}d)", info.supportLayers,
259 info.virtualDispCount, info.supportWriteBack, info.propertyCount);
260
261 ready_ = true;
262
263 screens_.emplace_back(std::move(screen));
264
265 LOGE("CreatePhysicalScreen, screenId is %{public}d", screenId);
266
267 return screenId;
268 }
269
OnHotPlugEvent(std::shared_ptr<HdiOutput> & output,bool connected)270 void HelloComposer::OnHotPlugEvent(std::shared_ptr<HdiOutput> &output, bool connected)
271 {
272 if (mainThreadHandler_ == nullptr) {
273 LOGI("In main thread, call OnHotPlug directly");
274 OnHotPlug(output, connected);
275 } else {
276 LOGI("In sub thread, post msg to main thread");
277 mainThreadHandler_->PostTask(std::bind(&HelloComposer::OnHotPlug, this, output, connected));
278 }
279 }
280
OnHotPlug(std::shared_ptr<HdiOutput> & output,bool connected)281 void HelloComposer::OnHotPlug(std::shared_ptr<HdiOutput> &output, bool connected)
282 {
283 /*
284 * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
285 * initiated only after the initialization of the device is complete.
286 */
287 currScreenId_ = output->GetScreenId();
288 outputMap_[currScreenId_] = output;
289 deviceConnected_ = connected;
290
291 if (!initDeviceFinished_) {
292 LOGI("Init the device has not finished yet");
293 return;
294 }
295
296 LOGI("Callback HotPlugEvent, connected is %{public}u", connected);
297
298 if (connected) {
299 CreateShowLayers();
300 }
301 }
302
DoPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param)303 void HelloComposer::DoPrepareCompleted(sptr<Surface> &surface, const struct PrepareCompleteParam ¶m)
304 {
305 uint32_t screenId = curOutput_->GetScreenId();
306 uint32_t displayWidth = displayWidthsMap_[screenId];
307 uint32_t displayHeight = displayHeightsMap_[screenId];
308
309 BufferRequestConfig requestConfig = {
310 .width = displayWidth, // need display width
311 .height = displayHeight, // need display height
312 .strideAlignment = 0x8,
313 .format = PIXEL_FMT_BGRA_8888,
314 .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
315 .timeout = 0,
316 };
317
318 int32_t releaseFence = -1;
319 sptr<SurfaceBuffer> fbBuffer = nullptr;
320 SurfaceError ret = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
321 if (ret != 0) {
322 LOGE("RequestBuffer failed: %{public}s", SurfaceErrorStr(ret).c_str());
323 return;
324 }
325
326 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
327 tempFence->Wait(100); // 100 ms
328
329 uint32_t clientCount = 0;
330 bool hasClient = false;
331 const std::vector<LayerInfoPtr> &layers = param.layers;
332 for (const LayerInfoPtr &layer : layers) {
333 if (layer->GetCompositionType() == CompositionType::COMPOSITION_CLIENT) {
334 hasClient = true;
335 clientCount++;
336 }
337 }
338
339 auto addr = static_cast<uint8_t *>(fbBuffer->GetVirAddr());
340 if (hasClient) {
341 DrawFrameBufferData(addr, static_cast<uint32_t>(fbBuffer->GetWidth()),
342 static_cast<uint32_t>(fbBuffer->GetHeight()));
343 } else {
344 int32_t ret = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
345 if (ret != 0) {
346 LOGE("memset_s failed");
347 }
348 }
349
350 BufferFlushConfig flushConfig = {
351 .damage = {
352 .w = displayWidth,
353 .h = displayHeight,
354 }
355 };
356
357 /*
358 * if use GPU produce data, flush with gpu fence
359 */
360 ret = surface->FlushBuffer(fbBuffer, -1, flushConfig);
361 if (ret != 0) {
362 LOGE("FlushBuffer failed: %{public}s", SurfaceErrorStr(ret).c_str());
363 }
364 }
365
DrawFrameBufferData(void * image,uint32_t width,uint32_t height)366 void HelloComposer::DrawFrameBufferData(void *image, uint32_t width, uint32_t height)
367 {
368 static uint32_t value = 0x00;
369 value++;
370
371 uint32_t *pixel = static_cast<uint32_t *>(image);
372 for (uint32_t x = 0; x < width; x++) {
373 for (uint32_t y = 0; y < height; y++) {
374 *pixel++ = value;
375 }
376 }
377 }