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 "render_context_sample.h"
17 
18 #include "window.h"
19 #include <securec.h>
20 #include <event_handler.h>
21 #include <iostream>
22 
23 using namespace OHOS;
24 using namespace OHOS::Rosen;
25 
26 static const int DRAWING_WIDTH = 1200;
27 static const int DRAWING_HEIGHT = 800;
28 static const int SYNC_WAIT_TIMEOUT = 100;
29 
Run()30 void RenderContextSample::Run()
31 {
32     std::cout << "start to HdiBackend::GetInstance" << std::endl;
33     backend_ = OHOS::Rosen::HdiBackend::GetInstance();
34     if (backend_ == nullptr) {
35         std::cout << "HdiBackend::GetInstance fail" << std::endl;
36         return;
37     }
38 
39     backend_->RegScreenHotplug(RenderContextSample::OnScreenPlug, this);
40     while (1) {
41         if (output_ != nullptr) {
42             break;
43         }
44     }
45 
46     if (!initDeviceFinished_) {
47         if (deviceConnected_) {
48             CreatePhysicalScreen();
49         }
50         initDeviceFinished_ = true;
51     }
52     std::cout << "Init screen succeed" << std::endl;
53 
54     backend_->RegPrepareComplete(RenderContextSample::OnPrepareCompleted, this);
55 
56     sleep(1);
57 
58     auto runner = OHOS::AppExecFwk::EventRunner::Create(false);
59     auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
60     handler->PostTask([this]() { this->Init(); });
61     runner->Run();
62 }
63 
OnScreenPlug(std::shared_ptr<HdiOutput> & output,bool connected,void * data)64 void RenderContextSample::OnScreenPlug(std::shared_ptr<HdiOutput> &output, bool connected, void* data)
65 {
66     std::cout << "enter OnScreenPlug, connected is " << connected << std::endl;
67     auto* thisPtr = static_cast<RenderContextSample *>(data);
68     thisPtr->OnHotPlugEvent(output, connected);
69 }
70 
OnPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param,void * data)71 void RenderContextSample::OnPrepareCompleted(
72     sptr<Surface> &surface, const struct PrepareCompleteParam &param, void* data)
73 {
74     if (!param.needFlushFramebuffer) {
75         return;
76     }
77 
78     if (surface == nullptr) {
79         return;
80     }
81 
82     if (data == nullptr) {
83         return;
84     }
85 
86     std::cout << "OnPrepareCompleted param.layer size is " << (int)param.layers.size() << std::endl;
87     auto* thisPtr = static_cast<RenderContextSample *>(data);
88     thisPtr->DoPrepareCompleted(surface, param);
89 }
90 
InitEGL()91 void RenderContextSample::InitEGL()
92 {
93     renderContext = new RenderContext();
94     renderContext->InitializeEglContext();
95 }
96 
Init()97 void RenderContextSample::Init()
98 {
99     backGroundWidth = BACKGROUND_WIDTH;
100     backGroundHeight = BACKGROUND_HEIGHT;
101 
102     drawingWidth = DRAWING_WIDTH;
103     drawingHeight = DRAWING_HEIGHT;
104 
105     CreateBackGroundSurface();
106 
107     CreateDrawingSurface();
108 
109     InitEGL();
110 
111     Sync(0, nullptr);
112 }
113 
Sync(int64_t,void * data)114 void RenderContextSample::Sync(int64_t, void *data)
115 {
116     struct OHOS::FrameCallback cb = {
117         .frequency_ = freq_,
118         .timestamp_ = 0,
119         .userdata_ = data,
120         .callback_ = [this, data]() {
121             this->Sync(SYNC_FUNC_ARG, data);
122         },
123     };
124 
125     OHOS::VsyncError ret = OHOS::VsyncHelper::Current()->RequestFrameCallback(cb);
126     if (ret) {
127         std::cout << "RequestFrameCallback inner " <<  ret << std::endl;
128     }
129 
130     if (!ready_) {
131         return;
132     }
133 
134     Draw();
135 }
136 
CreateBackGroundSurface()137 void RenderContextSample::CreateBackGroundSurface()
138 {
139     backGroundCSurface = IConsumerSurface::Create();
140     backGroundCSurface->SetDefaultWidthAndHeight(backGroundWidth, backGroundHeight);
141     backGroundCSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA);
142 
143     sptr<IBufferProducer> producer = backGroundCSurface->GetProducer();
144     backGroundPSurface= Surface::CreateSurfaceAsProducer(producer);
145     backGroundCSurface->RegisterConsumerListener(this);
146 
147     prevBufferMap_[backGroundCSurface->GetUniqueId()] = nullptr;
148     prevFenceMap_[backGroundCSurface->GetUniqueId()] = SyncFence::INVALID_FENCE;
149 }
150 
CreateDrawingSurface()151 void RenderContextSample::CreateDrawingSurface()
152 {
153     drawingCSurface = IConsumerSurface::Create();
154     drawingCSurface->SetDefaultWidthAndHeight(backGroundWidth, backGroundHeight);
155     drawingCSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA);
156 
157     sptr<IBufferProducer> producer = drawingCSurface->GetProducer();
158     drawingPSurface= Surface::CreateSurfaceAsProducer(producer);
159     drawingCSurface->RegisterConsumerListener(this);
160 
161     prevBufferMap_[drawingCSurface->GetUniqueId()] = nullptr;
162     prevFenceMap_[drawingCSurface->GetUniqueId()] = SyncFence::INVALID_FENCE;
163 }
164 
OnBufferAvailable()165 void RenderContextSample::OnBufferAvailable()
166 {
167 }
168 
ProduceBackGroundBuffer(uint32_t width,uint32_t height)169 SurfaceError RenderContextSample::ProduceBackGroundBuffer(uint32_t width, uint32_t height)
170 {
171     OHOS::sptr<SurfaceBuffer> buffer;
172     int32_t releaseFence = -1;
173     BufferRequestConfig config = {
174         .width = width,
175         .height = height,
176         .strideAlignment = 0x8,
177         .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
178         .usage = backGroundPSurface->GetDefaultUsage(),
179     };
180 
181     SurfaceError ret = backGroundPSurface->RequestBuffer(buffer, releaseFence, config);
182     if (ret != 0) {
183         std::cout << "RequestBuffer failed:" << SurfaceErrorStr(ret).c_str() << std::endl;
184         return ret;
185     }
186 
187     sptr<SyncFence> tempFence = new SyncFence(releaseFence);
188     tempFence->Wait(SYNC_WAIT_TIMEOUT);
189 
190     if (buffer == nullptr) {
191         std::cout << "buffer is nullptr" << std::endl;
192         return SURFACE_ERROR_NULLPTR;
193     }
194 
195     void* addr = static_cast<uint8_t *>(buffer->GetVirAddr());
196     static uint32_t value = 0xffffffff;
197 
198     uint32_t *pixel = static_cast<uint32_t*>(addr);
199 
200     for (uint32_t x = 0; x < width; x++) {
201         for (uint32_t y = 0;  y < height; y++) {
202             *pixel++ = value;
203         }
204     }
205 
206     BufferFlushConfig flushConfig = {
207         .damage = {
208             .w = width,
209             .h = height,
210         },
211     };
212 
213     int32_t acquireFence = -1;
214     ret = backGroundPSurface->FlushBuffer(buffer, acquireFence, flushConfig);
215 
216     std::cout << "Sync: " << SurfaceErrorStr(ret).c_str() << std::endl;
217     return SURFACE_ERROR_OK;
218 }
219 
ProduceDrawingBuffer(uint32_t width,uint32_t height)220 SurfaceError RenderContextSample::ProduceDrawingBuffer(uint32_t width, uint32_t height)
221 {
222     const int CENTER_X = 128;
223     const int CENTER_Y = 128;
224     const int BIG_CIRCLE_RADIUS = 90;
225     const int SMALL_CIRCLE_RADIUS = 20;
226     const int MEDIUM_CIRCLE_RADIUS = 35;
227     const int SMALL_CIRCLE1_X = 86;
228     const int SMALL_CIRCLE1_Y = 86;
229     const int SMALL_CIRCLE2_X = 160;
230     const int SMALL_CIRCLE2_Y = 76;
231     const int MEDIUM_CIRCLE_X = 140;
232     const int MEDIUM_CIRCLE_Y = 150;
233     std::cout << "ProduceDrawingBuffer start" << std::endl;
234 
235     if (nwindow == nullptr) {
236         nwindow = CreateNativeWindowFromSurface(&drawingPSurface);
237         eglSurface = renderContext->CreateEGLSurface((EGLNativeWindowType)nwindow);
238     }
239     NativeWindowHandleOpt(nwindow, SET_BUFFER_GEOMETRY, width, height);
240     renderContext->MakeCurrent(eglSurface);
241 
242     SkCanvas* canvas = renderContext->AcquireSkCanvas(width, height);
243 
244     canvas->clear(SkColorSetARGB(0x20, 0x20, 0x20, 0xFF));
245     SkPaint paint;
246     paint.setColor(SK_ColorRED);
247     paint.setAntiAlias(true);
248     canvas->drawCircle(CENTER_X, CENTER_Y, BIG_CIRCLE_RADIUS, paint);
249     paint.setColor(SK_ColorGREEN);
250     canvas->drawCircle(SMALL_CIRCLE1_X, SMALL_CIRCLE1_Y, SMALL_CIRCLE_RADIUS, paint);
251     canvas->drawCircle(SMALL_CIRCLE2_X, SMALL_CIRCLE2_Y, SMALL_CIRCLE_RADIUS, paint);
252     canvas->drawCircle(MEDIUM_CIRCLE_X, MEDIUM_CIRCLE_Y, MEDIUM_CIRCLE_RADIUS, paint);
253     renderContext->RenderFrame();
254     renderContext->SwapBuffers(eglSurface);
255 
256     std::cout << "ProduceDrawingBuffer end" << std::endl;
257 
258     return SURFACE_ERROR_OK;
259 }
260 
DrawBackgroundLayer(std::shared_ptr<HdiLayerInfo> & layer)261 bool RenderContextSample::DrawBackgroundLayer(std::shared_ptr<HdiLayerInfo> &layer)
262 {
263     int32_t zorder = 0;
264     GraphicIRect dstRect;
265 
266     dstRect.x = 0;  // Absolute coordinates, with offset
267     dstRect.y = 0;
268     dstRect.w = BACKGROUND_WIDTH;
269     dstRect.h = BACKGROUND_HEIGHT;
270 
271     if (!FillBackGroundLayer(layer, zorder, dstRect)) {
272         return false;
273     }
274     return true;
275 }
276 
DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> & layer)277 bool RenderContextSample::DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> &layer)
278 {
279     int32_t zorder = 1;
280     GraphicIRect dstRect;
281 
282     dstRect.x = 0;  // Absolute coordinates, with offset
283     dstRect.y = 0;
284 
285     dstRect.w = DRAWING_WIDTH;
286     dstRect.h = DRAWING_HEIGHT;
287 
288     if (!FillDrawingLayer(layer, 0, zorder, dstRect)) {
289         return false;
290     }
291     return true;
292 }
293 
Draw()294 void RenderContextSample::Draw()
295 {
296     static int32_t count = 0;
297     std::shared_ptr<HdiLayerInfo> backgroundLayer = HdiLayerInfo::CreateHdiLayerInfo();
298     std::shared_ptr<HdiLayerInfo> drawingLayer = HdiLayerInfo::CreateHdiLayerInfo();
299     do {
300         std::cout << "+++++++ draw count " << count << std::endl;
301         if (!DrawBackgroundLayer(backgroundLayer)) {
302             std::cout << "DrawBackgroundLayer failed!" << std::endl;
303             return;
304         }
305 
306         if (!DrawDrawingLayer(drawingLayer)) {
307             std::cout << "DrawDrawingLayer failed!" << std::endl;
308             return;
309         }
310 
311         std::vector<LayerInfoPtr> layers;
312         layers.push_back(backgroundLayer);
313         layers.push_back(drawingLayer);
314 
315         output_->SetLayerInfo(layers);
316 
317         GraphicIRect damageRect;
318         damageRect.x = 0;
319         damageRect.y = 0;
320         damageRect.w = display_w;
321         damageRect.h = display_h;
322         std::vector<GraphicIRect> outputDamages;
323         outputDamages.emplace_back(damageRect);
324         output_->SetOutputDamages(outputDamages);
325 
326         backend_->Repaint(output_);
327         for (auto layerI : layers) {
328             int32_t releaseFence = -1;
329             sptr<SyncFence> tempFence = new SyncFence(releaseFence);
330             layerI->GetSurface()->ReleaseBuffer(layerI->GetBuffer(), tempFence);
331             tempFence->Wait(SYNC_WAIT_TIMEOUT); // 100 ms
332         }
333         std::cout << "------ draw count " << count << std::endl;
334         count++;
335     } while (false);
336 }
337 
FillDrawingLayer(std::shared_ptr<HdiLayerInfo> & showLayer,uint32_t index,uint32_t zorder,GraphicIRect & dstRect)338 bool RenderContextSample::FillDrawingLayer(std::shared_ptr<HdiLayerInfo> &showLayer, uint32_t index,
339     uint32_t zorder, GraphicIRect &dstRect)
340 {
341     if (ProduceDrawingBuffer(drawingWidth, drawingHeight) != SURFACE_ERROR_OK) {
342         std::cout << "FillDrawingLayer produce cBuffer failed" << std::endl;
343         return false;
344     }
345 
346     OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
347     int32_t fence = -1;
348     int64_t timestamp;
349     Rect damage;
350     SurfaceError ret = drawingCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
351     sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
352     if (ret != SURFACE_ERROR_OK) {
353         std::cout << "Acquire cBuffer failed: " << ret << std::endl;
354         return false;
355     }
356 
357     GraphicIRect srcRect;
358     srcRect.x = 0;
359     srcRect.y = 0;
360     srcRect.w = drawingWidth;
361     srcRect.h = drawingHeight;
362 
363     GraphicLayerAlpha alpha = { .enPixelAlpha = true };
364 
365     showLayer->SetSurface(drawingCSurface);
366     showLayer->SetBuffer(cbuffer, acquireSyncFence);
367     showLayer->SetZorder(zorder);
368     showLayer->SetAlpha(alpha);
369     showLayer->SetTransform(GraphicTransformType::GRAPHIC_ROTATE_NONE);
370     showLayer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
371     std::vector<GraphicIRect> visibleRegions;
372     visibleRegions.emplace_back(srcRect);
373     showLayer->SetVisibleRegions(visibleRegions);
374     std::vector<GraphicIRect> dirtyRegions;
375     dirtyRegions.emplace_back(srcRect);
376     showLayer->SetDirtyRegions(dirtyRegions);
377     showLayer->SetLayerSize(dstRect);
378     showLayer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
379     showLayer->SetCropRect(srcRect);
380     showLayer->SetPreMulti(false);
381 
382     prevBufferMap_[drawingCSurface->GetUniqueId()] = cbuffer;
383     prevFenceMap_[drawingCSurface->GetUniqueId()] = acquireSyncFence;
384 
385     return true;
386 }
387 
FillBackGroundLayer(std::shared_ptr<HdiLayerInfo> & showLayer,uint32_t zorder,GraphicIRect & dstRect)388 bool RenderContextSample::FillBackGroundLayer(std::shared_ptr<HdiLayerInfo> &showLayer,
389                                               uint32_t zorder, GraphicIRect &dstRect)
390 {
391     if (ProduceBackGroundBuffer(dstRect.w, dstRect.h) != SURFACE_ERROR_OK) {
392         std::cout << "Produce background cBuffer failed" << std::endl;
393         return false;
394     }
395 
396     OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
397     int32_t fence = -1;
398     int64_t timestamp;
399     Rect damage;
400     SurfaceError ret = backGroundCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
401     sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
402     if (ret != SURFACE_ERROR_OK) {
403         std::cout << "Acquire cBuffer failed" << std::endl;
404         return false;
405     }
406 
407     GraphicIRect srcRect;
408     srcRect.x = 0;
409     srcRect.y = 0;
410     srcRect.w = dstRect.w;
411     srcRect.h = dstRect.h;
412 
413     GraphicLayerAlpha alpha = { .enPixelAlpha = true };
414 
415     showLayer->SetSurface(backGroundCSurface);
416     showLayer->SetBuffer(cbuffer, acquireSyncFence);
417     showLayer->SetZorder(zorder);
418     showLayer->SetAlpha(alpha);
419     showLayer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
420     std::vector<GraphicIRect> visibleRegions;
421     visibleRegions.emplace_back(srcRect);
422     showLayer->SetVisibleRegions(visibleRegions);
423     std::vector<GraphicIRect> dirtyRegions;
424     dirtyRegions.emplace_back(srcRect);
425     showLayer->SetDirtyRegions(dirtyRegions);
426     showLayer->SetLayerSize(dstRect);
427     showLayer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
428     showLayer->SetCropRect(srcRect);
429     showLayer->SetPreMulti(false);
430 
431     prevBufferMap_[backGroundCSurface->GetUniqueId()] = cbuffer;
432     prevFenceMap_[backGroundCSurface->GetUniqueId()] = acquireSyncFence;
433 
434     std::cout << "FillBackGroundLayer finished" << std::endl;
435     return true;
436 }
437 
CreatePhysicalScreen()438 void RenderContextSample::CreatePhysicalScreen()
439 {
440     screen_ = HdiScreen::CreateHdiScreen(output_->GetScreenId());
441     screen_->Init();
442     screen_->GetScreenSupportedModes(displayModeInfos_);
443     size_t supportModeNum = displayModeInfos_.size();
444     if (supportModeNum > 0) {
445         screen_->GetScreenMode(currentModeIndex_);
446         for (size_t i = 0; i < supportModeNum; i++) {
447             if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
448                 this->freq_ = displayModeInfos_[i].freshRate;
449                 this->display_w = displayModeInfos_[i].width;
450                 this->display_h = displayModeInfos_[i].height;
451             }
452         }
453         screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
454         screen_->SetScreenMode(currentModeIndex_);
455 
456         GraphicDispPowerStatus powerState;
457         screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
458         screen_->GetScreenPowerStatus(powerState);
459     }
460 
461     GraphicDisplayCapability info;
462     screen_->GetScreenCapability(info);
463 
464     ready_ = true;
465 }
466 
OnHotPlugEvent(const std::shared_ptr<HdiOutput> & output,bool connected)467 void RenderContextSample::OnHotPlugEvent(const std::shared_ptr<HdiOutput> &output, bool connected)
468 {
469     /*
470      * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
471      * initiated only after the initialization of the device is complete.
472      */
473     output_ = output;
474     deviceConnected_ = connected;
475 
476     if (!initDeviceFinished_) {
477         std::cout << "Init the device has not finished yet" << std::endl;
478         return;
479     }
480 
481     std::cout << "Callback HotPlugEvent, connected is " << connected << std::endl;
482 
483     if (connected) {
484         CreatePhysicalScreen();
485     }
486 }
487 
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)488 void RenderContextSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam &param)
489 {
490     BufferRequestConfig requestConfig = {
491         .width = display_w,  // need display width
492         .height = display_h, // need display height
493         .strideAlignment = 0x8,
494         .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
495         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_FB,
496         .timeout = 0,
497     };
498 
499     if (surface == nullptr) {
500         std::cout << "surface is null" << std::endl;
501         return;
502     }
503 
504     int32_t releaseFence = -1;
505     sptr<SurfaceBuffer> fbBuffer = nullptr;
506     SurfaceError ret1 = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
507     if (ret1 != 0) {
508         std::cout << "RequestBuffer failed " << SurfaceErrorStr(ret1).c_str() << std::endl;
509         return;
510     }
511 
512     sptr<SyncFence> tempFence = new SyncFence(releaseFence);
513     tempFence->Wait(SYNC_WAIT_TIMEOUT);
514     auto addr = static_cast<uint8_t*>(fbBuffer->GetVirAddr());
515     int32_t ret2 = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
516     if (ret2 != 0) {
517         std::cout << "memset_s failed" << std::endl;
518     }
519 
520     BufferFlushConfig flushConfig = {
521         .damage = {
522             .w = display_w,
523             .h = display_h,
524         }
525     };
526 
527     /*
528      * if use GPU produce data, flush with gpu fence
529      */
530     ret2 = surface->FlushBuffer(fbBuffer, -1, flushConfig);
531     if (ret2 != 0) {
532         std::cout << "DoPrepareCompleted FlushBuffer failed"<< std::endl;
533     }
534 }
535