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