3fdf60cb3ea61b4e41166d89bf5c2423e5724812
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 card1\n");
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 add_property(int fd, drmModeAtomicReqPtr req, uint32_t id, uint32_t type, char *prop_name, uint64_t value)
84 {
85 int i, r;
86 drmModeObjectPropertiesPtr props = NULL;
88 props = drmModeObjectGetProperties(fd, id, type);
89 if(!props) {
90 printf("drmModeObjectGetProperties for id = %u failed\n", 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 id = %u failed\n", props->props[i], id);
98 drmModeFreeObjectProperties(props);
99 return -1;
100 }
101 if(strcmp(prop_name, prop->name) == 0) {
102 r = drmModeAtomicAddProperty(req, id, props->props[i], value);
103 if(r < 0) {
104 printf("set property %s for id = %u failed\n", prop_name, id);
105 }
106 drmModeFreeProperty(prop);
107 drmModeFreeObjectProperties(props);
108 return r < 0 ? -1 : 0;
109 }
110 drmModeFreeProperty(prop);
111 }
113 printf("could not find property %s for id = %u\n", prop_name, id);
114 drmModeFreeObjectProperties(props);
115 return -1;
116 }
118 static struct buffer *drm_new_buffer(uint32_t w, uint32_t h, uint32_t format)
119 {
120 struct drm_mode_destroy_dumb close_req;
121 struct drm_mode_create_dumb create_req;
122 struct drm_mode_map_dumb map_req;
123 struct buffer *buf;
124 void *vaddr;
125 uint32_t fb_id;
126 int r;
128 buf = calloc(sizeof(*buf), 1);
129 if(!buf) {
130 printf("unable to calloc buffer\n");
131 return NULL;
132 }
134 memset(&create_req, 0, sizeof(create_req));
135 create_req.width = w;
136 create_req.height =h;
137 create_req.bpp = 32;
138 r = ioctl(drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req);
139 if(r) {
140 printf("unable to create dumb buffer\n");
141 goto err1;
142 }
144 memset(&map_req, 0, sizeof(map_req));
145 map_req.handle = create_req.handle;
146 r = ioctl(drm.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req);
147 if(r) {
148 printf("unable to get map info for dumb buffer\n");
149 goto err2;
150 }
152 vaddr = mmap(0, create_req.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm.fd, map_req.offset);
153 if(vaddr == MAP_FAILED) {
154 printf("unable to map dumb buffer\n");
155 goto err2;
156 }
158 r = drmModeAddFB(drm.fd, w, h, format == DRM_FORMAT_XRGB8888 ? 24 : 32,
159 32, create_req.pitch, create_req.handle, &fb_id);
160 if(r) {
161 printf("unable to create FB\n");
162 exit(-1);
163 }
165 buf->width = w;
166 buf->height = h;
167 buf->handle = create_req.handle;
168 buf->vaddr = vaddr;
169 buf->format = format;
170 buf->stride = create_req.pitch;
171 buf->fb_id = fb_id;
173 return buf;
175 err2:
176 memset(&close_req, 0, sizeof(close_req));
177 close_req.handle = create_req.handle;
178 ioctl(drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &close_req);
179 err1:
180 free(buf);
181 return NULL;
182 }
184 int drm_setup_display(int w, int h, int *rw, int *rh)
185 {
186 int i, j;
187 drmModeResPtr res;
188 drmModeConnectorPtr conn = NULL;
189 drmModeModeInfoPtr mode = NULL;
190 drmModeEncoderPtr enc = NULL;
191 drmModeCrtcPtr crtc = NULL;
193 res = drmModeGetResources(drm.fd);
194 if(!res)
195 return -1;
197 for(i = 0; i < res->count_connectors; i++) {
198 conn = drmModeGetConnector(drm.fd, res->connectors[i]);
199 if(!conn)
200 return -1;
202 for(j = 0; j < conn->count_modes; j++)
203 if(conn->modes[j].hdisplay == w && conn->modes[j].vdisplay == h) {
204 mode = &conn->modes[j];
205 break;
206 }
208 if(mode)
209 break;
211 drmModeFreeConnector(conn);
212 conn = NULL;
213 }
215 if(!conn || !mode)
216 return -1;
218 for(i = 0; i < conn->count_encoders; i++) {
219 enc = drmModeGetEncoder(drm.fd, conn->encoders[i]);
220 if(!enc)
221 return -1;
223 for(j = 0; j < res->count_crtcs; j++) {
224 int crtc_id;
225 uint32_t crtc_mask;
227 crtc_id = res->crtcs[j];
228 crtc_mask = 1 << j;
229 if(enc->possible_crtcs & crtc_mask) {
230 crtc = drmModeGetCrtc(drm.fd, res->crtcs[j]);
231 if(!crtc)
232 return -1;
233 break;
234 }
235 }
237 if(crtc)
238 break;
239 }
242 if(!enc || !crtc)
243 return -1;
246 drm.connector_id = conn->connector_id;
247 drm.crtc_id = crtc->crtc_id;
248 memcpy(&drm.mode, mode, sizeof(*mode));
249 drmModeCreatePropertyBlob(drm.fd, &drm.mode, sizeof(drmModeModeInfo), &drm.mode_blob);
251 drmModeFreeConnector(conn);
252 drmModeFreeEncoder(enc);
253 drmModeFreeCrtc(crtc);
254 drmModeFreeResources(res);
256 if(rw)
257 *rw = drm.mode.hdisplay;
258 if(rh)
259 *rh = drm.mode.vdisplay;
261 return 0;
262 }
264 int drm_reset()
265 {
266 int i, r;
267 drmModeResPtr res;
268 drmModePlaneResPtr pres;
269 drmModeAtomicReqPtr disable_req, enable_req;
271 res = drmModeGetResources(drm.fd);
272 pres = drmModeGetPlaneResources(drm.fd);
274 disable_req = drmModeAtomicAlloc();
275 enable_req = drmModeAtomicAlloc();
277 r = 0;
278 for(i = 0; i < res->count_crtcs; i++)
279 r += add_property(drm.fd, disable_req, res->crtcs[i], DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
280 for(i = 0; i < pres->count_planes; i++) {
281 r += add_property(drm.fd, disable_req, pres->planes[i], DRM_MODE_OBJECT_PLANE, "FB_ID", 0);
282 r += add_property(drm.fd, disable_req, pres->planes[i], DRM_MODE_OBJECT_PLANE, "CRTC_ID", 0);
283 }
284 if(r)
285 return -1;
287 r = drmModeAtomicCommit(drm.fd, disable_req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
288 if(r) {
289 printf("disable atomic commit failed\n");
290 return -1;
291 }
293 r = 0;
294 r += add_property(drm.fd, enable_req, drm.connector_id, DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", drm.crtc_id);
295 r += add_property(drm.fd, enable_req, drm.crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
296 r += add_property(drm.fd, enable_req, drm.crtc_id, DRM_MODE_OBJECT_CRTC, "MODE_ID", drm.mode_blob);
297 if(r)
298 return -1;
300 r = drmModeAtomicCommit(drm.fd, enable_req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
301 if(r) {
302 printf("enable atomic commit failed\n");
303 exit(-1);
304 }
306 drmModeAtomicFree(disable_req);
307 drmModeAtomicFree(enable_req);
309 return 0;
310 }
312 static int drm_get_new_plane(int zorder)
313 {
314 int i, j;
315 drmModeResPtr res;
316 drmModePlaneResPtr pres;
317 uint32_t crtc_mask;
318 int plane_id;
319 drmModePlanePtr plane = NULL;
321 pres = drmModeGetPlaneResources(drm.fd);
322 res = drmModeGetResources(drm.fd);
323 if(!res || !pres)
324 return -1;
326 for(i = 0; i < res->count_crtcs; i++)
327 if(res->crtcs[i] == drm.crtc_id)
328 crtc_mask = 1 << i;
330 for(i = 0; i < pres->count_planes; i++) {
331 plane = drmModeGetPlane(drm.fd, pres->planes[i]);
332 if(!plane)
333 return -1;
335 if((plane->possible_crtcs & crtc_mask) == 0) {
336 drmModeFreePlane(plane);
337 continue;
338 }
340 bool occupied = false;
341 for(j = 0; j < drm.num_layers; j++)
342 if(drm.layers[j].plane_id == plane->plane_id) {
343 occupied = true;
344 break;
345 }
347 if(occupied)
348 continue;
350 if(true /*zorder check here!!! but broken right now*/ )
351 break;
352 }
354 if(!plane)
355 return -1;
357 plane_id = plane->plane_id;
358 drmModeFreePlane(plane);
360 return plane_id;
361 }
363 int drm_add_layer(int w, int h, int pos_x, int pos_y, int zorder, bool opaque)
364 {
365 int i;
366 int count = drm.num_layers;
367 struct list_head buffers;
370 drm.layers[count].plane_id = drm_get_new_plane(zorder);
371 if(drm.layers[count].plane_id < 0) {
372 printf("could not get a free plane\n");
373 return -1;
374 }
376 INIT_LIST_HEAD(&buffers);
377 for(i = 0; i < NUM_BUFFERS_PER_LAYER; i++) {
378 struct buffer *buf = drm_new_buffer(w, h, opaque ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_ARGB8888);
379 list_add_tail(&buf->link, &buffers);
380 }
381 drm.layers[count].bq = bq_init(&buffers);
383 drm.layers[count].zorder = zorder;
384 drm.layers[count].width = w;
385 drm.layers[count].height = h;
386 drm.layers[count].pos_x = pos_x;
387 drm.layers[count].pos_y = pos_y;
388 drm.layers[count].opaque = opaque;
390 drm.num_layers++;
392 return count;
394 }
396 void drm_print_allocations()
397 {
398 int i;
400 printf("%s: using connector_id %d\n", __func__, drm.connector_id);
401 printf("%s: using crtc_id %d\n", __func__, drm.crtc_id);
402 printf("%s: using mode %s\n", __func__, drm.mode.name);
403 for(i = 0; i < drm.num_layers; i++)
404 printf("%s: using plane_id %d for layer %d\n", __func__, drm.layers[i].plane_id, i);
405 }
407 struct biqueue *drm_get_bq(int index)
408 {
409 return drm.layers[index].bq;
410 }
412 void *drm_loop(void *arg)
413 {
414 int i, r;
415 int count;
416 drmModeAtomicReqPtr commit_req;
417 struct buffer *old_buffers[32] = {NULL};
418 struct buffer *new_buffers[32];
420 while(true) {
421 commit_req = drmModeAtomicAlloc();
422 count = drm.num_layers;
424 r = 0;
425 for(i = 0; i < count; i++) {
426 struct buffer *buf = list_entry(bq_next_full(drm.layers[i].bq), struct buffer, link);
427 new_buffers[i] = buf;
429 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "FB_ID", buf->fb_id);
430 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_ID", drm.crtc_id);
431 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_X", 0 << 16);
432 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_Y", 0 << 16);
433 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_W", buf->width << 16);
434 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "SRC_H", buf->height << 16);
435 #if defined (CONFIG_DISPLAY_SPLIT)
436 if(plane_split == false) {
437 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_X", drm.layers[i].pos_x);
438 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_Y", drm.layers[i].pos_y);
439 } else {
440 int x, y;
441 if(i == 0) {
442 x = drm.mode.hdisplay - buf->width;
443 y = drm.layers[i].pos_y;
444 } else if(i == 1) {
445 x = drm.layers[i].pos_x;
446 y = drm.mode.vdisplay - buf->height;
447 } else if(i == 2) {
448 x = drm.mode.hdisplay - buf->width;
449 y = drm.mode.vdisplay - buf->height;
450 } else {
451 x = drm.layers[i].pos_x;
452 y = drm.layers[i].pos_y;
453 }
454 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_X", x);
455 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_Y", y);
456 }
457 #else
458 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_X", drm.layers[i].pos_x);
459 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_Y", drm.layers[i].pos_y);
460 #endif
461 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_W", drm.layers[i].width);
462 r += add_property(drm.fd, commit_req, drm.layers[i].plane_id, DRM_MODE_OBJECT_PLANE, "CRTC_H", drm.layers[i].height);
463 }
465 if(r) {
466 printf("add_property_failed\n");
467 goto next_iter;
468 }
470 r = drmModeAtomicCommit(drm.fd, commit_req, 0, NULL);
471 if(r) {
472 printf("atomic commit failed\n");
473 }
474 next_iter:
475 drmModeAtomicFree(commit_req);
477 for(i = 0; i < count; i++) {
478 if(old_buffers[i])
479 bq_queue_empty(drm.layers[i].bq, &old_buffers[i]->link);
480 old_buffers[i] = new_buffers[i];
481 }
482 }
483 }
485 void *drm_buffer_get_priv(struct buffer *b)
486 {
487 return b->priv_data;
488 }
490 void drm_buffer_set_priv(struct buffer *b, void *priv)
491 {
492 b->priv_data = priv;
493 }