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