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 ¶m, 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 = IConsumerSurface::Create();
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 = IConsumerSurface::Create();
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 = GRAPHIC_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->AcquireSkCanvas(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 GraphicIRect 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 GraphicIRect 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 GraphicIRect damageRect;
304 damageRect.x = 0;
305 damageRect.y = 0;
306 damageRect.w = display_w;
307 damageRect.h = display_h;
308 std::vector<GraphicIRect> outputDamages;
309 outputDamages.emplace_back(damageRect);
310 output_->SetOutputDamages(outputDamages);
311
312 backend_->Repaint(output_);
313 for (auto layerI : layers) {
314 int32_t releaseFence = -1;
315 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
316 layerI->GetSurface()->ReleaseBuffer(layerI->GetBuffer(), tempFence);
317 tempFence->Wait(100); // 100 ms
318 }
319 std::cout << "------ draw count " << count << std::endl;
320 count++;
321 } while (false);
322 }
323
FillDrawingLayer(std::shared_ptr<HdiLayerInfo> & showLayer,uint32_t index,uint32_t zorder,GraphicIRect & dstRect)324 bool RenderContextSample::FillDrawingLayer(std::shared_ptr<HdiLayerInfo> &showLayer, uint32_t index,
325 uint32_t zorder, GraphicIRect &dstRect)
326 {
327 if (ProduceDrawingBuffer(drawingWidth, drawingHeight) != SURFACE_ERROR_OK) {
328 std::cout << "FillDrawingLayer produce cBuffer failed" << std::endl;
329 return false;
330 }
331
332 OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
333 int32_t fence = -1;
334 int64_t timestamp;
335 Rect damage;
336 SurfaceError ret = drawingCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
337 sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
338 if (ret != SURFACE_ERROR_OK) {
339 std::cout << "Acquire cBuffer failed: " << ret << std::endl;
340 return false;
341 }
342
343 GraphicIRect srcRect;
344 srcRect.x = 0;
345 srcRect.y = 0;
346 srcRect.w = drawingWidth;
347 srcRect.h = drawingHeight;
348
349 GraphicLayerAlpha alpha = { .enPixelAlpha = true };
350
351 showLayer->SetSurface(drawingCSurface);
352 showLayer->SetBuffer(cbuffer, acquireSyncFence);
353 showLayer->SetZorder(zorder);
354 showLayer->SetAlpha(alpha);
355 showLayer->SetTransform(GraphicTransformType::GRAPHIC_ROTATE_NONE);
356 showLayer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
357 std::vector<GraphicIRect> visibleRegions;
358 visibleRegions.emplace_back(srcRect);
359 showLayer->SetVisibleRegions(visibleRegions);
360 std::vector<GraphicIRect> dirtyRegions;
361 dirtyRegions.emplace_back(srcRect);
362 showLayer->SetDirtyRegions(dirtyRegions);
363 showLayer->SetLayerSize(dstRect);
364 showLayer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
365 showLayer->SetCropRect(srcRect);
366 showLayer->SetPreMulti(false);
367
368 prevBufferMap_[drawingCSurface->GetUniqueId()] = cbuffer;
369 prevFenceMap_[drawingCSurface->GetUniqueId()] = acquireSyncFence;
370
371 return true;
372 }
373
FillBackGroundLayer(std::shared_ptr<HdiLayerInfo> & showLayer,uint32_t zorder,GraphicIRect & dstRect)374 bool RenderContextSample::FillBackGroundLayer(std::shared_ptr<HdiLayerInfo> &showLayer,
375 uint32_t zorder, GraphicIRect &dstRect)
376 {
377 if (ProduceBackGroundBuffer(dstRect.w, dstRect.h) != SURFACE_ERROR_OK) {
378 std::cout << "Produce background cBuffer failed" << std::endl;
379 return false;
380 }
381
382 OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
383 int32_t fence = -1;
384 int64_t timestamp;
385 Rect damage;
386 SurfaceError ret = backGroundCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
387 sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
388 if (ret != SURFACE_ERROR_OK) {
389 std::cout << "Acquire cBuffer failed" << std::endl;
390 return false;
391 }
392
393 GraphicIRect srcRect;
394 srcRect.x = 0;
395 srcRect.y = 0;
396 srcRect.w = dstRect.w;
397 srcRect.h = dstRect.h;
398
399 GraphicLayerAlpha alpha = { .enPixelAlpha = true };
400
401 showLayer->SetSurface(backGroundCSurface);
402 showLayer->SetBuffer(cbuffer, acquireSyncFence);
403 showLayer->SetZorder(zorder);
404 showLayer->SetAlpha(alpha);
405 showLayer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
406 std::vector<GraphicIRect> visibleRegions;
407 visibleRegions.emplace_back(srcRect);
408 showLayer->SetVisibleRegions(visibleRegions);
409 std::vector<GraphicIRect> dirtyRegions;
410 dirtyRegions.emplace_back(srcRect);
411 showLayer->SetDirtyRegions(dirtyRegions);
412 showLayer->SetLayerSize(dstRect);
413 showLayer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
414 showLayer->SetCropRect(srcRect);
415 showLayer->SetPreMulti(false);
416
417 prevBufferMap_[backGroundCSurface->GetUniqueId()] = cbuffer;
418 prevFenceMap_[backGroundCSurface->GetUniqueId()] = acquireSyncFence;
419
420 std::cout << "FillBackGroundLayer finished" << std::endl;
421 return true;
422 }
423
CreatePhysicalScreen()424 void RenderContextSample::CreatePhysicalScreen()
425 {
426 screen_ = HdiScreen::CreateHdiScreen(output_->GetScreenId());
427 screen_->Init();
428 screen_->GetScreenSupportedModes(displayModeInfos_);
429 size_t supportModeNum = displayModeInfos_.size();
430 if (supportModeNum > 0) {
431 screen_->GetScreenMode(currentModeIndex_);
432 for (size_t i = 0; i < supportModeNum; i++) {
433 if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
434 this->freq_ = displayModeInfos_[i].freshRate;
435 this->display_w = displayModeInfos_[i].width;
436 this->display_h = displayModeInfos_[i].height;
437 }
438 }
439 screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
440 screen_->SetScreenMode(currentModeIndex_);
441
442 GraphicDispPowerStatus powerState;
443 screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
444 screen_->GetScreenPowerStatus(powerState);
445 }
446
447 GraphicDisplayCapability info;
448 screen_->GetScreenCapability(info);
449
450 ready_ = true;
451 }
452
OnHotPlugEvent(const std::shared_ptr<HdiOutput> & output,bool connected)453 void RenderContextSample::OnHotPlugEvent(const std::shared_ptr<HdiOutput> &output, bool connected)
454 {
455 /*
456 * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
457 * initiated only after the initialization of the device is complete.
458 */
459 output_ = output;
460 deviceConnected_ = connected;
461
462 if (!initDeviceFinished_) {
463 std::cout << "Init the device has not finished yet" << std::endl;
464 return;
465 }
466
467 std::cout << "Callback HotPlugEvent, connected is " << connected << std::endl;
468
469 if (connected) {
470 CreatePhysicalScreen();
471 }
472 }
473
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)474 void RenderContextSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam ¶m)
475 {
476 BufferRequestConfig requestConfig = {
477 .width = display_w, // need display width
478 .height = display_h, // need display height
479 .strideAlignment = 0x8,
480 .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
481 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_FB,
482 .timeout = 0,
483 };
484
485 if (surface == nullptr) {
486 std::cout << "surface is null" << std::endl;
487 return;
488 }
489
490 int32_t releaseFence = -1;
491 sptr<SurfaceBuffer> fbBuffer = nullptr;
492 SurfaceError ret1 = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
493 if (ret1 != 0) {
494 std::cout << "RequestBuffer failed " << SurfaceErrorStr(ret1).c_str() << std::endl;
495 return;
496 }
497
498 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
499 tempFence->Wait(100);
500
501
502 auto addr = static_cast<uint8_t *>(fbBuffer->GetVirAddr());
503 int32_t ret2 = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
504 if (ret2 != 0) {
505 std::cout << "memset_s failed" << std::endl;
506 }
507
508 BufferFlushConfig flushConfig = {
509 .damage = {
510 .w = display_w,
511 .h = display_h,
512 }
513 };
514
515 /*
516 * if use GPU produce data, flush with gpu fence
517 */
518 ret2 = surface->FlushBuffer(fbBuffer, -1, flushConfig);
519 if (ret2 != 0) {
520 std::cout << "DoPrepareCompleted FlushBuffer failed"<< std::endl;
521 }
522 }
523