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