• 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 #include "config.h"
27 
28 #include <cassert>
29 #include <iomanip>
30 #include <list>
31 #include <sstream>
32 
33 #include <display_type.h>
34 
35 #include "hdi_backend.h"
36 #include "hdi_head.h"
37 #include "hdi_output.h"
38 #include "hdi_renderer.h"
39 
40 // C header adapter
41 extern "C" {
42 #include "libweston/libweston.h"
43 #include "libweston/libweston-internal.h"
44 #include "libweston/pixman-renderer.h"
45 #include "shared/helpers.h"
46 }
47 
48 #include "libweston/trace.h"
49 DEFINE_LOG_LABEL("HdiOutput");
50 
51 #define HDI_OUTPUT_FRMAEBUFFER_SIZE 2
52 #define HDI_OUTPUT_FRMAEBUFFER_GL_SIZE 2
53 
54 struct hdi_output {
55     struct weston_output base;
56     struct weston_mode mode;
57     BufferHandle *hdi_framebuffers[HDI_OUTPUT_FRMAEBUFFER_SIZE];
58     BufferHandle *gl_framebuffers[HDI_OUTPUT_FRMAEBUFFER_GL_SIZE];
59     uint32_t current_framebuffer_id;
60     struct wl_event_source *finish_frame_timer;
61     BufferHandle *framebuffer; // used by read_pixels
62 };
63 
64 static struct hdi_output *
to_hdi_output(struct weston_output * base)65 to_hdi_output(struct weston_output *base)
66 {
67     return container_of(base, struct hdi_output, base);
68 }
69 
70 static int
hdi_output_start_repaint_loop(struct weston_output * output)71 hdi_output_start_repaint_loop(struct weston_output *output)
72 {
73     LOG_SCOPE();
74     struct timespec ts;
75     weston_compositor_read_presentation_clock(output->compositor, &ts);
76     weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
77     return 0;
78 }
79 
80 static int
hdi_finish_frame_handle(void * data)81 hdi_finish_frame_handle(void *data)
82 {
83     LOG_CORE("finish_frame_timer called");
84     struct hdi_output *output =
85         reinterpret_cast<struct hdi_output *>(data);
86     struct timespec ts;
87     weston_compositor_read_presentation_clock(output->base.compositor, &ts);
88     weston_output_finish_frame(&output->base, &ts, 0);
89     return 1;
90 }
91 
92 static void
hdi_output_active_timer(struct hdi_output * output)93 hdi_output_active_timer(struct hdi_output *output)
94 {
95     LOG_CORE("active finish_frame_timer");
96     wl_event_source_timer_update(output->finish_frame_timer,
97                                  1000000 / output->mode.refresh);
98 }
99 
100 static void
hdi_output_create_timer(struct hdi_output * output)101 hdi_output_create_timer(struct hdi_output *output)
102 {
103     struct wl_event_loop *loop =
104         wl_display_get_event_loop(output->base.compositor->wl_display);
105     output->finish_frame_timer =
106         wl_event_loop_add_timer(loop, hdi_finish_frame_handle, output);
107 }
108 
109 static void
hdi_output_destroy_timer(struct hdi_output * output)110 hdi_output_destroy_timer(struct hdi_output *output)
111 {
112     wl_event_source_remove(output->finish_frame_timer);
113     output->finish_frame_timer = NULL;
114 }
115 
operator <<(std::ostream & os,const enum weston_renderer_type & type)116 std::ostream &operator <<(std::ostream &os, const enum weston_renderer_type &type)
117 {
118     switch (type) {
119         case WESTON_RENDERER_TYPE_GPU:
120             os << "GPU";
121             break;
122         case WESTON_RENDERER_TYPE_HDI:
123             os << "HDI";
124             break;
125     }
126     return os;
127 }
128 
dump_to_file(struct weston_buffer * buffer)129 static void dump_to_file(struct weston_buffer *buffer)
130 {
131     static int32_t cnt = 0;
132     static int64_t last = 0;
133     cnt++;
134     int64_t now = (int64_t)std::chrono::duration_cast<std::chrono::nanoseconds>(
135         std::chrono::steady_clock::now().time_since_epoch()).count();
136 
137     if (access("/data/render_dump", F_OK) == -1) {
138         last = now;
139         return;
140     }
141 
142     if (buffer == nullptr) {
143         LOG_ERROR("buffer is nullptr");
144         return;
145     }
146 
147     struct linux_dmabuf_buffer *dmabuf = linux_dmabuf_buffer_get(buffer->resource);
148     if (dmabuf == nullptr) {
149         LOG_ERROR("buffer->resource is not dmabuf");
150         return;
151     }
152 
153     BufferHandle *bh = dmabuf->attributes.buffer_handle;
154     if (bh == NULL) {
155         LOG_ERROR("dmabuf have no BufferHandle");
156         return;
157     }
158 
159     double diff = now - last;
160     if (diff > 1e10) {
161         diff = 0;
162     }
163     last = now;
164 
165     const char *unit = nullptr;
166     if (diff > 1e9) {
167         unit = "s";
168         diff /= 1e9;
169     } else if (diff > 1e6) {
170         unit = "ms";
171         diff /= 1e6;
172     } else if (diff > 1e3) {
173         unit = "us";
174         diff /= 1e3;
175     } else {
176         unit = "ns";
177     }
178 
179     std::stringstream ss;
180     ss << "/data/render_" << cnt << "_" << std::setprecision(3) << diff << unit << ".raw";
181     LOG_INFO("dumpimage: %s [fd=%d] (%dx%d)=%d [format=%d] [usage=%" PRIu64 "] {%" PRIu64 " -> %p}",
182         ss.str().c_str(), bh->fd, bh->width, bh->height,
183         bh->size, bh->format, bh->usage, bh->virAddr, bh->phyAddr);
184 
185     auto fp = fopen(ss.str().c_str(), "a+");
186     if (fp == nullptr) {
187         return;
188     }
189 
190     fwrite(bh->virAddr, bh->size, 1, fp);
191     fclose(fp);
192 }
193 
194 BufferHandle *
hdi_output_get_framebuffer(struct weston_output * output)195 hdi_output_get_framebuffer(struct weston_output *output)
196 {
197     if (output == nullptr) {
198         return nullptr;
199     }
200     return to_hdi_output(output)->framebuffer;
201 }
202 
203 static int
hdi_output_repaint(struct weston_output * output_base,pixman_region32_t * damage,void * repaint_data)204 hdi_output_repaint(struct weston_output *output_base,
205                    pixman_region32_t *damage,
206                    void *repaint_data)
207 {
208     LOG_SCOPE();
209     struct hdi_pending_state *hps =
210         reinterpret_cast<struct hdi_pending_state *>(repaint_data);
211     struct hdi_output *output = to_hdi_output(output_base);
212     struct weston_head *h = weston_output_get_first_head(output_base);
213     auto device_id = hdi_head_get_device_id(h);
214     struct hdi_backend *b = to_hdi_backend(output_base->compositor);
215 
216     // prepare framebuffer
217     output->current_framebuffer_id = (output->current_framebuffer_id + 1) % 2;
218     auto &hdi_framebuffer = output->hdi_framebuffers[output->current_framebuffer_id];
219     int32_t gl_framebuffer_id = output->current_framebuffer_id;
220     if (b->glri) {
221         gl_framebuffer_id = b->glri->output_get_current_fbo_index(output_base);
222     }
223     auto &gl_framebuffer = output->gl_framebuffers[gl_framebuffer_id];
224 
225     // assign view to renderer
226     bool need_gpu_render = false;
227     bool need_hdi_render = false;
228     std::list<std::stringstream> sss;
229     int32_t cnt = 0;
230     struct weston_view *view;
231     wl_list_for_each_reverse(view, &output_base->compositor->view_list, link) {
232         pixman_region32_t repaint;
233         pixman_region32_init(&repaint);
234         pixman_region32_intersect(&repaint,
235                         &view->transform.boundingbox, damage);
236         pixman_region32_subtract(&repaint, &repaint, &view->clip);
237 
238         if (!pixman_region32_not_empty(&repaint)) {
239             continue;
240         }
241         pixman_region32_fini(&repaint);
242 
243         if (cnt++ % 5 == 0) {
244             sss.emplace_back();
245             sss.back() << "view_list:";
246         }
247         sss.back() << " [" << view->renderer_type << "]" << (void *)view << ",";
248 
249         ViewDumpInfo dump_info = {
250             .view = view,
251             .type = view->renderer_type,
252         };
253         b->view_dump_info_pending[device_id].push_back(dump_info);
254 
255         if (view->renderer_type == WESTON_RENDERER_TYPE_GPU) {
256             need_gpu_render = true;
257         } else if (view->renderer_type == WESTON_RENDERER_TYPE_HDI) {
258             need_hdi_render = true;
259         }
260 
261         if (view->surface->type != WL_SURFACE_TYPE_VIDEO) {
262             dump_to_file(view->surface->buffer_ref.buffer);
263         }
264     }
265 
266     LOG_IMPORTANT("device_id: %d", device_id);
267     for (const auto &ss : sss) {
268         LOG_INFO("%s", ss.str().c_str());
269     }
270 
271     // gpu render
272     if (need_gpu_render) {
273         output_base->compositor->gpu_renderer->repaint_output(output_base, damage);
274         if (need_hdi_render) {
275             hdi_renderer_output_set_gpu_buffer(output_base, gl_framebuffer);
276         }
277     }
278 
279     // hdi render
280     if (need_hdi_render) {
281         output_base->compositor->hdi_renderer->repaint_output(output_base, damage);
282         hps->framebuffers[device_id] = hdi_framebuffer;
283     } else {
284         hps->framebuffers[device_id] = gl_framebuffer;
285     }
286 
287     // ScreenShot
288     output->framebuffer = hps->framebuffers[device_id];
289     switch (output->framebuffer->format) {
290         case PIXEL_FMT_RGBA_8888:
291             output_base->compositor->read_format = PIXMAN_a8b8g8r8;
292             break;
293         case PIXEL_FMT_BGRA_8888:
294             output_base->compositor->read_format = PIXMAN_a8r8g8b8;
295             break;
296         default:
297             assert(!"not support format");
298             break;
299     }
300     wl_signal_emit(&output_base->frame_signal, damage);
301 
302     hdi_output_active_timer(output);
303     return 0;
304 }
305 
306 int
hdi_output_set_mode(struct weston_output * base)307 hdi_output_set_mode(struct weston_output *base)
308 {
309     LOG_SCOPE();
310     struct hdi_output *output = to_hdi_output(base);
311     int output_width, output_height;
312 
313     /* We can only be called once. */
314     assert(!output->base.current_mode);
315 
316     /* Make sure we have scale set. */
317     assert(output->base.scale);
318 
319     struct hdi_backend *b = to_hdi_backend(base->compositor);
320     struct weston_head *whead = weston_output_get_first_head(&output->base);
321     uint32_t device_id = hdi_head_get_device_id(whead);
322 
323     uint32_t mode_number = 0;
324     int ret = b->device_funcs->GetDisplaySupportedModes(device_id, &mode_number, NULL);
325     LOG_CORE("DeviceFuncs.GetDisplaySupportedModes return %d", ret);
326 
327     DisplayModeInfo *modes =
328         reinterpret_cast<DisplayModeInfo *>(zalloc(mode_number * sizeof(DisplayModeInfo)));
329     ret = b->device_funcs->GetDisplaySupportedModes(device_id, &mode_number, modes);
330     LOG_CORE("DeviceFuncs.GetDisplaySupportedModes return %d", ret);
331     LOG_INFO("%s support %d modes", base->name, mode_number);
332 
333     uint32_t active_mode_id;
334     ret = b->device_funcs->GetDisplayMode(device_id, &active_mode_id);
335     LOG_CORE("DeviceFuncs.GetDisplayMode return %d", ret);
336 
337     int width = 0;
338     int height = 0;
339     int fresh_rate = 60;
340     for (int i = 0; i < mode_number; i++) {
341         LOG_INFO("modes(%d) %dx%d %dHz", modes[i].id, modes[i].width, modes[i].height, modes[i].freshRate);
342         if (modes[i].id == active_mode_id) {
343             width = modes[i].width;
344             height = modes[i].height;
345             fresh_rate = modes[i].freshRate;
346         }
347     }
348 
349     weston_head_set_monitor_strings(whead, "weston", "hdi", NULL);
350     weston_head_set_physical_size(whead, width, height);
351 
352     output->mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
353     output->mode.width = width * output->base.scale;
354     output->mode.height = height * output->base.scale;
355     output->mode.refresh = fresh_rate * 1000;
356     wl_list_insert(&output->base.mode_list, &output->mode.link);
357 
358     output->base.current_mode = &output->mode;
359     output->base.width = output->base.current_mode->width;
360     output->base.height = output->base.current_mode->height;
361     LOG_INFO("%s now use %d mode, %dx%d %dHz",
362              base->name, active_mode_id,
363              output->base.width, output->base.height, fresh_rate);
364 
365     return 0;
366 }
367 
368 static void
hdi_output_assign_planes(struct weston_output * output_base,void * repaint_data)369 hdi_output_assign_planes(struct weston_output *output_base,
370                          void *repaint_data)
371 {
372     struct weston_view *view;
373     wl_list_for_each(view, &output_base->compositor->view_list, link) {
374         weston_view_move_to_plane(view, &output_base->compositor->primary_plane);
375         view->psf_flags = 0;
376         view->surface->keep_buffer = true;
377     }
378 }
379 
380 static int
hdi_output_enable(struct weston_output * base)381 hdi_output_enable(struct weston_output *base)
382 {
383     LOG_SCOPE();
384     struct hdi_output *output = to_hdi_output(base);
385     struct hdi_backend *b = to_hdi_backend(base->compositor);
386     struct gl_renderer_fbo_options fbo_options;
387 
388     AllocInfo info = {
389         .width = output->mode.width,
390         .height = output->mode.height,
391         .usage = HBM_USE_MEM_DMA | HBM_USE_CPU_READ | HBM_USE_CPU_WRITE,
392         .format = PIXEL_FMT_BGRA_8888,
393     };
394     for (int i = 0; i < HDI_OUTPUT_FRMAEBUFFER_SIZE; i++) {
395         int ret = b->display_gralloc->AllocMem(info, output->hdi_framebuffers[i]);
396         LOG_CORE("GrallocFuncs.AllocMem return %d", ret);
397         b->display_gralloc->Mmap(*output->hdi_framebuffers[i]);
398         LOG_CORE("GrallocFuncs.Mmap return %p", output->hdi_framebuffers[i]->virAddr);
399     }
400 
401     info.format = PIXEL_FMT_RGBA_8888; // gl renderer color format
402     for (int i = 0; i < HDI_OUTPUT_FRMAEBUFFER_GL_SIZE; i++) {
403         int ret = b->display_gralloc->AllocMem(info, output->gl_framebuffers[i]);
404         LOG_CORE("GrallocFuncs.AllocMem return %d", ret);
405         b->display_gralloc->Mmap(*output->gl_framebuffers[i]);
406         LOG_CORE("GrallocFuncs.Mmap return %p", output->gl_framebuffers[i]->virAddr);
407 
408         fbo_options.handle[i] = output->gl_framebuffers[i];
409     }
410 
411     if (base->compositor->gpu_renderer && b->glri) {
412         b->glri->output_fbo_create(base, &fbo_options);
413     }
414 
415     output->base.start_repaint_loop = hdi_output_start_repaint_loop;
416     output->base.repaint = hdi_output_repaint;
417     output->base.assign_planes = hdi_output_assign_planes;
418     output->base.set_dpms = NULL;
419     output->base.switch_mode = NULL;
420     output->base.set_gamma = NULL;
421     output->base.set_backlight = NULL;
422     output->current_framebuffer_id = 0;
423     hdi_renderer_output_create(base, NULL);
424     hdi_output_create_timer(output);
425     hdi_output_active_timer(output);
426     return 0;
427 }
428 
429 static int
hdi_output_disable(struct weston_output * base)430 hdi_output_disable(struct weston_output *base)
431 {
432     LOG_SCOPE();
433     struct hdi_output *output = to_hdi_output(base);
434     struct hdi_backend *b = to_hdi_backend(base->compositor);
435 
436     if (!base->enabled) {
437         return 0;
438     }
439 
440     hdi_output_destroy_timer(output);
441     hdi_renderer_output_destroy(base);
442 
443     for (int i = 0; i < HDI_OUTPUT_FRMAEBUFFER_SIZE; i++) {
444         int ret = b->display_gralloc->Unmap(*output->hdi_framebuffers[i]);
445         LOG_CORE("GrallocFuncs.Unmap hdi_framebuffers");
446         b->display_gralloc->FreeMem(*output->hdi_framebuffers[i]);
447         LOG_CORE("GrallocFuncs.FreeMem hdi_framebuffers");
448     }
449 
450     for (int i = 0; i < HDI_OUTPUT_FRMAEBUFFER_GL_SIZE; i++) {
451         int ret = b->display_gralloc->Unmap(*output->gl_framebuffers[i]);
452         LOG_CORE("GrallocFuncs.Unmap gl_framebuffers");
453         b->display_gralloc->FreeMem(*output->gl_framebuffers[i]);
454         LOG_CORE("GrallocFuncs.FreeMem gl_framebuffers");
455     }
456     return 0;
457 }
458 
459 static void
hdi_output_destroy(struct weston_output * base)460 hdi_output_destroy(struct weston_output *base)
461 {
462     LOG_SCOPE();
463     hdi_output_disable(base);
464     weston_output_release(base);
465     free(to_hdi_output(base));
466 }
467 
468 static int
hdi_output_attach_head(struct weston_output * output_base,struct weston_head * head_base)469 hdi_output_attach_head(struct weston_output *output_base,
470                        struct weston_head *head_base)
471 {
472     LOG_SCOPE();
473     if (output_base->enabled == false) {
474         return 0;
475     }
476 
477     weston_output_schedule_repaint(output_base);
478     return 0;
479 }
480 
481 static void
hdi_output_detach_head(struct weston_output * output_base,struct weston_head * head_base)482 hdi_output_detach_head(struct weston_output *output_base,
483                        struct weston_head *head_base)
484 {
485     LOG_SCOPE();
486     if (output_base->enabled == false) {
487         return;
488     }
489 
490     weston_output_schedule_repaint(output_base);
491 }
492 
493 struct weston_output *
hdi_output_create(struct weston_compositor * compositor,const char * name)494 hdi_output_create(struct weston_compositor *compositor, const char *name)
495 {
496     LOG_SCOPE();
497     assert(name && !"name cannot be NULL.");
498 
499     struct hdi_output *output = (struct hdi_output *)zalloc(sizeof *output);
500     if (!output) {
501         LOG_ERROR("zalloc hdi_output failed");
502         return NULL;
503     }
504 
505     weston_output_init(&output->base, compositor, name);
506 
507     output->base.enable = hdi_output_enable;
508     output->base.destroy = hdi_output_destroy;
509     output->base.disable = hdi_output_disable;
510     output->base.attach_head = hdi_output_attach_head;
511     output->base.detach_head = hdi_output_detach_head;
512 
513     weston_compositor_add_pending_output(&output->base, compositor);
514     return &output->base;
515 }
516