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 &param, void* data)110 void DrawingEngineSample::OnPrepareCompleted(
111     sptr<Surface> &surface, const struct PrepareCompleteParam &param, 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 &param)399 void DrawingEngineSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam &param)
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 }