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