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     // For skia and DDGR by Nativewindow
220     surfaceFrame = surface_->NativeRequestFrame(drawingWidth, drawingHeight);
221     if (surfaceFrame == nullptr) {
222         std::cout << "Request Frame Failed" << std::endl;
223         return SURFACE_ERROR_ERROR;
224     }
225 #else
226     // For DDGR by flutter vulkan swapchian and skia-gl by swapbuffer
227     surfaceFrame = surface_->RequestFrame(drawingWidth, drawingHeight);
228 #endif
229     Drawing::Canvas* drcanvas = surface_->GetCanvas(surfaceFrame);
230     ExcuteBenchMark(drcanvas);
231 #ifdef RS_ENABLE_VK
232     // For skia and DDGR by Nativewindow
233     surface_->NativeFlushFrame(surfaceFrame);
234 #else
235     // For DDGR by flutter and skia-gl by swapbuffer
236     surface_->FlushFrame(surfaceFrame);
237 #endif
238 
239     std::cout << "DrawingEngineSample::DoDraw-" << std::endl;
240     return SURFACE_ERROR_OK;
241 }
242 
DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> & layer)243 bool DrawingEngineSample::DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> &layer)
244 {
245     int32_t zorder = 1;
246     GraphicIRect dstRect;
247     dstRect.x = 0;  // Absolute coordinates, with offset
248     dstRect.y = 0;
249     dstRect.w = display_w;
250     dstRect.h = display_h;
251 
252     SurfaceError err = DoDraw();
253     if (err != SURFACE_ERROR_OK) {
254         std::cout << "DoDraw failed" << std::endl;
255         return false;
256     }
257 
258     OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
259     int32_t fence = -1;
260     int64_t timestamp;
261     Rect damage;
262     SurfaceError ret = drawingCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
263     sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
264     if (ret != SURFACE_ERROR_OK) {
265         std::cout << "Acquire cBuffer failed: " << ret << std::endl;
266         return false;
267     }
268 
269     GraphicIRect srcRect;
270     srcRect.x = 0;
271     srcRect.y = 0;
272     srcRect.w = drawingWidth;
273     srcRect.h = drawingHeight;
274     GraphicLayerAlpha alpha = { .enPixelAlpha = true };
275     layer->SetSurface(drawingCSurface);
276     layer->SetBuffer(cbuffer, acquireSyncFence);
277     layer->SetZorder(zorder);
278     layer->SetAlpha(alpha);
279     layer->SetTransform(GraphicTransformType::GRAPHIC_ROTATE_NONE);
280     layer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
281     std::vector<GraphicIRect> visibleRegions;
282     visibleRegions.emplace_back(srcRect);
283     layer->SetVisibleRegions(visibleRegions);
284     std::vector<GraphicIRect> dirtyRegions;
285     dirtyRegions.emplace_back(srcRect);
286     layer->SetDirtyRegions(dirtyRegions);
287     layer->SetLayerSize(dstRect);
288     layer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
289     layer->SetCropRect(srcRect);
290     layer->SetPreMulti(false);
291     prevBufferMap_[drawingCSurface->GetUniqueId()] = cbuffer;
292     prevFenceMap_[drawingCSurface->GetUniqueId()] = acquireSyncFence;
293 
294     return true;
295 }
296 
OutPutDisplay()297 void DrawingEngineSample::OutPutDisplay()
298 {
299     static int32_t count = 0;
300     std::shared_ptr<HdiLayerInfo> drawingLayer = HdiLayerInfo::CreateHdiLayerInfo();
301     do {
302         if (!DrawDrawingLayer(drawingLayer)) {
303             std::cout << "DrawDrawingLayer failed!" << std::endl;
304             return;
305         }
306 
307         std::vector<LayerInfoPtr> layers;
308         layers.push_back(drawingLayer);
309         output_->SetLayerInfo(layers);
310 
311         GraphicIRect damageRect;
312         damageRect.x = 0;
313         damageRect.y = 0;
314         damageRect.w = display_w;
315         damageRect.h = display_h;
316         std::vector<GraphicIRect> outputDamages;
317         outputDamages.emplace_back(damageRect);
318         output_->SetOutputDamages(outputDamages);
319 
320         backend_->Repaint(output_);
321         int32_t releaseFence = -1;
322         sptr<SyncFence> tempFence = new SyncFence(releaseFence);
323         drawingCSurface->ReleaseBuffer(prevBufferMap_[drawingCSurface->GetUniqueId()], tempFence);
324         tempFence->Wait(100); // 100 ms
325         std::cout << "draw count " << count << std::endl;
326         std::cout << "display width is " << display_w << ", display height is " << display_h << std::endl;
327 
328         count++;
329     } while (false);
330 }
331 
CreatePhysicalScreen()332 void DrawingEngineSample::CreatePhysicalScreen()
333 {
334     screen_ = HdiScreen::CreateHdiScreen(output_->GetScreenId());
335     screen_->Init();
336     screen_->GetScreenSupportedModes(displayModeInfos_);
337     size_t supportModeNum = displayModeInfos_.size();
338     if (supportModeNum > 0) {
339         screen_->GetScreenMode(currentModeIndex_);
340         for (size_t i = 0; i < supportModeNum; i++) {
341             if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
342                 this->freq_ = displayModeInfos_[i].freshRate;
343                 this->display_w = displayModeInfos_[i].width;
344                 this->display_h = displayModeInfos_[i].height;
345             }
346         }
347         screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
348         screen_->SetScreenMode(currentModeIndex_);
349 
350         GraphicDispPowerStatus powerState;
351         screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
352         screen_->GetScreenPowerStatus(powerState);
353     }
354 
355     GraphicDisplayCapability info;
356     screen_->GetScreenCapability(info);
357 
358     std::cout << "display width is " << this->display_w << " display height is " << this->display_h << std::endl;
359 
360     drawingWidth = this->display_w;
361     drawingHeight = this->display_h;
362 
363     ready_ = true;
364 }
365 
OnHotPlugEvent(const std::shared_ptr<HdiOutput> & output,bool connected)366 void DrawingEngineSample::OnHotPlugEvent(const std::shared_ptr<HdiOutput> &output, bool connected)
367 {
368     /*
369      * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
370      * initiated only after the initialization of the device is complete.
371      */
372     if (output_ != nullptr) {
373         return;
374     }
375     output_ = output;
376     deviceConnected_ = connected;
377 
378     if (!initDeviceFinished_) {
379         std::cout << "Init the device has not finished yet" << std::endl;
380         return;
381     }
382 
383     std::cout << "Callback HotPlugEvent, connected is " << connected << std::endl;
384     if (connected) {
385         CreatePhysicalScreen();
386     }
387 }
388 
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)389 void DrawingEngineSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam &param)
390 {
391     BufferRequestConfig requestConfig = {
392         .width = display_w,  // need display width
393         .height = display_h, // need display height
394         .strideAlignment = 0x8,
395         .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
396         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_FB,
397         .timeout = 0,
398     };
399 
400     int32_t releaseFence = -1;
401     sptr<SurfaceBuffer> fbBuffer = nullptr;
402     SurfaceError err = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
403     if (err != 0) {
404         LOGE("RequestBuffer failed: %{public}s", SurfaceErrorStr(err).c_str());
405         return;
406     }
407 
408     sptr<SyncFence> tempFence = new SyncFence(releaseFence);
409     tempFence->Wait(100); // 100 ms
410 
411     int32_t ret = 0;
412     auto addr = static_cast<uint8_t *>(fbBuffer->GetVirAddr());
413     ret = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
414     if (ret != 0) {
415         std::cout << "memset_s failed" << std::endl;
416     }
417 
418     BufferFlushConfig flushConfig = {
419         .damage = {
420             .w = display_w,
421             .h = display_h,
422         }
423     };
424 
425     /*
426      * if use GPU produce data, flush with gpu fence
427      */
428     ret = surface->FlushBuffer(fbBuffer, -1, flushConfig);
429     if (ret != 0) {
430         std::cout << "DoPrepareCompleted FlushBuffer failed"<< std::endl;
431     }
432 }