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 ¶m, 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 ¶m)
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