blob: a90ef0f3edb0b5ef5db6523571160cf15b4d56ed [file] [log] [blame]
Song Zhao1b237602020-02-13 10:58:57 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
9#include <stdio.h>
10#include <stdlib.h>
11#include <stdint.h>
12#include <stdbool.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <errno.h>
16#include <pthread.h>
17#include <string.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/ioctl.h>
21#include <sys/mman.h>
22#include <sys/stat.h>
23
24#include <xf86drm.h>
25#include <xf86drmMode.h>
26#include <libsync.h>
27#include <drm_fourcc.h>
28#include <linux/videodev2.h>
29#include <meson_drm.h>
30
31#include "drm.h"
32#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
33#define MAX_BUF_SIZE 32
34
35static char* drm_master_dev_name = "/dev/dri/card0";
36static char* drm_cli_dev_name = "/dev/dri/renderD128";
37static int drm_fd, drm_cli_fd;
38static int drm_mode_set;
39extern unsigned int global_plane_id;
40
41struct gem_buffer {
42 uint32_t width;
43 uint32_t height;
44 unsigned int planes_count;
45 unsigned int size;
46 unsigned int handles[4];
47 unsigned int pitches[4];
48 unsigned int offsets[4];
49 int export_fds[4];
50
51 unsigned int framebuffer_id;
52};
53
54struct display_properties_ids {
55 uint32_t connector_crtc_id;
56 uint32_t crtc_mode_id;
57 uint32_t crtc_active;
58 uint32_t plane_fb_id;
59 uint32_t plane_crtc_id;
60 uint32_t plane_src_x;
61 uint32_t plane_src_y;
62 uint32_t plane_src_w;
63 uint32_t plane_src_h;
64 uint32_t plane_crtc_x;
65 uint32_t plane_crtc_y;
66 uint32_t plane_crtc_w;
67 uint32_t plane_crtc_h;
68 uint32_t plane_zpos;
69 uint32_t out_fence_ptr;
70};
71
72struct plane {
73 drmModePlane *plane;
74 drmModeObjectProperties *props;
75 drmModePropertyRes **props_info;
76};
77
78struct crtc {
79 drmModeCrtc *crtc;
80 drmModeObjectProperties *props;
81 drmModePropertyRes **props_info;
82};
83
84struct connector {
85 drmModeConnector *connector;
86 drmModeObjectProperties *props;
87 drmModePropertyRes **props_info;
88};
89
90struct display_setup {
91 unsigned int connector_id;
92 unsigned int encoder_id;
93 unsigned int crtc_id;
94 unsigned int plane_id;
95
96 unsigned int x;
97 unsigned int y;
98 unsigned int scaled_width;
99 unsigned int scaled_height;
100 unsigned int crtc_width;
101 unsigned int crtc_height;
102
103 struct display_properties_ids properties_ids;
104 drmModeModeInfo mode;
105
106 struct plane *plane;
107 struct crtc *crtc;
108 struct connector *connector;
109} setup;
110
111struct aml_display {
112 bool started;
113 pthread_t disp_t;
114 unsigned int q_len;
115 unsigned int ri; //read index
116 unsigned int wi; //write index
117 unsigned int total_num;
118 struct drm_frame *queue;
119};
120
121static struct gem_buffer *gem_buf;
122static struct gem_buffer osd_gem_buf;
123static displayed_cb_func display_cb;
124static struct aml_display aml_dis;
125
126static int create_meson_gem_buffer(int fd, enum frame_format fmt,
127 struct gem_buffer *buffer)
128{
129 struct drm_meson_gem_create gem_create;
130 int rc;
131 int i;
132 int width = buffer->width;
133 int height = buffer->height;
134
135 if (!buffer)
136 return -1;
137
138 for (i = 0; i < buffer->planes_count; i++) {
139 memset(&gem_create, 0, sizeof(gem_create));
140
141 if (fmt == FRAME_FMT_AFBC) {
142 gem_create.flags = MESON_USE_VIDEO_AFBC;
143 gem_create.size = width * height * 2;
144 buffer->pitches[i] = width*2;
145 } else {
146 gem_create.flags = MESON_USE_VIDEO_PLANE;
147 if (i == 0)
148 gem_create.size = width * height;
149 else
150 gem_create.size = width * height / 2;
151 buffer->pitches[i] = width;
152 }
153
154 rc = drmIoctl(fd, DRM_IOCTL_MESON_GEM_CREATE, &gem_create);
155 if (rc < 0) {
156 printf("Unable to create dumb buffer: %s\n",
157 strerror(errno));
158 return -1;
159 }
160
161 buffer->size += gem_create.size;
162 buffer->handles[i] = gem_create.handle;
163 buffer->offsets[i] = 0;
164
165 rc = drmPrimeHandleToFD(fd, buffer->handles[i], DRM_CLOEXEC | DRM_RDWR,
166 &buffer->export_fds[i]);
167 if (rc < 0) {
168 fprintf(stderr, "drmPirmeHandleToFD fail: %s\n", strerror(errno));
169 return -1;
170 }
171 }
172
173 return 0;
174}
175
176static int close_buffer(int fd, struct gem_buffer *buffer)
177{
178 int rc;
179 int i;
180 struct drm_mode_destroy_dumb destroy_dumb;
181
182 if (!buffer)
183 return -1;
184
185 for (i = 0; i < buffer->planes_count; i++)
186 close(buffer->export_fds[i]);
187
188 drmModeRmFB(fd, buffer->framebuffer_id);
189
190 memset(&destroy_dumb, 0, sizeof(destroy_dumb));
191 for (i = 0; i < buffer->planes_count; i++) {
192 destroy_dumb.handle = buffer->handles[i];
193
194 rc = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
195 if (rc < 0) {
196 fprintf(stderr, "Unable to destroy buffer: %s\n",
197 strerror(errno));
198 return -1;
199 }
200 }
201
202 return 0;
203}
204
205static int add_framebuffer(int fd, struct gem_buffer *buffer,
206 enum frame_format fmt, uint64_t modifier)
207{
208 uint64_t modifiers[4] = { 0, 0, 0, 0 };
209 uint32_t flags = 0;
210 unsigned int id;
211 unsigned int i;
212 int rc;
213 uint32_t drm_fmt;
214
215 if (fmt == FRAME_FMT_NV21)
216 drm_fmt = DRM_FORMAT_NV21;
217 else if (fmt == FRAME_FMT_NV12)
218 drm_fmt = DRM_FORMAT_NV12;
219 else if (fmt == FRAME_FMT_AFBC)
220 drm_fmt = DRM_FORMAT_YUYV;
221 else {
222 printf("ftm %d not supported\n", fmt);
223 return -1;
224 }
225
226 for (i = 0; i < buffer->planes_count; i++) {
227 if (buffer->handles[i] != 0 &&
228 modifier != DRM_FORMAT_MOD_NONE) {
229 flags |= DRM_MODE_FB_MODIFIERS;
230 modifiers[i] = modifier;
231 }
232 }
233
234 rc = drmModeAddFB2WithModifiers(fd, buffer->width,
235 buffer->height, drm_fmt,
236 buffer->handles, buffer->pitches,
237 buffer->offsets, modifiers, &id, flags);
238 if (rc < 0) {
239 fprintf(stderr, "Unable to add framebuffer for plane: %s\n",
240 strerror(errno));
241 return -1;
242 }
243
244 buffer->framebuffer_id = id;
245
246 return 0;
247}
248
249static int discover_properties(int fd, struct display_properties_ids *ids)
250{
251 //int connector_id = setup.connector_id;
252 int crtc_id = setup.crtc_id;
253 int plane_id = setup.plane_id;
254 drmModeObjectPropertiesPtr properties = NULL;
255 drmModePropertyPtr property = NULL;
256 struct {
257 uint32_t object_type;
258 uint32_t object_id;
259 char *name;
260 uint32_t *value;
261 } glue[] = {
262 { DRM_MODE_OBJECT_PLANE, plane_id, "FB_ID", &ids->plane_fb_id },
263 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_ID", &ids->plane_crtc_id },
264 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_X", &ids->plane_src_x },
265 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_Y", &ids->plane_src_y },
266 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_W", &ids->plane_src_w },
267 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_H", &ids->plane_src_h },
268 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_X", &ids->plane_crtc_x },
269 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_Y", &ids->plane_crtc_y },
270 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_W", &ids->plane_crtc_w },
271 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_H", &ids->plane_crtc_h },
272 { DRM_MODE_OBJECT_CRTC, crtc_id, "OUT_FENCE_PTR", &ids->out_fence_ptr},
273 };
274 unsigned int i, j;
275 int rc;
276
277 for (i = 0; i < ARRAY_SIZE(glue); i++) {
278 properties = drmModeObjectGetProperties(fd,
279 glue[i].object_id,
280 glue[i].object_type);
281 if (properties == NULL) {
282 fprintf(stderr, "Unable to get DRM properties(%s): %s\n",
283 glue[i].name, strerror(errno));
284 goto error;
285 }
286
287 for (j = 0; j < properties->count_props; j++) {
288 property = drmModeGetProperty(fd,
289 properties->props[j]);
290 if (property == NULL) {
291 fprintf(stderr, "Unable to get DRM property: %s\n",
292 strerror(errno));
293 goto error;
294 }
295
296 if (strcmp(property->name, glue[i].name) == 0) {
297 *glue[i].value = property->prop_id;
298 break;
299 }
300
301 drmModeFreeProperty(property);
302 property = NULL;
303 }
304
305 if (j == properties->count_props) {
306 fprintf(stderr, "Unable to find property for %s\n",
307 glue[i].name);
308 goto error;
309 }
310
311 drmModeFreeProperty(property);
312 property = NULL;
313
314 drmModeFreeObjectProperties(properties);
315 properties = NULL;
316 }
317
318 rc = 0;
319 goto complete;
320
321error:
322 rc = -1;
323
324complete:
325 if (property != NULL)
326 drmModeFreeProperty(property);
327
328 if (properties != NULL)
329 drmModeFreeObjectProperties(properties);
330
331 return rc;
332}
333
334static int add_connector_property(drmModeAtomicReq *req, uint32_t obj_id,
335 const char *name, uint64_t value, struct display_setup *setup)
336{
337 struct connector *obj = setup->connector;
338 unsigned int i;
339 int prop_id = 0;
340
341 for (i = 0 ; i < obj->props->count_props ; i++) {
342 if (strcmp(obj->props_info[i]->name, name) == 0) {
343 prop_id = obj->props_info[i]->prop_id;
344 break;
345 }
346 }
347
348 if (prop_id < 0) {
349 printf("no connector property: %s\n", name);
350 return -EINVAL;
351 }
352
353 return drmModeAtomicAddProperty(req, obj_id, prop_id, value);
354}
355
356static int add_crtc_property(drmModeAtomicReq *req, uint32_t obj_id,
357 const char *name, uint64_t value, struct display_setup *setup)
358{
359 struct crtc *obj = setup->crtc;
360 unsigned int i;
361 int prop_id = -1;
362
363 for (i = 0 ; i < obj->props->count_props ; i++) {
364 if (strcmp(obj->props_info[i]->name, name) == 0) {
365 prop_id = obj->props_info[i]->prop_id;
366 break;
367 }
368 }
369
370 if (prop_id < 0) {
371 printf("no crtc property: %s\n", name);
372 return -EINVAL;
373 }
374
375 return drmModeAtomicAddProperty(req, obj_id, prop_id, value);
376}
377
378int span(struct timeval* t1, struct timeval* t2)
379{
380 int64_t time = (t2->tv_sec - t1->tv_sec);
381 time *= 1000000;
382 time += t2->tv_usec - t1->tv_usec;
383 time /= 1000;
384 return (int)time;
385}
386
387static int page_flip(int fd, unsigned int crtc_id, unsigned int plane_id,
388 struct display_properties_ids *ids,
389 struct gem_buffer* gem_buf)
390{
391 drmModeAtomicReqPtr request;
392 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
393 int rc;
394 int out_fence_fd = 0;
395 //struct timeval t1, t2;
396
397 request = drmModeAtomicAlloc();
398
399 if (!drm_mode_set) {
400 unsigned int connector_id = setup.connector_id;
401 uint32_t blob_id;
402
403 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
404 if (add_connector_property(request, connector_id, "CRTC_ID",
405 crtc_id, &setup) < 0)
406 return -1;
407
408 if (drmModeCreatePropertyBlob(fd, &setup.mode, sizeof(drmModeModeInfo),
409 &blob_id) != 0)
410 return -1;
411
412 if (add_crtc_property(request, crtc_id, "MODE_ID", blob_id, &setup) < 0)
413 return -1;
414
415 if (add_crtc_property(request, crtc_id, "ACTIVE", 1, &setup) < 0)
416 return -1;
417
418 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_x, 0);
419 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_y, 0);
420 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_w,
421 setup.scaled_width);
422 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_h,
423 setup.scaled_height);
424 drm_mode_set = 1;
425 }
426
427 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_x, 0);
428 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_y, 0);
429 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_w,
430 gem_buf->width << 16);
431 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_h,
432 gem_buf->height << 16);
433
434 drmModeAtomicAddProperty(request, plane_id, ids->plane_fb_id,
435 gem_buf->framebuffer_id);
436 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_id,
437 crtc_id);
438 drmModeAtomicAddProperty(request, crtc_id, ids->out_fence_ptr, (unsigned long)&out_fence_fd);
439
440 rc = drmModeAtomicCommit(fd, request, flags, NULL);
441 if (rc < 0) {
442 fprintf(stderr, "Unable to flip page: %s\n", strerror(errno));
443 goto error;
444 }
445
446 //gettimeofday(&t1, NULL);
447 rc = sync_wait(out_fence_fd, 50);
448 if (rc < 0)
449 printf("wait out fence fail %d, %s\n", rc, strerror(errno));
450 else {
451 //gettimeofday(&t2, NULL);
452 //printf("%s %d span:%d\n", __func__, __LINE__, span(&t1, &t2));
453 }
454 close(out_fence_fd);
455 rc = 0;
456 goto complete;
457
458error:
459 rc = -1;
460
461complete:
462 drmModeAtomicFree(request);
463
464 return rc;
465}
466
467static uint32_t find_crtc_for_encoder(const drmModeRes *resources,
468 const drmModeEncoder *encoder) {
469 int i;
470
471 for (i = 0; i < resources->count_crtcs; i++) {
472 /* possible_crtcs is a bitmask as described here:
473 * https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api
474 */
475 const uint32_t crtc_mask = 1 << i;
476 const uint32_t crtc_id = resources->crtcs[i];
477 if (encoder->possible_crtcs & crtc_mask) {
478 return crtc_id;
479 }
480 }
481
482 /* no match found */
483 return -1;
484}
485
486static uint32_t find_crtc_for_connector(int fd, const drmModeRes *resources,
487 const drmModeConnector *connector) {
488 int i;
489
490 for (i = 0; i < connector->count_encoders; i++) {
491 const uint32_t encoder_id = connector->encoders[i];
492 drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id);
493
494 if (encoder) {
495 const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder);
496
497 drmModeFreeEncoder(encoder);
498 if (crtc_id != 0) {
499 return crtc_id;
500 }
501 }
502 }
503
504 /* no match found */
505 return -1;
506}
507
508static int init_drm(int fd, drmModeModeInfo *mode)
509{
510 drmModeRes *resources;
511 drmModeConnector *connector = NULL;
512 drmModeEncoder *encoder = NULL;
513 int i, area;
514 drmModeModeInfo *curr_mode;
515
516
517 resources = drmModeGetResources(fd);
518 if (!resources) {
519 printf("drmModeGetResources failed: %s\n", strerror(errno));
520 return -1;
521 }
522
523 /* find a connected connector: */
524 for (i = 0; i < resources->count_connectors; i++) {
525 connector = drmModeGetConnector(fd, resources->connectors[i]);
526 if (connector->connection == DRM_MODE_CONNECTED) {
527 /* it's connected, let's use this! */
528 break;
529 }
530 drmModeFreeConnector(connector);
531 connector = NULL;
532 }
533
534 if (!connector) {
535 /* we could be fancy and listen for hotplug events and wait for
536 * a connector..
537 */
538 printf("no connected connector!\n");
539 return -1;
540 }
541
542 setup.connector_id = connector->connector_id;
543
544 /* find preferred mode or the highest resolution mode: */
545 for (i = 0, area = 0; i < connector->count_modes; i++) {
546 drmModeModeInfo *current_mode = &connector->modes[i];
547
548 if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
549 curr_mode = current_mode;
550 }
551
552 int current_area = current_mode->hdisplay * current_mode->vdisplay;
553 if (current_area > area) {
554 curr_mode = current_mode;
555 area = current_area;
556 }
557 }
558
559 if (!curr_mode) {
560 printf("could not find mode!\n");
561 return -1;
562 }
563
564 memcpy(mode, curr_mode, sizeof(drmModeModeInfo));
565
566 /* find encoder: */
567 for (i = 0; i < resources->count_encoders; i++) {
568 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
569 if (encoder->encoder_id == connector->encoder_id)
570 break;
571 drmModeFreeEncoder(encoder);
572 encoder = NULL;
573 }
574
575 if (encoder) {
576 setup.crtc_id = encoder->crtc_id;
577 } else {
578 uint32_t crtc_id1 = find_crtc_for_connector(fd, resources, connector);
579 setup.crtc_id = crtc_id1;
580 }
581
582 drmModeFreeResources(resources);
583
584 return 0;
585}
586
587static int OsdBufferCreate(int fd, uint32_t width,
588 uint32_t height, struct gem_buffer *buffer) {
589 int rc;
590 uint32_t flags = 0;
591 void *data;
592 struct drm_mode_create_dumb create_dumb;
593 uint64_t modifiers[4] = { 0, 0, 0, 0 };
594 struct drm_mode_map_dumb map_dumb;
595
596 memset(&create_dumb, 0, sizeof(create_dumb));
597 create_dumb.width = width;
598 create_dumb.height = height;
599 create_dumb.bpp = 32;
600
601 rc = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
602 if (rc < 0) {
603 printf("Unable to create dumb buffer: %s\n", strerror(errno));
604 return -1;
605 }
606
607 buffer->size = create_dumb.size;
608 buffer->pitches[0] = create_dumb.pitch;
609 buffer->offsets[0] = 0;
610 buffer->handles[0] = create_dumb.handle;
611
612 rc = drmModeAddFB2WithModifiers(fd, width, height, DRM_FORMAT_ARGB8888,
613 buffer->handles, buffer->pitches,
614 buffer->offsets, modifiers, &buffer->framebuffer_id, flags);
615 if (rc < 0) {
616 printf("Unable to add framebuffer for osd plane: %s\n", strerror(errno));
617 return -1;
618 }
619
620 memset(&map_dumb, 0, sizeof(map_dumb));
621 map_dumb.handle = buffer->handles[0];
622 rc = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
623 if (rc < 0) {
624 printf("Unable to map buffer: %s\n", strerror(errno));
625 return -1;
626 }
627
628 data = mmap(0, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
629 map_dumb.offset);
630 if (data == MAP_FAILED) {
631 printf("Unable to mmap buffer: %s\n", strerror(errno));
632 return -1;
633 }
634
635 /* make it transparent */
636 memset(data, 0, buffer->size);
637
638 munmap(data, buffer->size);
639 return 0;
640}
641
642int config_sys_node(const char* path, const char* value)
643{
644 int fd;
645 /* enable video plane */
646 fd = open(path, O_RDWR);
647 if (fd < 0) {
648 printf("fail to open %s\n", path);
649 return -1;
650 }
651 if (write(fd, value, strlen(value)) != 1) {
652 printf("fail to write %s to %s\n", value, path);
653 return -1;
654 }
655 close(fd);
656
657 return 0;
658}
659
660int display_engine_start()
661{
662 unsigned int plane_id;
663 drmModeModeInfo mode;
664 int rc;
665
666 drm_fd = drmOpen("meson", drm_master_dev_name);
667 if (drm_fd < 0) {
668 printf("Unable to open DRM node: %s\n",
669 strerror(errno));
670 return -1;
671 }
672
673 drm_cli_fd = drmOpen("meson", drm_cli_dev_name);
674 if (drm_cli_fd < 0) {
675 printf("Unable to open client DRM node: %s\n",
676 strerror(errno));
677 return -1;
678 }
679
680 rc = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
681 if (rc < 0) {
682 fprintf(stderr, "Unable to set DRM atomic capability: %s\n",
683 strerror(errno));
684 return -1;
685 }
686
687 rc = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
688 if (rc < 0) {
689 fprintf(stderr,
690 "Unable to set DRM universal planes capability: %s\n",
691 strerror(errno));
692 return -1;
693 }
694
695 /* prepare all connectors and CRTCs */
696 rc = init_drm(drm_fd, &mode);
697 if (rc) {
698 fprintf(stderr, "modeset_prepare fail\n");
699 return -1;
700 }
701
702 plane_id = global_plane_id;
703 if (rc < 0) {
704 printf("Unable to select DRM plane for CRTC %d\n",
705 setup.crtc_id);
706 return -1;
707 }
708
709 setup.crtc_width = mode.hdisplay;
710 setup.crtc_height = mode.vdisplay;
711 setup.scaled_width = mode.hdisplay;
712 setup.scaled_height = mode.vdisplay;
713
714 memcpy(&setup.mode, &mode, sizeof(drmModeModeInfo));
715 setup.plane_id = plane_id;
716
717 printf("plane: %u, crtc: %u, encoder:%u, connector: %u.\n",
718 setup.plane_id, setup.crtc_id,
719 setup.encoder_id, setup.connector_id);
720
721 rc = discover_properties(drm_fd, &setup.properties_ids);
722 if (rc < 0) {
723 fprintf(stderr, "Unable to discover DRM properties\n");
724 return -1;
725 }
726
727 setup.plane = calloc(1, sizeof(struct plane));
728 setup.crtc = calloc(1, sizeof(struct crtc));
729 setup.connector = calloc(1, sizeof(struct connector));
730
731#define get_resource(type, Type, id) do { \
732 setup.type->type = drmModeGet##Type(drm_fd, id); \
733 if (!setup.type->type) { \
734 printf("could not get %s %i: %s\n", \
735#type, id, strerror(errno)); \
736 return -1; \
737 } \
738} while (0)
739
740 get_resource(plane, Plane, setup.plane_id);
741 get_resource(crtc, Crtc, setup.crtc_id);
742 get_resource(connector, Connector, setup.connector_id);
743
744#define get_properties(type, TYPE, id) do { \
745 uint32_t i; \
746 setup.type->props = drmModeObjectGetProperties(drm_fd, \
747 id, DRM_MODE_OBJECT_##TYPE); \
748 if (!setup.type->props) { \
749 printf("could not get %s %u properties: %s\n", \
750#type, id, strerror(errno)); \
751 return -1; \
752 } \
753 setup.type->props_info = calloc(setup.type->props->count_props, \
754 sizeof(setup.type->props_info)); \
755 for (i = 0; i < setup.type->props->count_props; i++) { \
756 setup.type->props_info[i] = drmModeGetProperty(drm_fd, \
757 setup.type->props->props[i]); \
758 } \
759} while (0)
760
761 get_properties(plane, PLANE, setup.plane_id);
762 get_properties(crtc, CRTC, setup.crtc_id);
763 get_properties(connector, CONNECTOR, setup.connector_id);
764
765 /* enable video plane */
766 config_sys_node("/sys/class/video/disable_video", "0");
767 /* ignore frame duration */
768 config_sys_node("/sys/class/video/freerun_mode", "1");
769
770 /* make osd transparent */
771 rc = OsdBufferCreate(drm_cli_fd, setup.crtc_width, setup.crtc_height, &osd_gem_buf);
772 if (rc) {
773 printf("OsdBufferCreate fail %d\n", rc);
774 return -1;
775 }
776 rc = drmModeSetCrtc(drm_fd, setup.crtc_id, osd_gem_buf.framebuffer_id, 0, 0,
777 &setup.connector_id, 1, &setup.mode);
778 if (rc) {
779 printf("drmModeSetCrtc fail %d\n", rc);
780 return -1;
781 }
782 return 0;
783}
784
785static int frame_destroy(struct drm_frame* drm_f)
786{
787 int rc;
788 struct gem_buffer *gem_buf = drm_f->gem;
789
790 rc = close_buffer(drm_cli_fd, gem_buf);
791 free(gem_buf);
792 free(drm_f);
793 return rc;
794}
795
796struct drm_frame* display_create_buffer(unsigned int width, unsigned int height,
797 enum frame_format format, int planes_count)
798{
799 int rc;
800 struct drm_frame* frame = calloc(1, sizeof(*frame));
801 struct gem_buffer *gem_buf = calloc(1, sizeof(*gem_buf));
802
803 if (!frame || !gem_buf) {
804 printf("oom\n");
805 return NULL;
806 }
807
808 gem_buf->width = width;
809 gem_buf->height = height;
810 frame->gem = gem_buf;
811 frame->destroy = frame_destroy;
812
813 gem_buf->planes_count = planes_count;
814
815 rc = create_meson_gem_buffer(drm_cli_fd, format, gem_buf);
816 if (rc < 0) {
817 printf("create_meson_gem_buffer fail %d\n", rc);
818 goto error;
819 }
820 if (planes_count == 2)
821 printf("export_fd: %d/%d\n",
822 gem_buf->export_fds[0],
823 gem_buf->export_fds[1]);
824 else
825 printf("export_fd: %d\n",
826 gem_buf->export_fds[0]);
827
828 rc = add_framebuffer(drm_cli_fd, gem_buf,
829 format, DRM_FORMAT_MOD_NONE);
830 if (rc < 0) {
831 printf("Unable to add DRM framebuffer\n");
832 goto error;
833 }
834
835 return frame;
836error:
837 close_buffer(drm_cli_fd, gem_buf);
838 if (frame) free(frame);
839 if (gem_buf) free(gem_buf);
840 return NULL;
841}
842
843int display_get_buffer_fds(struct drm_frame* drm_f, int *fd, int cnt)
844{
845 int i;
846 struct gem_buffer *gem_buf = drm_f->gem;
847
848 if (gem_buf->planes_count > cnt || !fd) {
849 return -1;
850 }
851 for (i = 0; i < gem_buf->planes_count; i++)
852 fd[i] = gem_buf->export_fds[i];
853 return 0;
854}
855
856int display_engine_stop()
857{
858 aml_dis.started = false;
859 pthread_join(aml_dis.disp_t, NULL);
860 close_buffer(drm_cli_fd, &osd_gem_buf);
861
862 if (aml_dis.queue)
863 free(aml_dis.queue);
864 if (gem_buf)
865 free(gem_buf);
866 if (setup.plane) {
867 if (setup.plane->props_info)
868 free(setup.plane->props_info);
869 free(setup.plane);
870 }
871 if (setup.crtc) {
872 if (setup.crtc->props_info)
873 free(setup.crtc->props_info);
874 free(setup.crtc);
875 }
876 if (setup.connector) {
877 if (setup.connector->props_info)
878 free(setup.connector->props_info);
879 free(setup.connector);
880 }
881 if (drm_fd >= 0)
882 drmClose(drm_fd);
883 if (drm_cli_fd >= 0)
884 drmClose(drm_cli_fd);
885
886 return 0;
887}
888
889static int queue_frame(struct drm_frame* frame)
890{
891 if (aml_dis.total_num == aml_dis.q_len)
892 return -1;
893 aml_dis.queue[aml_dis.wi] = *frame;
894 if (aml_dis.wi == aml_dis.q_len - 1)
895 aml_dis.wi = 0;
896 else
897 aml_dis.wi++;
898 aml_dis.total_num++;
899
900 return 0;
901}
902
903static int dequeue_frame(struct drm_frame* frame)
904{
905 if (!aml_dis.total_num)
906 return -1;
907 *frame = aml_dis.queue[aml_dis.ri];
908 if (aml_dis.ri == aml_dis.q_len - 1)
909 aml_dis.ri = 0;
910 else
911 aml_dis.ri++;
912 aml_dis.total_num--;
913
914 return 0;
915}
916
917static void * display_thread_func(void * arg)
918{
919 struct drm_frame f, f_p1, f_p2;
920 unsigned int fence_num;
921
922 f.pri_dec = NULL;
923 f_p1.pri_dec = NULL;
924 f_p2.pri_dec = NULL;
925
926 while (aml_dis.started) {
927 int rc;
928 struct gem_buffer* gem_buf;
929
930 rc = dequeue_frame(&f);
931 if (rc) {
932 usleep(10);
933 continue;
934 }
935 gem_buf = f.gem;
936
937 rc = page_flip(drm_fd, setup.crtc_id, setup.plane_id,
938 &setup.properties_ids, gem_buf);
939 if (rc) {
940 printf("page_flip error\n");
941 continue;
942 }
943 fence_num++;
944 /* 2 fence delay on video layer, 1 fence delay on osd */
945 if (f_p2.pri_dec) {
946 display_cb(f_p2.pri_dec);
947 }
948
949 f_p2 = f_p1;
950 f_p1 = f;
951 }
952 return NULL;
953}
954
955int display_engine_show(struct drm_frame* frame)
956{
957 int rc;
958
959 if (!aml_dis.started) {
960 aml_dis.queue = (struct drm_frame*)calloc(MAX_BUF_SIZE, sizeof(*aml_dis.queue));
961 if (!aml_dis.queue) {
962 printf("%s OOM\n", __func__);
963 return -1;
964 }
965 aml_dis.q_len = MAX_BUF_SIZE;
966 aml_dis.ri = aml_dis.wi = aml_dis.total_num = 0;
967 aml_dis.started = true;
968
969 rc = pthread_create(&aml_dis.disp_t, NULL, display_thread_func, NULL);
970 if (rc) {
971 printf("create dispay thread fails\n");
972 return -1;
973 }
974 }
975
976 while (aml_dis.started) {
977 if (queue_frame(frame)) {
978 usleep(10);
979 continue;
980 } else
981 break;
982 }
983
984 return 0;
985}
986
987int display_engine_register_cb(displayed_cb_func cb)
988{
989 display_cb = cb;
990 return 0;
991}
992
993int display_wait_for_display()
994{
995 while (aml_dis.started && aml_dis.total_num) {
996 usleep(10);
997 }
998 if (!aml_dis.started)
999 return -1;
1000
1001 return 0;
1002}