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 "drawing_engine_sample.h"
17
18 #include "window.h"
19 #include <securec.h>
20 #include <vsync_generator.h>
21 #include <vsync_controller.h>
22 #include <vsync_distributor.h>
23 #include <event_handler.h>
24 #include <vsync_receiver.h>
25 #include <iostream>
26
27 #include "include/core/SkBitmap.h"
28
29 using namespace OHOS;
30 using namespace OHOS::Rosen;
31
32 namespace {
33 sptr<VSyncReceiver> g_receiver = nullptr;
34 }
35
~DrawingEngineSample()36 DrawingEngineSample::~DrawingEngineSample()
37 {
38 if (benchMark_ != nullptr) {
39 delete benchMark_;
40 }
41 if (drawingProxy != nullptr) {
42 delete drawingProxy;
43 }
44 }
45
SetBenchMark(OHOS::Rosen::BenchMark * benchMark)46 void DrawingEngineSample::SetBenchMark(OHOS::Rosen::BenchMark* benchMark)
47 {
48 benchMark_ = benchMark;
49 std::cout << "SetBenchMark is " << benchMark_ << std::endl;
50 }
51
Run()52 void DrawingEngineSample::Run()
53 {
54 auto generator = CreateVSyncGenerator();
55 sptr<VSyncController> vsyncController = new VSyncController(generator, 0);
56 sptr<VSyncDistributor> vsyncDistributor = new VSyncDistributor(vsyncController, "HelloComposer");
57 sptr<VSyncConnection> vsyncConnection = new VSyncConnection(vsyncDistributor, "HelloComposer");
58 vsyncDistributor->AddConnection(vsyncConnection);
59
60 std::cout << "start to HdiBackend::GetInstance" << std::endl;
61 backend_ = OHOS::Rosen::HdiBackend::GetInstance();
62 if (backend_ == nullptr) {
63 std::cout << "HdiBackend::GetInstance fail" << std::endl;
64 return;
65 }
66
67 backend_->RegScreenHotplug(DrawingEngineSample::OnScreenPlug, this);
68 while (1) {
69 if (output_ != nullptr) {
70 break;
71 }
72 }
73
74 if (!initDeviceFinished_) {
75 if (deviceConnected_) {
76 CreatePhysicalScreen();
77 }
78 initDeviceFinished_ = true;
79 }
80 std::cout << "Init screen succeed" << std::endl;
81
82 backend_->RegPrepareComplete(DrawingEngineSample::OnPrepareCompleted, this);
83
84 sleep(1);
85
86 auto runner = OHOS::AppExecFwk::EventRunner::Create(false);
87 auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
88 g_receiver = new VSyncReceiver(vsyncConnection, handler);
89 g_receiver->Init();
90 handler->PostTask(std::bind(&DrawingEngineSample::Init, this));
91 runner->Run();
92 }
93
OnScreenPlug(std::shared_ptr<HdiOutput> & output,bool connected,void * data)94 void DrawingEngineSample::OnScreenPlug(std::shared_ptr<HdiOutput> &output, bool connected, void* data)
95 {
96 std::cout << "enter OnScreenPlug, connected is " << connected << std::endl;
97 auto* thisPtr = static_cast<DrawingEngineSample *>(data);
98 thisPtr->OnHotPlugEvent(output, connected);
99 }
100
OnPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param,void * data)101 void DrawingEngineSample::OnPrepareCompleted(
102 sptr<Surface> &surface, const struct PrepareCompleteParam ¶m, void* data)
103 {
104 if (!param.needFlushFramebuffer) {
105 return;
106 }
107
108 if (surface == nullptr) {
109 LOGE("surface is null");
110 return;
111 }
112
113 if (data == nullptr) {
114 LOGE("data ptr is null");
115 return;
116 }
117
118 auto* thisPtr = static_cast<DrawingEngineSample *>(data);
119 thisPtr->DoPrepareCompleted(surface, param);
120 }
121
InitContext()122 void DrawingEngineSample::InitContext()
123 {
124 std::cout << "DrawingEngineSample::InitContext+" << std::endl;
125 drawingProxy = new DrawingProxy();
126 drawingProxy->InitDrawContext();
127 std::cout << "DrawingEngineSample::InitContext-" << std::endl;
128 }
129
Init()130 void DrawingEngineSample::Init()
131 {
132 std::cout << "DrawingEngineSample::Init+" << std::endl;
133 CreateDrawingSurface();
134 InitContext();
135 Sync(0, nullptr);
136 Initilized = true;
137 std::cout << "DrawingEngineSample::Init-" << std::endl;
138 }
139
Sync(int64_t,void * data)140 void DrawingEngineSample::Sync(int64_t, void *data)
141 {
142 std::cout << "Sync+" << std::endl;
143 VSyncReceiver::FrameCallback fcb = {
144 .userData_ = data,
145 .callback_ = std::bind(&DrawingEngineSample::Sync, this, ::std::placeholders::_1, ::std::placeholders::_2),
146 };
147
148 if (g_receiver != nullptr) {
149 g_receiver->RequestNextVSync(fcb);
150 }
151
152 if (!ready_) {
153 LOGE("hdi screen is not ready");
154 return;
155 }
156
157 if (Initilized == false) {
158 LOGI("call init function");
159 return;
160 }
161
162 OutPutDisplay();
163 std::cout << "Sync-" << std::endl;
164 }
165
CreateDrawingSurface()166 void DrawingEngineSample::CreateDrawingSurface()
167 {
168 drawingCSurface = IConsumerSurface::Create();
169 drawingCSurface->SetDefaultWidthAndHeight(drawingWidth, drawingHeight);
170 drawingCSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA);
171
172 sptr<IBufferProducer> producer = drawingCSurface->GetProducer();
173 drawingPSurface= Surface::CreateSurfaceAsProducer(producer);
174 drawingCSurface->RegisterConsumerListener(this);
175
176 prevBufferMap_[drawingCSurface->GetUniqueId()] = nullptr;
177 prevFenceMap_[drawingCSurface->GetUniqueId()] = SyncFence::INVALID_FENCE;
178 }
179
OnBufferAvailable()180 void DrawingEngineSample::OnBufferAvailable()
181 {
182 }
183
ExcuteBenchMark(SkCanvas * canvas)184 void DrawingEngineSample::ExcuteBenchMark(SkCanvas* canvas)
185 {
186 std::cout << "ExcuteBenchMark benchmark is " << benchMark_ << std::endl;
187 if (benchMark_ == nullptr) {
188 return;
189 }
190 benchMark_->Start();
191 benchMark_->Test(canvas, drawingWidth, drawingHeight);
192 benchMark_->Stop();
193 }
194
DoDraw()195 SurfaceError DrawingEngineSample::DoDraw()
196 {
197 LOGI("DrawingEngineSample::DoDraw+");
198 std::shared_ptr<SurfaceBase> surface = OHOS::Rosen::SurfaceOhos::CreateSurface(drawingPSurface);
199 if (surface == nullptr) {
200 return SURFACE_ERROR_ERROR;
201 }
202 surface->SetDrawingProxy(drawingProxy);
203
204 auto surfaceFrame = surface->RequestFrame(drawingWidth, drawingHeight);
205 if (surfaceFrame == nullptr) {
206 std::cout << "Request Frame Failed" << std::endl;
207 return SURFACE_ERROR_ERROR;
208 }
209
210 SkCanvas* canvas = surface->GetCanvas(surfaceFrame);
211
212 ExcuteBenchMark(canvas);
213
214 surface->FlushFrame(surfaceFrame);
215
216 LOGI("DrawingEngineSample::DoDraw-");
217 return SURFACE_ERROR_OK;
218 }
219
DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> & layer)220 bool DrawingEngineSample::DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> &layer)
221 {
222 int32_t zorder = 1;
223 GraphicIRect dstRect;
224 dstRect.x = 0; // Absolute coordinates, with offset
225 dstRect.y = 0;
226 dstRect.w = display_w;
227 dstRect.h = display_h;
228
229 SurfaceError err = DoDraw();
230 if (err != SURFACE_ERROR_OK) {
231 std::cout << "DoDraw failed" << std::endl;
232 return false;
233 }
234
235 OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
236 int32_t fence = -1;
237 int64_t timestamp;
238 Rect damage;
239 SurfaceError ret = drawingCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
240 sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
241 if (ret != SURFACE_ERROR_OK) {
242 std::cout << "Acquire cBuffer failed: " << ret << std::endl;
243 return false;
244 }
245
246 GraphicIRect srcRect;
247 srcRect.x = 0;
248 srcRect.y = 0;
249 srcRect.w = drawingWidth;
250 srcRect.h = drawingHeight;
251 GraphicLayerAlpha alpha = { .enPixelAlpha = true };
252 layer->SetSurface(drawingCSurface);
253 layer->SetBuffer(cbuffer, acquireSyncFence);
254 layer->SetZorder(zorder);
255 layer->SetAlpha(alpha);
256 layer->SetTransform(GraphicTransformType::GRAPHIC_ROTATE_NONE);
257 layer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
258 std::vector<GraphicIRect> visibleRegions;
259 visibleRegions.emplace_back(srcRect);
260 layer->SetVisibleRegions(visibleRegions);
261 std::vector<GraphicIRect> dirtyRegions;
262 dirtyRegions.emplace_back(srcRect);
263 layer->SetDirtyRegions(dirtyRegions);
264 layer->SetLayerSize(dstRect);
265 layer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
266 layer->SetCropRect(srcRect);
267 layer->SetPreMulti(false);
268 prevBufferMap_[drawingCSurface->GetUniqueId()] = cbuffer;
269 prevFenceMap_[drawingCSurface->GetUniqueId()] = acquireSyncFence;
270
271 return true;
272 }
273
OutPutDisplay()274 void DrawingEngineSample::OutPutDisplay()
275 {
276 static int32_t count = 0;
277 std::shared_ptr<HdiLayerInfo> drawingLayer = HdiLayerInfo::CreateHdiLayerInfo();
278 do {
279 if (!DrawDrawingLayer(drawingLayer)) {
280 std::cout << "DrawDrawingLayer failed!" << std::endl;
281 return;
282 }
283
284 std::vector<LayerInfoPtr> layers;
285 layers.push_back(drawingLayer);
286 output_->SetLayerInfo(layers);
287
288 GraphicIRect damageRect;
289 damageRect.x = 0;
290 damageRect.y = 0;
291 damageRect.w = display_w;
292 damageRect.h = display_h;
293 std::vector<GraphicIRect> outputDamages;
294 outputDamages.emplace_back(damageRect);
295 output_->SetOutputDamages(outputDamages);
296
297 backend_->Repaint(output_);
298 int32_t releaseFence = -1;
299 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
300 drawingCSurface->ReleaseBuffer(prevBufferMap_[drawingCSurface->GetUniqueId()], tempFence);
301 tempFence->Wait(100); // 100 ms
302 std::cout << "draw count " << count << std::endl;
303 std::cout << "display width is " << display_w << ", display height is " << display_h << std::endl;
304
305 count++;
306 } while (false);
307 }
308
CreatePhysicalScreen()309 void DrawingEngineSample::CreatePhysicalScreen()
310 {
311 screen_ = HdiScreen::CreateHdiScreen(output_->GetScreenId());
312 screen_->Init();
313 screen_->GetScreenSupportedModes(displayModeInfos_);
314 size_t supportModeNum = displayModeInfos_.size();
315 if (supportModeNum > 0) {
316 screen_->GetScreenMode(currentModeIndex_);
317 for (size_t i = 0; i < supportModeNum; i++) {
318 if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
319 this->freq_ = displayModeInfos_[i].freshRate;
320 this->display_w = displayModeInfos_[i].width;
321 this->display_h = displayModeInfos_[i].height;
322 }
323 }
324 screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
325 screen_->SetScreenMode(currentModeIndex_);
326
327 GraphicDispPowerStatus powerState;
328 screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
329 screen_->GetScreenPowerStatus(powerState);
330 }
331
332 GraphicDisplayCapability info;
333 screen_->GetScreenCapability(info);
334
335 std::cout << "display width is " << this->display_w << " display height is " << this->display_h << std::endl;
336
337 drawingWidth = this->display_w;
338 drawingHeight = this->display_h;
339
340 ready_ = true;
341 }
342
OnHotPlugEvent(const std::shared_ptr<HdiOutput> & output,bool connected)343 void DrawingEngineSample::OnHotPlugEvent(const std::shared_ptr<HdiOutput> &output, bool connected)
344 {
345 /*
346 * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
347 * initiated only after the initialization of the device is complete.
348 */
349 output_ = output;
350 deviceConnected_ = connected;
351
352 if (!initDeviceFinished_) {
353 std::cout << "Init the device has not finished yet" << std::endl;
354 return;
355 }
356
357 std::cout << "Callback HotPlugEvent, connected is " << connected << std::endl;
358 if (connected) {
359 CreatePhysicalScreen();
360 }
361 }
362
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)363 void DrawingEngineSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam ¶m)
364 {
365 BufferRequestConfig requestConfig = {
366 .width = display_w, // need display width
367 .height = display_h, // need display height
368 .strideAlignment = 0x8,
369 .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
370 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_FB,
371 .timeout = 0,
372 };
373
374 int32_t releaseFence = -1;
375 sptr<SurfaceBuffer> fbBuffer = nullptr;
376 SurfaceError err = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
377 if (err != 0) {
378 LOGE("RequestBuffer failed: %{public}s", SurfaceErrorStr(err).c_str());
379 return;
380 }
381
382 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
383 tempFence->Wait(100); // 100 ms
384
385 int32_t ret = 0;
386 auto addr = static_cast<uint8_t *>(fbBuffer->GetVirAddr());
387 ret = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
388 if (ret != 0) {
389 std::cout << "memset_s failed" << std::endl;
390 }
391
392 BufferFlushConfig flushConfig = {
393 .damage = {
394 .w = display_w,
395 .h = display_h,
396 }
397 };
398
399 /*
400 * if use GPU produce data, flush with gpu fence
401 */
402 ret = surface->FlushBuffer(fbBuffer, -1, flushConfig);
403 if (ret != 0) {
404 std::cout << "DoPrepareCompleted FlushBuffer failed"<< std::endl;
405 }
406 }