• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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