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 "drawing_engine_sample.h"
17
18 #include "window.h"
19 #include <securec.h>
20 #include <vsync_generator.h>
21 #include <vsync_controller.h>
22 #include <vsync_distributor.h>
23 #include <event_handler.h>
24 #include <vsync_receiver.h>
25 #include <iostream>
26
27 #include "include/core/SkBitmap.h"
28 #include "include/core/SkCanvas.h"
29 #include "draw/canvas.h"
30
31 #ifdef RS_ENABLE_VK
32 #include "platform/ohos/backend/rs_vulkan_context.h"
33 #include "surface_ohos_vulkan.h"
34 #endif
35
36 using namespace OHOS;
37 using namespace OHOS::Rosen;
38
39 namespace {
40 sptr<VSyncReceiver> g_receiver = nullptr;
41 }
42
~DrawingEngineSample()43 DrawingEngineSample::~DrawingEngineSample()
44 {
45 if (benchMark_ != nullptr) {
46 delete benchMark_;
47 benchMark_ = nullptr;
48 }
49 if (drawingProxy != nullptr) {
50 delete drawingProxy;
51 drawingProxy = nullptr;
52 }
53 }
54
SetBenchMark(OHOS::Rosen::BenchMark * benchMark)55 void DrawingEngineSample::SetBenchMark(OHOS::Rosen::BenchMark* benchMark)
56 {
57 benchMark_ = benchMark;
58 std::cout << "SetBenchMark is " << benchMark_ << std::endl;
59 }
60
Run()61 void DrawingEngineSample::Run()
62 {
63 auto generator = CreateVSyncGenerator();
64 sptr<VSyncController> vsyncController = new VSyncController(generator, 0);
65 sptr<VSyncDistributor> vsyncDistributor = new VSyncDistributor(vsyncController, "HelloComposer");
66 sptr<VSyncConnection> vsyncConnection = new VSyncConnection(vsyncDistributor, "HelloComposer");
67 vsyncDistributor->AddConnection(vsyncConnection);
68
69 std::cout << "start to HdiBackend::GetInstance" << std::endl;
70 backend_ = OHOS::Rosen::HdiBackend::GetInstance();
71 if (backend_ == nullptr) {
72 std::cout << "HdiBackend::GetInstance fail" << std::endl;
73 return;
74 }
75
76 backend_->RegScreenHotplug(DrawingEngineSample::OnScreenPlug, this);
77 while (1) {
78 if (output_ != nullptr) {
79 break;
80 }
81 }
82
83 if (!initDeviceFinished_) {
84 if (deviceConnected_) {
85 CreatePhysicalScreen();
86 }
87 initDeviceFinished_ = true;
88 }
89 std::cout << "Init screen succeed" << std::endl;
90
91 backend_->RegPrepareComplete(DrawingEngineSample::OnPrepareCompleted, this);
92
93 sleep(1);
94
95 auto runner = OHOS::AppExecFwk::EventRunner::Create(false);
96 auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
97 g_receiver = new VSyncReceiver(vsyncConnection, nullptr, handler, "DrawingEngineSample");
98 g_receiver->Init();
99 handler->PostTask(std::bind(&DrawingEngineSample::Init, this));
100 runner->Run();
101 }
102
OnScreenPlug(std::shared_ptr<HdiOutput> & output,bool connected,void * data)103 void DrawingEngineSample::OnScreenPlug(std::shared_ptr<HdiOutput> &output, bool connected, void* data)
104 {
105 std::cout << "enter OnScreenPlug, connected is " << connected << std::endl;
106 auto* thisPtr = static_cast<DrawingEngineSample *>(data);
107 thisPtr->OnHotPlugEvent(output, connected);
108 }
109
OnPrepareCompleted(sptr<Surface> & surface,const struct PrepareCompleteParam & param,void * data)110 void DrawingEngineSample::OnPrepareCompleted(
111 sptr<Surface> &surface, const struct PrepareCompleteParam ¶m, void* data)
112 {
113 if (!param.needFlushFramebuffer) {
114 return;
115 }
116
117 if (surface == nullptr) {
118 LOGE("surface is null");
119 return;
120 }
121
122 if (data == nullptr) {
123 LOGE("data ptr is null");
124 return;
125 }
126
127 auto* thisPtr = static_cast<DrawingEngineSample *>(data);
128 thisPtr->DoPrepareCompleted(surface, param);
129 }
130
InitContext()131 void DrawingEngineSample::InitContext()
132 {
133 std::cout << "DrawingEngineSample::InitContext+" << std::endl;
134 drawingProxy = new DrawingProxy();
135 drawingProxy->InitDrawContext();
136 std::cout << "DrawingEngineSample::InitContext-" << std::endl;
137 }
138
Init()139 void DrawingEngineSample::Init()
140 {
141 std::cout << "DrawingEngineSample::Init+" << std::endl;
142 CreateDrawingSurface();
143 InitContext();
144 Sync(0, nullptr);
145 Initilized = true;
146 std::cout << "DrawingEngineSample::Init-" << std::endl;
147 }
148
Sync(int64_t,void * data)149 void DrawingEngineSample::Sync(int64_t, void *data)
150 {
151 std::cout << "Sync+" << std::endl;
152 VSyncReceiver::FrameCallback fcb = {
153 .userData_ = data,
154 .callback_ = std::bind(&DrawingEngineSample::Sync, this, ::std::placeholders::_1, ::std::placeholders::_2),
155 };
156
157 if (g_receiver != nullptr) {
158 g_receiver->RequestNextVSync(fcb);
159 }
160
161 if (!ready_) {
162 LOGE("hdi screen is not ready");
163 return;
164 }
165
166 if (Initilized == false) {
167 LOGI("call init function");
168 return;
169 }
170
171 OutPutDisplay();
172 std::cout << "Sync-" << std::endl;
173 }
174
CreateDrawingSurface()175 void DrawingEngineSample::CreateDrawingSurface()
176 {
177 drawingCSurface = IConsumerSurface::Create();
178 drawingCSurface->SetDefaultWidthAndHeight(drawingWidth, drawingHeight);
179 drawingCSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA);
180
181 sptr<IBufferProducer> producer = drawingCSurface->GetProducer();
182 drawingPSurface= Surface::CreateSurfaceAsProducer(producer);
183 drawingCSurface->RegisterConsumerListener(this);
184
185 prevBufferMap_[drawingCSurface->GetUniqueId()] = nullptr;
186 prevFenceMap_[drawingCSurface->GetUniqueId()] = SyncFence::INVALID_FENCE;
187 }
188
OnBufferAvailable()189 void DrawingEngineSample::OnBufferAvailable()
190 {
191 }
192
ExcuteBenchMark(Drawing::Canvas * canvas)193 void DrawingEngineSample::ExcuteBenchMark(Drawing::Canvas* canvas)
194 {
195 std::cout << "ExcuteBenchMark benchmark is " << benchMark_ << std::endl;
196 if (benchMark_ == nullptr) {
197 return;
198 }
199 benchMark_->Start();
200 benchMark_->Test(canvas, drawingWidth, drawingHeight);
201 benchMark_->Stop();
202 }
203
DoDraw()204 SurfaceError DrawingEngineSample::DoDraw()
205 {
206 std::cout << "DrawingEngineSample::DoDraw+" << std::endl;
207 if (surface_ == nullptr) {
208 surface_ = OHOS::Rosen::SurfaceOhos::CreateSurface(drawingPSurface);
209 }
210 if (surface_ == nullptr) {
211 std::cout << "DrawingEngineSample::surface_ is nullptr" << std::endl;
212 return SURFACE_ERROR_ERROR;
213 }
214 surface_->SetDrawingProxy(drawingProxy);
215
216 std::unique_ptr<SurfaceFrame> surfaceFrame;
217
218 #ifdef RS_ENABLE_VK
219 // For skia and DDGR by Nativewindow
220 surfaceFrame = surface_->NativeRequestFrame(drawingWidth, drawingHeight);
221 if (surfaceFrame == nullptr) {
222 std::cout << "Request Frame Failed" << std::endl;
223 return SURFACE_ERROR_ERROR;
224 }
225 #else
226 // For DDGR by flutter vulkan swapchian and skia-gl by swapbuffer
227 surfaceFrame = surface_->RequestFrame(drawingWidth, drawingHeight);
228 #endif
229 Drawing::Canvas* drcanvas = surface_->GetCanvas(surfaceFrame);
230 ExcuteBenchMark(drcanvas);
231 #ifdef RS_ENABLE_VK
232 // For skia and DDGR by Nativewindow
233 surface_->NativeFlushFrame(surfaceFrame);
234 #else
235 // For DDGR by flutter and skia-gl by swapbuffer
236 surface_->FlushFrame(surfaceFrame);
237 #endif
238
239 std::cout << "DrawingEngineSample::DoDraw-" << std::endl;
240 return SURFACE_ERROR_OK;
241 }
242
DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> & layer)243 bool DrawingEngineSample::DrawDrawingLayer(std::shared_ptr<HdiLayerInfo> &layer)
244 {
245 int32_t zorder = 1;
246 GraphicIRect dstRect;
247 dstRect.x = 0; // Absolute coordinates, with offset
248 dstRect.y = 0;
249 dstRect.w = display_w;
250 dstRect.h = display_h;
251
252 SurfaceError err = DoDraw();
253 if (err != SURFACE_ERROR_OK) {
254 std::cout << "DoDraw failed" << std::endl;
255 return false;
256 }
257
258 OHOS::sptr<SurfaceBuffer> cbuffer = nullptr;
259 int32_t fence = -1;
260 int64_t timestamp;
261 Rect damage;
262 SurfaceError ret = drawingCSurface->AcquireBuffer(cbuffer, fence, timestamp, damage);
263 sptr<SyncFence> acquireSyncFence = new SyncFence(fence);
264 if (ret != SURFACE_ERROR_OK) {
265 std::cout << "Acquire cBuffer failed: " << ret << std::endl;
266 return false;
267 }
268
269 GraphicIRect srcRect;
270 srcRect.x = 0;
271 srcRect.y = 0;
272 srcRect.w = drawingWidth;
273 srcRect.h = drawingHeight;
274 GraphicLayerAlpha alpha = { .enPixelAlpha = true };
275 layer->SetSurface(drawingCSurface);
276 layer->SetBuffer(cbuffer, acquireSyncFence);
277 layer->SetZorder(zorder);
278 layer->SetAlpha(alpha);
279 layer->SetTransform(GraphicTransformType::GRAPHIC_ROTATE_NONE);
280 layer->SetCompositionType(GraphicCompositionType::GRAPHIC_COMPOSITION_DEVICE);
281 std::vector<GraphicIRect> visibleRegions;
282 visibleRegions.emplace_back(srcRect);
283 layer->SetVisibleRegions(visibleRegions);
284 std::vector<GraphicIRect> dirtyRegions;
285 dirtyRegions.emplace_back(srcRect);
286 layer->SetDirtyRegions(dirtyRegions);
287 layer->SetLayerSize(dstRect);
288 layer->SetBlendType(GraphicBlendType::GRAPHIC_BLEND_SRC);
289 layer->SetCropRect(srcRect);
290 layer->SetPreMulti(false);
291 prevBufferMap_[drawingCSurface->GetUniqueId()] = cbuffer;
292 prevFenceMap_[drawingCSurface->GetUniqueId()] = acquireSyncFence;
293
294 return true;
295 }
296
OutPutDisplay()297 void DrawingEngineSample::OutPutDisplay()
298 {
299 static int32_t count = 0;
300 std::shared_ptr<HdiLayerInfo> drawingLayer = HdiLayerInfo::CreateHdiLayerInfo();
301 do {
302 if (!DrawDrawingLayer(drawingLayer)) {
303 std::cout << "DrawDrawingLayer failed!" << std::endl;
304 return;
305 }
306
307 std::vector<LayerInfoPtr> layers;
308 layers.push_back(drawingLayer);
309 output_->SetLayerInfo(layers);
310
311 GraphicIRect damageRect;
312 damageRect.x = 0;
313 damageRect.y = 0;
314 damageRect.w = display_w;
315 damageRect.h = display_h;
316 std::vector<GraphicIRect> outputDamages;
317 outputDamages.emplace_back(damageRect);
318 output_->SetOutputDamages(outputDamages);
319
320 backend_->Repaint(output_);
321 int32_t releaseFence = -1;
322 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
323 drawingCSurface->ReleaseBuffer(prevBufferMap_[drawingCSurface->GetUniqueId()], tempFence);
324 tempFence->Wait(100); // 100 ms
325 std::cout << "draw count " << count << std::endl;
326 std::cout << "display width is " << display_w << ", display height is " << display_h << std::endl;
327
328 count++;
329 } while (false);
330 }
331
CreatePhysicalScreen()332 void DrawingEngineSample::CreatePhysicalScreen()
333 {
334 screen_ = HdiScreen::CreateHdiScreen(output_->GetScreenId());
335 screen_->Init();
336 screen_->GetScreenSupportedModes(displayModeInfos_);
337 size_t supportModeNum = displayModeInfos_.size();
338 if (supportModeNum > 0) {
339 screen_->GetScreenMode(currentModeIndex_);
340 for (size_t i = 0; i < supportModeNum; i++) {
341 if (displayModeInfos_[i].id == static_cast<int32_t>(currentModeIndex_)) {
342 this->freq_ = displayModeInfos_[i].freshRate;
343 this->display_w = displayModeInfos_[i].width;
344 this->display_h = displayModeInfos_[i].height;
345 }
346 }
347 screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
348 screen_->SetScreenMode(currentModeIndex_);
349
350 GraphicDispPowerStatus powerState;
351 screen_->SetScreenPowerStatus(GraphicDispPowerStatus::GRAPHIC_POWER_STATUS_ON);
352 screen_->GetScreenPowerStatus(powerState);
353 }
354
355 GraphicDisplayCapability info;
356 screen_->GetScreenCapability(info);
357
358 std::cout << "display width is " << this->display_w << " display height is " << this->display_h << std::endl;
359
360 drawingWidth = this->display_w;
361 drawingHeight = this->display_h;
362
363 ready_ = true;
364 }
365
OnHotPlugEvent(const std::shared_ptr<HdiOutput> & output,bool connected)366 void DrawingEngineSample::OnHotPlugEvent(const std::shared_ptr<HdiOutput> &output, bool connected)
367 {
368 /*
369 * Currently, IPC communication cannot be nested. Therefore, Vblank registration can be
370 * initiated only after the initialization of the device is complete.
371 */
372 if (output_ != nullptr) {
373 return;
374 }
375 output_ = output;
376 deviceConnected_ = connected;
377
378 if (!initDeviceFinished_) {
379 std::cout << "Init the device has not finished yet" << std::endl;
380 return;
381 }
382
383 std::cout << "Callback HotPlugEvent, connected is " << connected << std::endl;
384 if (connected) {
385 CreatePhysicalScreen();
386 }
387 }
388
DoPrepareCompleted(sptr<Surface> surface,const struct PrepareCompleteParam & param)389 void DrawingEngineSample::DoPrepareCompleted(sptr<Surface> surface, const struct PrepareCompleteParam ¶m)
390 {
391 BufferRequestConfig requestConfig = {
392 .width = display_w, // need display width
393 .height = display_h, // need display height
394 .strideAlignment = 0x8,
395 .format = GRAPHIC_PIXEL_FMT_BGRA_8888,
396 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_FB,
397 .timeout = 0,
398 };
399
400 int32_t releaseFence = -1;
401 sptr<SurfaceBuffer> fbBuffer = nullptr;
402 SurfaceError err = surface->RequestBuffer(fbBuffer, releaseFence, requestConfig);
403 if (err != 0) {
404 LOGE("RequestBuffer failed: %{public}s", SurfaceErrorStr(err).c_str());
405 return;
406 }
407
408 sptr<SyncFence> tempFence = new SyncFence(releaseFence);
409 tempFence->Wait(100); // 100 ms
410
411 int32_t ret = 0;
412 auto addr = static_cast<uint8_t *>(fbBuffer->GetVirAddr());
413 ret = memset_s(addr, fbBuffer->GetSize(), 0, fbBuffer->GetSize());
414 if (ret != 0) {
415 std::cout << "memset_s failed" << std::endl;
416 }
417
418 BufferFlushConfig flushConfig = {
419 .damage = {
420 .w = display_w,
421 .h = display_h,
422 }
423 };
424
425 /*
426 * if use GPU produce data, flush with gpu fence
427 */
428 ret = surface->FlushBuffer(fbBuffer, -1, flushConfig);
429 if (ret != 0) {
430 std::cout << "DoPrepareCompleted FlushBuffer failed"<< std::endl;
431 }
432 }