feature_en: enumerate plane zpos for virtual planes as well
[glsdk/ti-cluster-linux-application.git] / drm_util.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <stdbool.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <sys/mman.h>
10 #include <sys/ioctl.h>
12 #include <xf86drm.h>
13 #include <xf86drmMode.h>
15 #include <drm_mode.h>
16 #include <drm_fourcc.h>
18 #include <list.h>
19 #include <biqueue.h>
20 #include <drm_util.h>
22 #define NUM_BUFFERS_PER_LAYER (6)
24 #if defined (CONFIG_DISPLAY_SPLIT)
25 extern bool plane_split;
26 #endif
28 static struct {
29         int fd;
30         int connector_id;
31         int crtc_id;
32         drmModeModeInfo mode;
33         uint32_t mode_blob;
35         struct {
36                 struct biqueue *bq;
37                 int plane_id;
38                 int width;
39                 int height;
40                 int zorder;
41                 bool opaque;
42                 int pos_x;
43                 int pos_y;
44         } layers[32];
45         int num_layers;
46 } drm;
48 int setup_drm(char *dev_fname)
49 {
50         int r;
52         drm.fd = open(dev_fname, O_RDWR);
53         if(drm.fd < 0) {
54                 printf("unable to open card %s\n", dev_fname);
55                 return -1;
56         }
58         r = drmSetMaster(drm.fd);
59         if(r) {
60                 printf("unable to set master\n");
61                 goto err1;
62         }
64         r = drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
65         if(r) {
66                 printf("unable to set universal planes\n");
67                 goto err1;
68         }
70         r = drmSetClientCap(drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
71         if(r) {
72                 printf("unable to set atomic\n");
73                 goto err1;
74         }
76         return 0;
78 err1:
79         close(drm.fd);
80         return -1;
81 }
83 static int get_zorder(int fd, uint32_t plane_id)
84 {
85         int i, r;
86         drmModeObjectPropertiesPtr props = NULL;
88         props = drmModeObjectGetProperties(fd, plane_id, DRM_MODE_OBJECT_PLANE);
89         if(!props) {
90                 printf("drmModeObjectGetProperties for plane %u failed\n", plane_id);
91                 return -1;
92         }
94         for(i = 0; i < props->count_props; i++) {
95                 drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[i]);
96                 if(!prop) {
97                         printf("getting prop = %u for plane %u failed\n", props->props[i], plane_id);
98                         drmModeFreeObjectProperties(props);
99                         return -1;
100                 }
101                 if(strcmp("zpos", prop->name) == 0) {
102                         r = props->prop_values[i];
103                         drmModeFreeProperty(prop);
104                         drmModeFreeObjectProperties(props);
105                         return r;
106                 }
107                 drmModeFreeProperty(prop);
109         }
110         printf("could not find property zpos for plane = %u\n", plane_id);
111         drmModeFreeObjectProperties(props);
113         return -1;
116 static int add_property(int fd, drmModeAtomicReqPtr req, uint32_t id, uint32_t type, char *prop_name, uint64_t value)
118         int i, r;
119         drmModeObjectPropertiesPtr props = NULL;
120         
121         props = drmModeObjectGetProperties(fd, id, type);
122         if(!props) {
123                 printf("drmModeObjectGetProperties for id = %u failed\n", id);
124                 return -1;
125         }
127         for(i = 0; i < props->count_props; i++) {
128                 drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[i]);
129                 if(!prop) {
130                         printf("getting prop = %u for id = %u failed\n", props->props[i], id);
131                         drmModeFreeObjectProperties(props);
132                         return -1;
133                 }
134                 if(strcmp(prop_name, prop->name) == 0) {
135                         r = drmModeAtomicAddProperty(req, id, props->props[i], value);
136                         if(r < 0) {
137                                 printf("set property %s for id = %u failed\n", prop_name, id);
138                         }
139                         drmModeFreeProperty(prop);
140                         drmModeFreeObjectProperties(props);
141                         return r < 0 ? -1 : 0;
142                 }
143                 drmModeFreeProperty(prop);
144         }
146         printf("could not find property %s for id = %u\n", prop_name, id);
147         drmModeFreeObjectProperties(props);
148         return -1;
151 static struct buffer *drm_new_buffer(uint32_t w, uint32_t h, uint32_t format)
153         struct drm_mode_destroy_dumb close_req;
154         struct drm_mode_create_dumb create_req;
155         struct drm_mode_map_dumb map_req;
156         struct buffer *buf;
157         void *vaddr;
158         uint32_t fb_id;
159         int r;
161         buf = calloc(sizeof(*buf), 1);
162         if(!buf) {
163                 printf("unable to calloc buffer\n");
164                 return NULL;
165         }
167         memset(&create_req, 0, sizeof(create_req));
168         create_req.width = w;
169         create_req.height =h;
170         create_req.bpp = 32;
171         r = ioctl(drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req);
172         if(r) {
173                 printf("unable to create dumb buffer\n");
174                 goto err1;
175         }
177         memset(&map_req, 0, sizeof(map_req));
178         map_req.handle = create_req.handle;
179         r = ioctl(drm.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req);
180         if(r) {
181                 printf("unable to get map info for dumb buffer\n");
182                 goto err2;
183         }
185         vaddr = mmap(0, create_req.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm.fd, map_req.offset);
186         if(vaddr == MAP_FAILED) {
187                 printf("unable to map dumb buffer\n");
188                 goto err2;
189         }
191         r = drmModeAddFB(drm.fd, w, h, format == DRM_FORMAT_XRGB8888 ? 24 : 32,
192                         32, create_req.pitch, create_req.handle, &fb_id);
193         if(r) {
194                 printf("unable to create FB\n");
195                 exit(-1);
196         }
198         buf->width = w;
199         buf->height = h;
200         buf->handle = create_req.handle;
201         buf->vaddr = vaddr;
202         buf->format = format;
203         buf->stride = create_req.pitch;
204         buf->fb_id = fb_id;
206         return buf;
208 err2:
209         memset(&close_req, 0, sizeof(close_req));
210         close_req.handle = create_req.handle;
211         ioctl(drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &close_req);
212 err1:
213         free(buf);
214         return NULL;
217 int drm_setup_display(int w, int h, int *rw, int *rh)
219         int i, j;
220         drmModeResPtr res;
221         drmModeConnectorPtr conn = NULL;
222         drmModeModeInfoPtr mode = NULL;
223         drmModeEncoderPtr enc = NULL;
224         drmModeCrtcPtr crtc = NULL;
226         res = drmModeGetResources(drm.fd);
227         if(!res)
228                 return -1;
230         for(i = 0; i < res->count_connectors; i++) {
231                 conn = drmModeGetConnector(drm.fd, res->connectors[i]);
232                 if(!conn)
233                         return -1;
235                 for(j = 0; j < conn->count_modes; j++)
236                         if(conn->modes[j].hdisplay == w && conn->modes[j].vdisplay == h) {
237                                 mode = &conn->modes[j];
238                                 break;
239                         }
241                 if(mode)
242                         break;
244                 drmModeFreeConnector(conn);
245                 conn = NULL;
246         }
248         if(!conn || !mode)
249                 return -1;
251         for(i = 0; i < conn->count_encoders; i++) {
252                 enc = drmModeGetEncoder(drm.fd, conn->encoders[i]);
253                 if(!enc)
254                         return -1;
256                 for(j = 0; j < res->count_crtcs; j++) {
257                         int crtc_id;
258                         uint32_t crtc_mask;
260                         crtc_id = res->crtcs[j];
261                         crtc_mask = 1 << j;
262                         if(enc->possible_crtcs & crtc_mask) {
263                                 crtc = drmModeGetCrtc(drm.fd, res->crtcs[j]);
264                                 if(!crtc)
265                                         return -1;
266                                 break;
267                         }
268                 }
270                 if(crtc)
271                         break;
272         }
275         if(!enc || !crtc)
276                 return -1;
279         drm.connector_id = conn->connector_id;
280         drm.crtc_id = crtc->crtc_id;
281         memcpy(&drm.mode, mode, sizeof(*mode));
282         drmModeCreatePropertyBlob(drm.fd, &drm.mode, sizeof(drmModeModeInfo), &drm.mode_blob);
284         drmModeFreeConnector(conn);
285         drmModeFreeEncoder(enc);
286         drmModeFreeCrtc(crtc);
287         drmModeFreeResources(res);
289         if(rw)
290                 *rw = drm.mode.hdisplay;
291         if(rh)
292                 *rh = drm.mode.vdisplay;
294         return 0;
297 int drm_reset()
299         int i, r;
300         drmModeResPtr res;
301         drmModePlaneResPtr pres;
302         drmModeAtomicReqPtr disable_req, enable_req;
304         res = drmModeGetResources(drm.fd);
305         pres = drmModeGetPlaneResources(drm.fd);
307         disable_req = drmModeAtomicAlloc();
308         enable_req = drmModeAtomicAlloc();
310         r = 0;
311         for(i = 0; i < res->count_crtcs; i++)
312                 r += add_property(drm.fd, disable_req, res->crtcs[i], DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
313         for(i = 0; i < pres->count_planes; i++) {
314                 r += add_property(drm.fd, disable_req, pres->planes[i], DRM_MODE_OBJECT_PLANE, "FB_ID", 0);
315                 r += add_property(drm.fd, disable_req, pres->planes[i], DRM_MODE_OBJECT_PLANE, "CRTC_ID", 0);
316         }
317         if(r)
318                 return -1;
320         r = drmModeAtomicCommit(drm.fd, disable_req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
321         if(r) {
322                 printf("disable atomic commit failed\n");
323                 return -1;
324         }
326         r = 0;
327         r += add_property(drm.fd, enable_req, drm.connector_id, DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", drm.crtc_id);
328         r += add_property(drm.fd, enable_req, drm.crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
329         r += add_property(drm.fd, enable_req, drm.crtc_id, DRM_MODE_OBJECT_CRTC, "MODE_ID", drm.mode_blob);
330         if(r)
331                 return -1;
333         r = drmModeAtomicCommit(drm.fd, enable_req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
334         if(r) {
335                 printf("enable atomic commit failed\n");
336                 exit(-1);
337         }
339         drmModeAtomicFree(disable_req);
340         drmModeAtomicFree(enable_req);
342         return 0;
345 static int drm_get_new_plane(int zorder)
347         int i, j;
348         drmModeResPtr res;
349         drmModePlaneResPtr pres;
350         uint32_t crtc_mask;
351         int plane_id;
352         drmModePlanePtr plane = NULL;
354         pres = drmModeGetPlaneResources(drm.fd);
355         res = drmModeGetResources(drm.fd);
356         if(!res || !pres)
357                 return -1;
359         for(i = 0; i < res->count_crtcs; i++)
360                 if(res->crtcs[i] == drm.crtc_id)
361                         crtc_mask = 1 << i;
363         for(i = 0; i < pres->count_planes; i++) {
364                 plane = drmModeGetPlane(drm.fd, pres->planes[i]);
365                 if(!plane)
366                         return -1;
368                 if((plane->possible_crtcs & crtc_mask) == 0) {
369                         drmModeFreePlane(plane);
370                         continue;
371                 }
373                 bool occupied = false;
374                 for(j = 0; j < drm.num_layers; j++)
375                         if(drm.layers[j].plane_id == plane->plane_id) {
376                                 occupied = true;
377                                 break;
378                         }
380                 if(occupied) 
381                         continue;
383                 if(get_zorder(drm.fd, plane->plane_id) == zorder)
384                         break;
385         }
387         if(!plane)
388                 return -1;
390         plane_id = plane->plane_id;
391         drmModeFreePlane(plane);
393         return plane_id;
396 int drm_add_layer(int w, int h, int pos_x, int pos_y, int zorder, bool opaque)
398         int i;
399         int count = drm.num_layers;
400         struct list_head buffers;
403         drm.layers[count].plane_id = drm_get_new_plane(zorder);
404         if(drm.layers[count].plane_id < 0) {
405                 printf("could not get a free plane\n");
406                 return -1;
407         }
409         INIT_LIST_HEAD(&buffers);
410         for(i = 0; i < NUM_BUFFERS_PER_LAYER; i++) {
411                 struct buffer *buf = drm_new_buffer(w, h, opaque ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_ARGB8888);
412                 list_add_tail(&buf->link, &buffers);
413         }
414         drm.layers[count].bq = bq_init(&buffers);
416         drm.layers[count].zorder = zorder;
417         drm.layers[count].width = w;
418         drm.layers[count].height = h;
419         drm.layers[count].pos_x = pos_x;
420         drm.layers[count].pos_y = pos_y;
421         drm.layers[count].opaque = opaque;
423         drm.num_layers++;
425         return count;
429 void drm_print_allocations()
431         int i;
433         printf("%s: using connector_id %d\n", __func__, drm.connector_id);
434         printf("%s: using crtc_id %d\n", __func__, drm.crtc_id);
435         printf("%s: using mode %s\n", __func__, drm.mode.name);
436         for(i = 0; i < drm.num_layers; i++)
437                 printf("%s: using plane_id %d for layer %d\n", __func__, drm.layers[i].plane_id, i);
440 struct biqueue *drm_get_bq(int index)
442         return drm.layers[index].bq;
445 void *drm_loop(void *arg)
447         int i, r;
448         int count;
449         drmModeAtomicReqPtr commit_req;
450         struct buffer *old_buffers[32] = {NULL};
451         struct buffer *mid_buffers[32] = {NULL};
452         struct buffer *new_buffers[32];
454         while(true) {
455                 commit_req = drmModeAtomicAlloc();
456                 count = drm.num_layers;
458                 r = 0;
459                 for(i = 0; i < count; i++) {
460                         struct buffer *buf = list_entry(bq_next_full(drm.layers[i].bq), struct buffer, link);
461                         new_buffers[i] = buf;
463                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "FB_ID", buf->fb_id);
464                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_ID", drm.crtc_id);
465                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_X", 0 << 16);
466                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_Y", 0 << 16);
467                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_W", buf->width << 16);
468                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_H", buf->height << 16);
469 #if defined (CONFIG_DISPLAY_SPLIT)
470                         if(plane_split == false) {
471                                 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_X", drm.layers[i].pos_x);
472                                 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_Y", drm.layers[i].pos_y);
473                         } else {
474                                 int x, y;
475                                 if(i == 0) {
476                                         x = drm.mode.hdisplay - buf->width;
477                                         y = drm.layers[i].pos_y;
478                                 } else if(i == 1) {
479                                         x = drm.layers[i].pos_x;
480                                         y = drm.mode.vdisplay - buf->height;
481                                 } else if(i == 2) {
482                                         x = drm.mode.hdisplay - buf->width;
483                                         y = drm.mode.vdisplay - buf->height;
484                                 } else {
485                                         x = drm.layers[i].pos_x;
486                                         y = drm.layers[i].pos_y;
487                                 }
488                                 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_X", x);
489                                 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_Y", y);
490                         }
491 #else
492                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_X", drm.layers[i].pos_x);
493                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_Y", drm.layers[i].pos_y);
494 #endif
495                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_W", drm.layers[i].width);
496                         r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_H", drm.layers[i].height);
497                 }
499                 if(r) {
500                         printf("add_property_failed\n");
501                         goto next_iter;
502                 }
504                 r = drmModeAtomicCommit(drm.fd, commit_req, 0, NULL);
505                 if(r) {
506                         printf("atomic commit failed\n");
507                 }
508 next_iter:
509                 drmModeAtomicFree(commit_req);
511                 for(i = 0; i < count; i++) {
512                         if(old_buffers[i])
513                                 bq_queue_empty(drm.layers[i].bq, &old_buffers[i]->link);
514                         old_buffers[i] = mid_buffers[i];
515                         mid_buffers[i] = new_buffers[i];
516                 }
517         }
520 void *drm_buffer_get_priv(struct buffer *b)
522         return b->priv_data;
525 void drm_buffer_set_priv(struct buffer *b, void *priv)
527         b->priv_data = priv;