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