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