1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <getopt.h>
7
8 #include <drm.h>
9 #include <drm_fourcc.h>
10 #include <errno.h>
11 #include <xf86drm.h>
12 #include <xf86drmMode.h>
13
14 #include "bo.h"
15 #include "dev.h"
16 #include "modeset.h"
17
show_usage(char * name)18 static void show_usage(char *name)
19 {
20 printf("Usage: %s [OPTION]\n", name);
21 printf(" -c, --card Index of dri card (ie: /dev/dri/cardN)\n");
22 printf(" -r, --crtc Index of crtc to use for test\n");
23 printf("\n\n");
24 }
25
parse_arguments(int argc,char * argv[],int * card,int * crtc)26 void parse_arguments(int argc, char *argv[], int *card, int *crtc)
27 {
28 static struct option options[] = {
29 { "card", required_argument, NULL, 'c' },
30 { "crtc", required_argument, NULL, 'r' },
31 { "help", no_argument, NULL, 'h' },
32 };
33 int option_index = 0;
34 int c;
35
36 *card = -1;
37 *crtc = -1;
38 do {
39 c = getopt_long(argc, argv, "c:r:h", options, &option_index);
40 switch (c) {
41 case 0:
42 case 'h':
43 show_usage(argv[0]);
44 exit(0);
45 case -1:
46 break;
47 case 'c':
48 if (optarg[0] < '0' || optarg[0] > '9') {
49 printf("Invalid card value '%s'!\n", optarg);
50 show_usage(argv[0]);
51 exit(-1);
52 }
53 *card = optarg[0] - '0';
54 break;
55 case 'r':
56 if (optarg[0] < '0' || optarg[0] > '9') {
57 printf("Invalid crtc value '%s'!\n", optarg);
58 show_usage(argv[0]);
59 exit(-1);
60 }
61 *crtc = optarg[0] - '0';
62 break;
63 }
64 } while (c != -1);
65
66 if (*card < 0 || *crtc < 0) {
67 show_usage(argv[0]);
68 exit(-1);
69 }
70 }
71
get_prop_id(struct sp_dev * dev,drmModeObjectPropertiesPtr props,const char * name)72 static uint32_t get_prop_id(struct sp_dev *dev,
73 drmModeObjectPropertiesPtr props, const char *name)
74 {
75 drmModePropertyPtr p;
76 uint32_t i, prop_id = 0; /* Property ID should always be > 0 */
77
78 for (i = 0; !prop_id && i < props->count_props; i++) {
79 p = drmModeGetProperty(dev->fd, props->props[i]);
80 if (!strcmp(p->name, name))
81 prop_id = p->prop_id;
82 drmModeFreeProperty(p);
83 }
84 if (!prop_id)
85 printf("Could not find %s property\n", name);
86 return prop_id;
87 }
88
get_supported_format(struct sp_plane * plane,uint32_t * format)89 static int get_supported_format(struct sp_plane *plane, uint32_t *format)
90 {
91 uint32_t i;
92
93 for (i = 0; i < plane->plane->count_formats; i++) {
94 if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 ||
95 plane->plane->formats[i] == DRM_FORMAT_ARGB8888 ||
96 plane->plane->formats[i] == DRM_FORMAT_RGBA8888 ||
97 plane->plane->formats[i] == DRM_FORMAT_NV12) {
98 *format = plane->plane->formats[i];
99 return 0;
100 }
101 }
102 printf("No suitable formats found!\n");
103 return -ENOENT;
104 }
105
create_sp_dev(int card)106 struct sp_dev *create_sp_dev(int card)
107 {
108 struct sp_dev *dev;
109 int ret, fd, i, j;
110 drmModeRes *r = NULL;
111 drmModePlaneRes *pr = NULL;
112 char card_path[256];
113
114 snprintf(card_path, sizeof(card_path), "/dev/dri/card%d", card);
115
116 fd = open(card_path, O_RDWR);
117 if (fd < 0) {
118 printf("failed to open card0\n");
119 return NULL;
120 }
121
122 dev = calloc(1, sizeof(*dev));
123 if (!dev) {
124 printf("failed to allocate dev\n");
125 return NULL;
126 }
127
128 dev->fd = fd;
129
130 ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
131 if (ret) {
132 printf("failed to set client cap\n");
133 goto err;
134 }
135
136 ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
137 if (ret) {
138 printf("Failed to set atomic cap %d", ret);
139 goto err;
140 }
141
142 r = drmModeGetResources(dev->fd);
143 if (!r) {
144 printf("failed to get r\n");
145 goto err;
146 }
147
148 dev->num_connectors = r->count_connectors;
149 dev->connectors = calloc(dev->num_connectors,
150 sizeof(struct sp_connector));
151 if (!dev->connectors) {
152 printf("failed to allocate connectors\n");
153 goto err;
154 }
155 for (i = 0; i < dev->num_connectors; i++) {
156 drmModeObjectPropertiesPtr props;
157 dev->connectors[i].conn = drmModeGetConnector(dev->fd,
158 r->connectors[i]);
159 if (!dev->connectors[i].conn) {
160 printf("failed to get connector %d\n", i);
161 goto err;
162 }
163
164 props = drmModeObjectGetProperties(dev->fd, r->connectors[i],
165 DRM_MODE_OBJECT_CONNECTOR);
166 if (!props) {
167 printf("failed to get connector properties\n");
168 goto err;
169 }
170
171 dev->connectors[i].crtc_id_pid = get_prop_id(dev, props,
172 "CRTC_ID");
173 drmModeFreeObjectProperties(props);
174 if (!dev->connectors[i].crtc_id_pid)
175 goto err;
176 }
177
178 dev->num_encoders = r->count_encoders;
179 dev->encoders = calloc(dev->num_encoders, sizeof(*dev->encoders));
180 if (!dev->encoders) {
181 printf("failed to allocate encoders\n");
182 goto err;
183 }
184 for (i = 0; i < dev->num_encoders; i++) {
185 dev->encoders[i] = drmModeGetEncoder(dev->fd, r->encoders[i]);
186 if (!dev->encoders[i]) {
187 printf("failed to get encoder %d\n", i);
188 goto err;
189 }
190 }
191
192 dev->num_crtcs = r->count_crtcs;
193 dev->crtcs = calloc(dev->num_crtcs, sizeof(struct sp_crtc));
194 if (!dev->crtcs) {
195 printf("failed to allocate crtcs\n");
196 goto err;
197 }
198 for (i = 0; i < dev->num_crtcs; i++) {
199 drmModeObjectPropertiesPtr props;
200
201 dev->crtcs[i].crtc = drmModeGetCrtc(dev->fd, r->crtcs[i]);
202 if (!dev->crtcs[i].crtc) {
203 printf("failed to get crtc %d\n", i);
204 goto err;
205 }
206 dev->crtcs[i].pipe = i;
207 dev->crtcs[i].num_planes = 0;
208
209 props = drmModeObjectGetProperties(dev->fd, r->crtcs[i],
210 DRM_MODE_OBJECT_CRTC);
211 if (!props) {
212 printf("failed to get crtc properties\n");
213 goto err;
214 }
215
216 dev->crtcs[i].mode_pid = get_prop_id(dev, props, "MODE_ID");
217 dev->crtcs[i].active_pid = get_prop_id(dev, props, "ACTIVE");
218 drmModeFreeObjectProperties(props);
219 if (!dev->crtcs[i].mode_pid || !dev->crtcs[i].active_pid)
220 goto err;
221 }
222
223 pr = drmModeGetPlaneResources(dev->fd);
224 if (!pr) {
225 printf("failed to get plane resources\n");
226 goto err;
227 }
228 dev->num_planes = pr->count_planes;
229 dev->planes = calloc(dev->num_planes, sizeof(struct sp_plane));
230 for(i = 0; i < dev->num_planes; i++) {
231 drmModeObjectPropertiesPtr props;
232 struct sp_plane *plane = &dev->planes[i];
233
234 plane->dev = dev;
235 plane->plane = drmModeGetPlane(dev->fd, pr->planes[i]);
236 if (!plane->plane) {
237 printf("failed to get plane %d\n", i);
238 goto err;
239 }
240 plane->bo = NULL;
241 plane->in_use = 0;
242
243 ret = get_supported_format(plane, &plane->format);
244 if (ret) {
245 printf("failed to get supported format: %d\n", ret);
246 goto err;
247 }
248
249 for (j = 0; j < dev->num_crtcs; j++) {
250 if (plane->plane->possible_crtcs & (1 << j))
251 dev->crtcs[j].num_planes++;
252 }
253
254 props = drmModeObjectGetProperties(dev->fd, pr->planes[i],
255 DRM_MODE_OBJECT_PLANE);
256 if (!props) {
257 printf("failed to get plane properties\n");
258 goto err;
259 }
260 plane->crtc_pid = get_prop_id(dev, props, "CRTC_ID");
261 if (!plane->crtc_pid) {
262 drmModeFreeObjectProperties(props);
263 goto err;
264 }
265 plane->fb_pid = get_prop_id(dev, props, "FB_ID");
266 if (!plane->fb_pid) {
267 drmModeFreeObjectProperties(props);
268 goto err;
269 }
270 plane->crtc_x_pid = get_prop_id(dev, props, "CRTC_X");
271 if (!plane->crtc_x_pid) {
272 drmModeFreeObjectProperties(props);
273 goto err;
274 }
275 plane->crtc_y_pid = get_prop_id(dev, props, "CRTC_Y");
276 if (!plane->crtc_y_pid) {
277 drmModeFreeObjectProperties(props);
278 goto err;
279 }
280 plane->crtc_w_pid = get_prop_id(dev, props, "CRTC_W");
281 if (!plane->crtc_w_pid) {
282 drmModeFreeObjectProperties(props);
283 goto err;
284 }
285 plane->crtc_h_pid = get_prop_id(dev, props, "CRTC_H");
286 if (!plane->crtc_h_pid) {
287 drmModeFreeObjectProperties(props);
288 goto err;
289 }
290 plane->src_x_pid = get_prop_id(dev, props, "SRC_X");
291 if (!plane->src_x_pid) {
292 drmModeFreeObjectProperties(props);
293 goto err;
294 }
295 plane->src_y_pid = get_prop_id(dev, props, "SRC_Y");
296 if (!plane->src_y_pid) {
297 drmModeFreeObjectProperties(props);
298 goto err;
299 }
300 plane->src_w_pid = get_prop_id(dev, props, "SRC_W");
301 if (!plane->src_w_pid) {
302 drmModeFreeObjectProperties(props);
303 goto err;
304 }
305 plane->src_h_pid = get_prop_id(dev, props, "SRC_H");
306 if (!plane->src_h_pid) {
307 drmModeFreeObjectProperties(props);
308 goto err;
309 }
310 drmModeFreeObjectProperties(props);
311 }
312
313 if (pr)
314 drmModeFreePlaneResources(pr);
315 if (r)
316 drmModeFreeResources(r);
317
318 return dev;
319 err:
320 if (pr)
321 drmModeFreePlaneResources(pr);
322 if (r)
323 drmModeFreeResources(r);
324 destroy_sp_dev(dev);
325 return NULL;
326 }
327
destroy_sp_dev(struct sp_dev * dev)328 void destroy_sp_dev(struct sp_dev *dev)
329 {
330 int i;
331
332 if (dev->planes) {
333 for (i = 0; i< dev->num_planes; i++) {
334 if (dev->planes[i].in_use)
335 put_sp_plane(&dev->planes[i]);
336 if (dev->planes[i].plane)
337 drmModeFreePlane(dev->planes[i].plane);
338 if (dev->planes[i].bo)
339 free_sp_bo(dev->planes[i].bo);
340 }
341 free(dev->planes);
342 }
343 if (dev->crtcs) {
344 for (i = 0; i< dev->num_crtcs; i++) {
345 if (dev->crtcs[i].crtc)
346 drmModeFreeCrtc(dev->crtcs[i].crtc);
347 }
348 free(dev->crtcs);
349 }
350 if (dev->encoders) {
351 for (i = 0; i< dev->num_encoders; i++) {
352 if (dev->encoders[i])
353 drmModeFreeEncoder(dev->encoders[i]);
354 }
355 free(dev->encoders);
356 }
357 if (dev->connectors) {
358 for (i = 0; i< dev->num_connectors; i++) {
359 if (dev->connectors[i].conn)
360 drmModeFreeConnector(dev->connectors[i].conn);
361 }
362 free(dev->connectors);
363 }
364
365 close(dev->fd);
366 free(dev);
367 }
368