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 }