• 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 #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 &param, 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 &param)
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 }