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