1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <sys/time.h>
31
32 #include <graphic_dumper_helper.h>
33 #include <libudev.h>
34
35 #include "hdi_backend.h"
36 #include "hdi_head.h"
37 #include "hdi_output.h"
38 #include "hdi_renderer.h"
39
40 #include "mix_renderer.h"
41
42 // C header adapter
43 extern "C" {
44 #include "libweston/backend-hdi.h"
45 #include "libweston/launcher-util.h"
46 #include "libweston/libweston.h"
47 #include "libweston/libweston-internal.h"
48 #include "libweston/linux-dmabuf.h"
49 #include "libweston/windowed-output-api.h"
50 #include "shared/helpers.h"
51 }
52
53 #include "libweston/trace.h"
54 DEFINE_LOG_LABEL("HdiBackend");
55 constexpr const char *dumper_view_tag = "weston.view";
56 constexpr const char *dumper_hdi_tag = "weston.hdi";
57 constexpr const char *dumper_vsync_tag = "weston.vsync";
58
59 struct hdi_backend *
to_hdi_backend(struct weston_compositor * base)60 to_hdi_backend(struct weston_compositor *base)
61 {
62 return container_of(base->backend, struct hdi_backend, base);
63 }
64
65 static void
hdi_backend_plug_event(uint32_t device_id,bool connected,void * data)66 hdi_backend_plug_event(uint32_t device_id, bool connected, void *data)
67 {
68 LOG_SCOPE();
69 struct hdi_backend *b = (struct hdi_backend *)data;
70
71 if (connected == true) {
72 LOG_INFO("new screen");
73 hdi_head_create(b->compositor, device_id);
74 } else {
75 LOG_INFO("del screen");
76 struct weston_head *base, *next;
77 wl_list_for_each_safe(base, next, &b->compositor->head_list, compositor_link) {
78 if (hdi_head_get_device_id(base) == device_id) {
79 hdi_head_destroy(base);
80 }
81 }
82 }
83 }
84
85 static int
hdi_gl_renderer_init(struct hdi_backend * b)86 hdi_gl_renderer_init(struct hdi_backend *b)
87 {
88 uint32_t format[3] = { b->gbm_format, 0, 0, };
89 const struct gl_renderer_display_options options = {
90 .egl_platform = EGL_PLATFORM_GBM_KHR,
91 .egl_surface_type = EGL_PBUFFER_BIT,
92 .drm_formats = format,
93 .drm_formats_count = 2,
94 };
95
96 b->glri = (struct gl_renderer_interface *)weston_load_module("gl-renderer.so", "gl_renderer_interface");
97 if (!b->glri)
98 return -1;
99
100 return b->glri->display_create(b->compositor, &options);
101 }
102
103 static void
hdi_backend_destroy(struct weston_compositor * ec)104 hdi_backend_destroy(struct weston_compositor *ec)
105 {
106 LOG_SCOPE();
107 struct hdi_backend *b = to_hdi_backend(ec);
108 struct weston_head *base, *next;
109
110 udev_input_destroy(&b->input);
111 weston_compositor_shutdown(ec);
112
113 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
114 hdi_head_destroy(base);
115 }
116
117 delete b->display_gralloc;
118 LayerUninitialize(b->layer_funcs);
119 DeviceUninitialize(b->device_funcs);
120
121 if (b->udev == NULL) {
122 udev_unref(b->udev);
123 }
124
125 delete b;
126 }
127
128 static struct hdi_pending_state *
hdi_backend_create_pending_state(struct hdi_backend * b)129 hdi_backend_create_pending_state(struct hdi_backend *b)
130 {
131 auto hps = new struct hdi_pending_state();
132 if (hps == NULL) {
133 return NULL;
134 }
135
136 hps->backend = b;
137 return hps;
138 }
139
140 static void
hdi_backend_destroy_pending_state(struct hdi_pending_state * hps)141 hdi_backend_destroy_pending_state(struct hdi_pending_state *hps)
142 {
143 delete hps;
144 }
145
146 static void *
hdi_backend_repaint_begin(struct weston_compositor * compositor)147 hdi_backend_repaint_begin(struct weston_compositor *compositor)
148 {
149 LOG_PASS();
150 struct hdi_backend *b = to_hdi_backend(compositor);
151 b->layer_dump_info_pending.clear();
152 b->view_dump_info_pending.clear();
153 return hdi_backend_create_pending_state(to_hdi_backend(compositor));
154 }
155
156 static int
hdi_backend_repaint_flush(struct weston_compositor * compositor,void * repaint_data)157 hdi_backend_repaint_flush(struct weston_compositor *compositor,
158 void *repaint_data)
159 {
160 LOG_SCOPE();
161 struct hdi_backend *b = to_hdi_backend(compositor);
162 auto hps = reinterpret_cast<struct hdi_pending_state *>(repaint_data);
163
164 b->view_dump_info = b->view_dump_info_pending;
165 b->layer_dump_info = b->layer_dump_info_pending;
166 for (auto &[device_id, framebuffer] : hps->framebuffers) {
167 bool needFlushFramebuffer = false;
168 int32_t fence;
169 int ret = b->device_funcs->PrepareDisplayLayers(device_id, &needFlushFramebuffer);
170 LOG_CORE("[ret=%d] DeviceFuncs.PrepareDisplayLayers device_id: %d", ret, device_id);
171
172 /* process comp change */
173 // {
174 // uint32_t layer_numer;
175 // ret = b->device_funcs->GetDisplayCompChange(device_id, &layer_numer, NULL, NULL);
176 // LOG_CORE("[ret=%d] DeviceFuncs.GetDisplayCompChange", ret);
177 // LOG_INFO("change layer number: %d", layer_numer);
178 //
179 // uint32_t *layers = calloc(layer_numer, sizeof *layers);
180 // CompositionType *types = calloc(layer_numer, sizeof *types);
181 // ret = b->device_funcs->GetDisplayCompChange(device_id, &layer_numer, layers, types);
182 // LOG_CORE("[ret=%d] DeviceFuncs.GetDisplayCompChange", ret);
183 // for (uint32_t i = 0; i < layer_numer; i++) {
184 // LOG_INFO("change layer id: %d, type: %d", layers[i], types[i]);
185 // }
186 // free(layers);
187 // free(types);
188 // }
189
190 if (needFlushFramebuffer == true) {
191 ret = b->device_funcs->SetDisplayClientBuffer(device_id, framebuffer, -1);
192 LOG_CORE("[ret=%d] DeviceFuncs.SetDisplayClientBuffer", ret);
193 }
194
195 gettimeofday(&b->samples[b->sample_current], nullptr);
196 b->sample_current = (b->sample_current + 1) % (sizeof(b->samples) / sizeof(b->samples[0]));
197
198 ret = b->device_funcs->Commit(device_id, &fence);
199 LOG_CORE("[ret=%d] DeviceFuncs.Commit", ret);
200
201 /* process release fence */
202 // {
203 // uint32_t layer_numer;
204 // int ret = b->device_funcs->GetDisplayReleaseFence(device_id, &layer_numer, NULL, NULL);
205 // LOG_CORE("[ret=%d] DeviceFuncs.GetDisplayReleaseFence", ret);
206 // LOG_INFO("fence layer number: %d", layer_numer);
207 //
208 // uint32_t *layers = calloc(layer_numer, sizeof *layers);
209 // int32_t *fences = calloc(layer_numer, sizeof *fences);
210 //
211 // ret = b->device_funcs->GetDisplayReleaseFence(device_id, &layer_numer, layers, fences);
212 // LOG_CORE("[ret=%d] DeviceFuncs.GetDisplayReleaseFence", ret);
213 //
214 // for (uint32_t i = 0; i < layer_numer; i++) {
215 // LOG_INFO("layer id: %d, fence: %d", layers[i], fences[i]);
216 // }
217 // }
218 }
219
220 hdi_backend_destroy_pending_state(hps);
221 return 0;
222 }
223
OnDumpView(struct hdi_backend * b)224 void OnDumpView(struct hdi_backend *b)
225 {
226 auto dumper = OHOS::GraphicDumperHelper::GetInstance();
227 for (auto &[device_id, res] : b->view_dump_info) {
228 dumper->SendInfo(dumper_view_tag, "device_id: %d", device_id);
229 for (auto &info : res) {
230 dumper->SendInfo(dumper_view_tag, " [%s]%p",
231 info.type == WESTON_RENDERER_TYPE_HDI ? "hdi" :
232 info.type == WESTON_RENDERER_TYPE_GPU ? "gpu" :
233 "unknown", info.view);
234 }
235 }
236
237 }
238
OnDumpHdi(struct hdi_backend * b)239 void OnDumpHdi(struct hdi_backend *b)
240 {
241 auto dumper = OHOS::GraphicDumperHelper::GetInstance();
242 for (auto &[device_id, res] : b->layer_dump_info) {
243 dumper->SendInfo(dumper_hdi_tag, "device_id: %d", device_id);
244 for (auto &[layer_id, info] : res) {
245 dumper->SendInfo(dumper_hdi_tag, " layer_id: %d", layer_id);
246 dumper->SendInfo(dumper_hdi_tag, " view %p", info.view);
247 dumper->SendInfo(dumper_hdi_tag, " src x: %d, y: %d, w: %d, h: %d",
248 info.src.x, info.src.y, info.src.w, info.src.h);
249 dumper->SendInfo(dumper_hdi_tag, " dst x: %d, y: %d, w: %d, h: %d",
250 info.dst.x, info.dst.y, info.dst.w, info.dst.h);
251 dumper->SendInfo(dumper_hdi_tag, " zorder: %d, blend: %d, composition: %d, transformMode: %d",
252 info.zorder, info.blend_type, info.comp_type, info.rotate_type);
253 }
254 }
255 }
256
OnDumpVsync(struct hdi_backend * b)257 void OnDumpVsync(struct hdi_backend *b)
258 {
259 auto &samples = b->samples;
260 auto &sample_current = b->sample_current;
261 auto framesize = sizeof(samples) / sizeof(samples[0]) - 1;
262
263 auto dumper = OHOS::GraphicDumperHelper::GetInstance();
264 auto last = (sample_current + framesize) % (framesize + 1);
265 int64_t diff = (int64_t)samples[last].tv_sec * 1000000 + (int64_t)samples[last].tv_usec;
266 diff -= (int64_t)samples[sample_current].tv_sec * 1000000 + (int64_t)samples[sample_current].tv_usec;
267 if (diff == 0) {
268 diff = 1;
269 }
270
271 double rate = 1000000.0 / diff * framesize;
272 dumper->SendInfo(dumper_vsync_tag, "framerate: %lf", rate);
273 }
274
275 struct hdi_backend *
hdi_backend_create(struct weston_compositor * compositor,struct weston_hdi_backend_config * config)276 hdi_backend_create(struct weston_compositor *compositor,
277 struct weston_hdi_backend_config *config)
278 {
279 LOG_SCOPE();
280 int ret;
281
282 // ctor1. alloc memory
283 auto b = new struct hdi_backend();
284 if (b == NULL) {
285 LOG_ERROR("zalloc hdi-backend failed");
286 return NULL;
287 }
288
289 // ctor2. init super attributes
290 b->compositor = compositor;
291 compositor->backend = &b->base;
292
293 // ctor3. init virtual function
294 b->base.destroy = hdi_backend_destroy;
295 b->base.repaint_begin = hdi_backend_repaint_begin;
296 b->base.repaint_flush = hdi_backend_repaint_flush;
297 b->base.repaint_cancel = NULL;
298 b->base.create_output = hdi_output_create;
299 b->base.device_changed = NULL;
300 b->base.can_scanout_dmabuf = NULL;
301
302 auto dumper = OHOS::GraphicDumperHelper::GetInstance();
303 dumper->AddDumpListener(dumper_view_tag, std::bind(OnDumpView, b));
304 dumper->AddDumpListener(dumper_hdi_tag, std::bind(OnDumpHdi, b));
305 dumper->AddDumpListener(dumper_vsync_tag, std::bind(OnDumpVsync, b));
306
307 // init renderer
308 ret = mix_renderer_init(compositor);
309 if (ret < 0) {
310 LOG_ERROR("mix_renderer_init failed");
311 goto err_free;
312 }
313
314 ret = hdi_renderer_init(compositor);
315 if (ret < 0) {
316 LOG_ERROR("hdi_renderer_init failed");
317 goto err_free;
318 }
319
320 ret = hdi_gl_renderer_init(b);
321 if (ret < 0) {
322 LOG_ERROR("hdi_gl_renderer_init failed, gpu render disable.");
323 }
324
325 // init hdi device
326 ret = DeviceInitialize(&b->device_funcs);
327 LOG_CORE("[ret=%d] DeviceInitialize", ret);
328 if (ret != DISPLAY_SUCCESS || b->device_funcs == NULL) {
329 LOG_ERROR("DeviceInitialize failed");
330 goto err_free;
331 }
332
333 ret = LayerInitialize(&b->layer_funcs);
334 LOG_CORE("[ret=%d] LayerInitialize", ret);
335 if (ret != DISPLAY_SUCCESS || b->layer_funcs == NULL) {
336 LOG_ERROR("LayerInitialize failed");
337 goto err_device_init;
338 }
339
340 b->display_gralloc = ::OHOS::HDI::Display::V1_0::IDisplayGralloc::Get();
341 if (ret != DISPLAY_SUCCESS || b->display_gralloc == NULL) {
342 LOG_ERROR("IDisplayGralloc::Get failed");
343 goto err_layer_init;
344 }
345
346 do {
347 const char *seat_id = "seat0";
348 compositor->launcher = weston_launcher_connect(compositor, 1,
349 seat_id, true);
350 if (compositor->launcher == NULL) {
351 LOG_ERROR("fatal: drm backend should be run using "
352 "weston-launch binary, or your system should "
353 "provide the logind D-Bus API.");
354 break;
355 }
356
357 b->udev = udev_new();
358 if (b->udev == NULL) {
359 LOG_ERROR("failed to initialize udev context");
360 break;
361 }
362
363 if (udev_input_init(&b->input, compositor,
364 b->udev, "seat0", config->configure_device) < 0) {
365 LOG_ERROR("failed to create input devices");
366 break;
367 }
368
369 udev_input_enable(&b->input);
370 } while (false);
371
372 ret = b->device_funcs->RegHotPlugCallback(hdi_backend_plug_event, b);
373 LOG_CORE("[ret=%d] DeviceFuncs.RegHotPlugCallback", ret);
374
375 // init linux_dmabuf
376 if (compositor->hdi_renderer->import_dmabuf) {
377 if (linux_dmabuf_setup(compositor) < 0) {
378 LOG_ERROR("Error: dmabuf protocol setup failed.\n");
379 goto err_gralloc_init;
380 }
381 }
382
383 // register plugin
384 static const struct weston_hdi_output_api api = {
385 hdi_output_set_mode,
386 };
387 if (weston_plugin_api_register(compositor,
388 WESTON_HDI_OUTPUT_API_NAME, &api, sizeof(api)) < 0) {
389 LOG_ERROR("Failed to register hdi output API.\n");
390 goto err_gralloc_init;
391 }
392
393 return b;
394
395 err_gralloc_init:
396 delete b->display_gralloc;
397
398 err_layer_init:
399 LayerUninitialize(b->layer_funcs);
400
401 err_device_init:
402 DeviceUninitialize(b->device_funcs);
403
404 err_free:
405 weston_compositor_shutdown(compositor);
406 delete b;
407 return NULL;
408 }
409