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