1 /*
2  * Copyright (c) 2022 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 "drawing_sample.h"
17 
18 #include <securec.h>
19 #include <sync_fence.h>
20 #include <vsync_controller.h>
21 #include <vsync_distributor.h>
22 #include <vsync_generator.h>
23 #include <vsync_receiver.h>
24 
25 using namespace OHOS;
26 using namespace Rosen;
27 using namespace Drawing;
28 
29 namespace {
30 sptr<VSyncReceiver> g_receiver = nullptr;
31 }
32 
Run()33 void DrawingSample::Run()
34 {
35     auto generator = CreateVSyncGenerator();
36     sptr<VSyncController> vsyncController = new VSyncController(generator, 0);
37     sptr<VSyncDistributor> vsyncDistributor = new VSyncDistributor(vsyncController, "DrawingSample");
38     sptr<VSyncConnection> vsyncConnection = new VSyncConnection(vsyncDistributor, "DrawingSample");
39     vsyncDistributor->AddConnection(vsyncConnection);
40 
41     LOGI("start to run drawing sample");
42     backend_ = OHOS::Rosen::HdiBackend::GetInstance();
43     if (backend_ == nullptr) {
44         LOGE("HdiBackend::GetInstance fail");
45         return;
46     }
47 
48     backend_->RegScreenHotplug(DrawingSample::OnScreenPlug, this);
49     while (1) {
50         if (!outputMap_.empty()) {
51             break;
52         }
53     }
54 
55     if (!initDeviceFinished_) {
56         if (deviceConnected_) {
57             CreateShowLayers();
58         }
59         initDeviceFinished_ = true;
60     }
61     LOGI("Init screen succeed");
62 
63     backend_->RegPrepareComplete(DrawingSample::OnPrepareCompleted, this);
64 
65     sleep(1);
66     std::shared_ptr<OHOS::AppExecFwk::EventRunner> runner = OHOS::AppExecFwk::EventRunner::Create(false);
67     mainThreadHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
68     g_receiver = new VSyncReceiver(vsyncConnection, mainThreadHandler_);
69     g_receiver->Init();
70     mainThreadHandler_->PostTask(std::bind(&DrawingSample::RequestSync, this));
71     runner->Run();
72 }
73 
OnScreenPlug(std::shared_ptr<HdiOutput> & output,bool connected,void * data)74 void DrawingSample::OnScreenPlug(std::shared_ptr<HdiOutput>& output, bool connected, void* data)
75 {
76     LOGI("enter OnScreenPlug, connected is %{public}d", connected);
77     auto* thisPtr = static_cast<DrawingSample*>(data);
78     thisPtr->OnHotPlugEvent(output, connected);
79 }
80 
OnPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param,void * data)81 void DrawingSample::OnPrepareCompleted(
82     sptr<Surface> &surface, const struct PrepareCompleteParam& param, void* data)
83 {
84     if (!param.needFlushFramebuffer) {
85         return;
86     }
87 
88     if (surface == nullptr) {
89         LOGE("surface is null");
90         return;
91     }
92 
93     if (data == nullptr) {
94         LOGE("data ptr is null");
95         return;
96     }
97 
98     auto* thisPtr = static_cast<DrawingSample*>(data);
99     thisPtr->DoPrepareCompleted(surface, param);
100 }
101 
CreateShowLayers()102 void DrawingSample::CreateShowLayers()
103 {
104     uint32_t screenId = CreatePhysicalScreen();
105 
106     LOGI("Create %{public}zu screens", screens_.size());
107 
108     InitLayers(screenId);
109 }
110 
RequestSync()111 void DrawingSample::RequestSync()
112 {
113     Sync(0, nullptr);
114 }
115 
InitLayers(uint32_t screenId)116 void DrawingSample::InitLayers(uint32_t screenId)
117 {
118     LOGI("Init layers, screenId is %{public}d", screenId);
119     uint32_t displayWidth = displayWidthsMap_[screenId];
120     uint32_t displayHeight = displayHeightsMap_[screenId];
121 
122     std::unique_ptr<LayerContext>& drawLayer = drawLayersMap_[screenId];
123     // launcher
124     drawLayer = std::make_unique<LayerContext>(GraphicIRect { 0, 0, displayWidth, displayHeight },
125         GraphicIRect { 0, 0, displayWidth, displayHeight }, 0, LayerType::LAYER_LAUNCHER);
126 }
127 
Sync(int64_t,void * data)128 void DrawingSample::Sync(int64_t, void* data)
129 {
130     VSyncReceiver::FrameCallback fcb = {
131         .userData_ = data,
132         .callback_ = std::bind(&DrawingSample::Sync, this, ::std::placeholders::_1, ::std::placeholders::_2),
133     };
134     if (g_receiver != nullptr) {
135         g_receiver->RequestNextVSync(fcb);
136     }
137     if (!ready_) {
138         return;
139     }
140 
141     Draw();
142 }
143 
Draw()144 void DrawingSample::Draw()
145 {
146     for (auto iter = drawLayersMap_.begin(); iter != drawLayersMap_.end(); ++iter) {
147         uint32_t screenId = iter->first;
148         std::unique_ptr<LayerContext>& drawLayer = drawLayersMap_[screenId];
149 
150         for (auto iter = drawFuncMap_.begin(); iter != drawFuncMap_.end(); iter++) {
151             std::cout << "-------------------------------------------------------\n";
152             std::cout << "Drawing module " << iter->first << " start.\n";
153             for (auto& func : iter->second) {
154                 drawLayer->DrawBuffer(func); // producer
155                 drawLayer->FillHDILayer();   // consumer
156                 std::vector<LayerInfoPtr> layerVec;
157                 layerVec.emplace_back(drawLayer->GetHdiLayer());
158                 curOutput_ = outputMap_[screenId];
159                 curOutput_->SetLayerInfo(layerVec);
160 
161                 GraphicIRect damageRect;
162                 damageRect.x = 0;
163                 damageRect.y = 0;
164                 damageRect.w = static_cast<int32_t>(displayWidthsMap_[screenId]);
165                 damageRect.h = static_cast<int32_t>(displayHeightsMap_[screenId]);
166                 std::vector<GraphicIRect> outputDamages;
167                 outputDamages.emplace_back(damageRect);
168                 curOutput_->SetOutputDamages(outputDamages);
169                 backend_->Repaint(curOutput_);
170                 sleep(2); // wait 2s
171                 auto preBuffer = drawLayer->GetPreBuffer();
172                 int32_t releaseFence = -1;
173                 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
174                 drawLayer->GetHdiLayer()->GetSurface()->ReleaseBuffer(preBuffer, tempFence);
175                 tempFence->Wait(100); // 100 ms
176             }
177             std::cout << "Drawing module " << iter->first << " end.\n";
178         }
179     }
180 }
181 
CreatePhysicalScreen()182 uint32_t DrawingSample::CreatePhysicalScreen()
183 {
184     uint32_t screenId = currScreenId_;
185     std::unique_ptr<HdiScreen> screen = HdiScreen::CreateHdiScreen(screenId);
186     screen->Init();
187     screen->GetScreenSupportedModes(displayModeInfos_);
188     size_t supportModeNum = displayModeInfos_.size();
189     if (supportModeNum > 0) {
190         screen->GetScreenMode(currentModeIndex_);
191         LOGI("currentModeIndex:%{public}d", currentModeIndex_);
192         for (size_t i = 0; i < supportModeNum; i++) {
193             LOGI("modes(%{public}d) %{public}dx%{public}d freq:%{public}d", displayModeInfos_[i].id,
194                 displayModeInfos_[i].width, displayModeInfos_[i].height, displayModeInfos_[i].freshRate);
195             if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
196                 freq_ = displayModeInfos_[i].freshRate; // 30 freq
197                 displayWidthsMap_[screenId] = static_cast<uint32_t>(displayModeInfos_[i].width);
198                 displayHeightsMap_[screenId] = static_cast<uint32_t>(displayModeInfos_[i].height);
199                 break;
200             }
201         }
202         screen->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
203         screen->SetScreenMode(currentModeIndex_);
204         LOGI("SetScreenMode: currentModeIndex(%{public}d)", currentModeIndex_);
205 
206         GraphicDispPowerStatus powerState;
207         screen->GetScreenPowerStatus(powerState);
208         LOGI("get poweState:%{public}d", powerState);
209     }
210 
211     GraphicDisplayCapability info;
212     screen->GetScreenCapability(info);
213     LOGI("ScreenCapability: name(%{public}s), type(%{public}d), phyWidth(%{public}d), "
214          "phyHeight(%{public}d)",
215         info.name.c_str(), info.type, info.phyWidth, info.phyHeight);
216     LOGI("ScreenCapability: supportLayers(%{public}d), virtualDispCount(%{public}d), "
217          "supportWriteBack(%{public}d), propertyCount(%{public}d)",
218         info.supportLayers, info.virtualDispCount, info.supportWriteBack, info.propertyCount);
219 
220     ready_ = true;
221 
222     screens_.emplace_back(std::move(screen));
223 
224     LOGE("CreatePhysicalScreen, screenId is %{public}d", screenId);
225 
226     return screenId;
227 }
228 
OnHotPlugEvent(std::shared_ptr<HdiOutput> & output,bool connected)229 void DrawingSample::OnHotPlugEvent(std::shared_ptr<HdiOutput>& output, bool connected)
230 {
231     if (mainThreadHandler_ == nullptr) {
232         LOGI("In main thread, call OnHotPlug directly");
233         OnHotPlug(output, connected);
234     } else {
235         LOGI("In sub thread, post msg to main thread");
236         mainThreadHandler_->PostTask(std::bind(&DrawingSample::OnHotPlug, this, output, connected));
237     }
238 }
239 
OnHotPlug(std::shared_ptr<HdiOutput> & output,bool connected)240 void DrawingSample::OnHotPlug(std::shared_ptr<HdiOutput>& output, bool connected)
241 {
242     /*
243      * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
244      * initiated only after the initialization of the device is complete.
245      */
246     currScreenId_ = output->GetScreenId();
247     outputMap_[currScreenId_] = output;
248     deviceConnected_ = connected;
249 
250     if (!initDeviceFinished_) {
251         LOGI("Init the device has not finished yet");
252         return;
253     }
254 
255     LOGI("Callback HotPlugEvent, connected is %{public}u", connected);
256 
257     if (connected) {
258         CreateShowLayers();
259     }
260 }
261 
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)262 void DrawingSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam& param)
263 {
264     uint32_t screenId = curOutput_->GetScreenId();
265     uint32_t displayWidth = displayWidthsMap_[screenId];
266     uint32_t displayHeight = displayHeightsMap_[screenId];
267 
268     BufferRequestConfig requestConfig = {
269         .width = displayWidth,   // need display width
270         .height = displayHeight, // need display height
271         .strideAlignment = 0x8,
272         .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
273         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
274         .timeout = 0,
275     };
276 
277     int32_t releaseFence = -1;
278     sptr<SurfaceBuffer> fbBuffer = nullptr;
279     SurfaceError ret1 = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
280     if (ret1 != 0) {
281         LOGE("RequestBuffer failed: %{public}s", SurfaceErrorStr(ret1).c_str());
282         return;
283     }
284 
285     sptr<SyncFence> tempFence = new SyncFence(releaseFence);
286     tempFence->Wait(100); // 100 ms
287 
288     auto addr = static_cast<uint8_t*>(fbBuffer->GetVirAddr());
289     int32_t ret2 = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
290     if (ret2 != 0) {
291         LOGE("memset_s failed");
292     }
293 
294     BufferFlushConfig flushConfig = { .damage = {
295                                           .w = displayWidth,
296                                           .h = displayHeight,
297                                       } };
298 
299     /*
300      * if use GPU produce data, flush with gpu fence
301      */
302     SurfaceError ret3 = surface->FlushBuffer(fbBuffer, -1, flushConfig);
303     if (ret3 != 0) {
304         LOGE("FlushBuffer failed: %{public}s", SurfaceErrorStr(ret3).c_str());
305     }
306 }