• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param, 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 &param)
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 }