st/egl: Rename kms backend to drm.
[mesa.git] / src / gallium / state_trackers / egl / drm / modeset.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include "util/u_memory.h"
30 #include "util/u_inlines.h"
31 #include "egllog.h"
32
33 #include "native_drm.h"
34
35 static boolean
36 kms_surface_validate(struct native_surface *nsurf, uint attachment_mask,
37 unsigned int *seq_num, struct pipe_resource **textures,
38 int *width, int *height)
39 {
40 struct kms_surface *ksurf = kms_surface(nsurf);
41
42 if (!resource_surface_add_resources(ksurf->rsurf, attachment_mask))
43 return FALSE;
44 if (textures)
45 resource_surface_get_resources(ksurf->rsurf, textures, attachment_mask);
46
47 if (seq_num)
48 *seq_num = ksurf->sequence_number;
49 if (width)
50 *width = ksurf->width;
51 if (height)
52 *height = ksurf->height;
53
54 return TRUE;
55 }
56
57 /**
58 * Add textures as DRM framebuffers.
59 */
60 static boolean
61 kms_surface_init_framebuffers(struct native_surface *nsurf, boolean need_back)
62 {
63 struct kms_surface *ksurf = kms_surface(nsurf);
64 struct kms_display *kdpy = ksurf->kdpy;
65 int num_framebuffers = (need_back) ? 2 : 1;
66 int i, err;
67
68 for (i = 0; i < num_framebuffers; i++) {
69 struct kms_framebuffer *fb;
70 enum native_attachment natt;
71 struct winsys_handle whandle;
72 uint block_bits;
73
74 if (i == 0) {
75 fb = &ksurf->front_fb;
76 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
77 }
78 else {
79 fb = &ksurf->back_fb;
80 natt = NATIVE_ATTACHMENT_BACK_LEFT;
81 }
82
83 if (!fb->texture) {
84 /* make sure the texture has been allocated */
85 resource_surface_add_resources(ksurf->rsurf, 1 << natt);
86 fb->texture =
87 resource_surface_get_single_resource(ksurf->rsurf, natt);
88 if (!fb->texture)
89 return FALSE;
90 }
91
92 /* already initialized */
93 if (fb->buffer_id)
94 continue;
95
96 /* TODO detect the real value */
97 fb->is_passive = TRUE;
98
99 memset(&whandle, 0, sizeof(whandle));
100 whandle.type = DRM_API_HANDLE_TYPE_KMS;
101
102 if (!kdpy->base.screen->resource_get_handle(kdpy->base.screen,
103 fb->texture, &whandle))
104 return FALSE;
105
106 block_bits = util_format_get_blocksizebits(ksurf->color_format);
107 err = drmModeAddFB(kdpy->fd, ksurf->width, ksurf->height,
108 block_bits, block_bits, whandle.stride, whandle.handle,
109 &fb->buffer_id);
110 if (err) {
111 fb->buffer_id = 0;
112 return FALSE;
113 }
114 }
115
116 return TRUE;
117 }
118
119 static boolean
120 kms_surface_flush_frontbuffer(struct native_surface *nsurf)
121 {
122 #ifdef DRM_MODE_FEATURE_DIRTYFB
123 struct kms_surface *ksurf = kms_surface(nsurf);
124 struct kms_display *kdpy = ksurf->kdpy;
125
126 if (ksurf->front_fb.is_passive)
127 drmModeDirtyFB(kdpy->fd, ksurf->front_fb.buffer_id, NULL, 0);
128 #endif
129
130 return TRUE;
131 }
132
133 static boolean
134 kms_surface_swap_buffers(struct native_surface *nsurf)
135 {
136 struct kms_surface *ksurf = kms_surface(nsurf);
137 struct kms_crtc *kcrtc = &ksurf->current_crtc;
138 struct kms_display *kdpy = ksurf->kdpy;
139 struct kms_framebuffer tmp_fb;
140 int err;
141
142 if (!ksurf->back_fb.buffer_id) {
143 if (!kms_surface_init_framebuffers(&ksurf->base, TRUE))
144 return FALSE;
145 }
146
147 if (ksurf->is_shown && kcrtc->crtc) {
148 err = drmModeSetCrtc(kdpy->fd, kcrtc->crtc->crtc_id,
149 ksurf->back_fb.buffer_id, kcrtc->crtc->x, kcrtc->crtc->y,
150 kcrtc->connectors, kcrtc->num_connectors, &kcrtc->crtc->mode);
151 if (err)
152 return FALSE;
153 }
154
155 /* swap the buffers */
156 tmp_fb = ksurf->front_fb;
157 ksurf->front_fb = ksurf->back_fb;
158 ksurf->back_fb = tmp_fb;
159
160 resource_surface_swap_buffers(ksurf->rsurf,
161 NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
162 /* the front/back textures are swapped */
163 ksurf->sequence_number++;
164 kdpy->event_handler->invalid_surface(&kdpy->base,
165 &ksurf->base, ksurf->sequence_number);
166
167 return TRUE;
168 }
169
170 static void
171 kms_surface_wait(struct native_surface *nsurf)
172 {
173 /* no-op */
174 }
175
176 static void
177 kms_surface_destroy(struct native_surface *nsurf)
178 {
179 struct kms_surface *ksurf = kms_surface(nsurf);
180
181 if (ksurf->current_crtc.crtc)
182 drmModeFreeCrtc(ksurf->current_crtc.crtc);
183
184 if (ksurf->front_fb.buffer_id)
185 drmModeRmFB(ksurf->kdpy->fd, ksurf->front_fb.buffer_id);
186 pipe_resource_reference(&ksurf->front_fb.texture, NULL);
187
188 if (ksurf->back_fb.buffer_id)
189 drmModeRmFB(ksurf->kdpy->fd, ksurf->back_fb.buffer_id);
190 pipe_resource_reference(&ksurf->back_fb.texture, NULL);
191
192 resource_surface_destroy(ksurf->rsurf);
193 FREE(ksurf);
194 }
195
196 static struct kms_surface *
197 kms_display_create_surface(struct native_display *ndpy,
198 const struct native_config *nconf,
199 uint width, uint height)
200 {
201 struct kms_display *kdpy = kms_display(ndpy);
202 struct kms_config *kconf = kms_config(nconf);
203 struct kms_surface *ksurf;
204
205 ksurf = CALLOC_STRUCT(kms_surface);
206 if (!ksurf)
207 return NULL;
208
209 ksurf->kdpy = kdpy;
210 ksurf->color_format = kconf->base.color_format;
211 ksurf->width = width;
212 ksurf->height = height;
213
214 ksurf->rsurf = resource_surface_create(kdpy->base.screen,
215 ksurf->color_format,
216 PIPE_BIND_RENDER_TARGET |
217 PIPE_BIND_SAMPLER_VIEW |
218 PIPE_BIND_DISPLAY_TARGET |
219 PIPE_BIND_SCANOUT);
220 if (!ksurf->rsurf) {
221 FREE(ksurf);
222 return NULL;
223 }
224
225 resource_surface_set_size(ksurf->rsurf, ksurf->width, ksurf->height);
226
227 ksurf->base.destroy = kms_surface_destroy;
228 ksurf->base.swap_buffers = kms_surface_swap_buffers;
229 ksurf->base.flush_frontbuffer = kms_surface_flush_frontbuffer;
230 ksurf->base.validate = kms_surface_validate;
231 ksurf->base.wait = kms_surface_wait;
232
233 return ksurf;
234 }
235
236 /**
237 * Choose a CRTC that supports all given connectors.
238 */
239 static uint32_t
240 kms_display_choose_crtc(struct native_display *ndpy,
241 uint32_t *connectors, int num_connectors)
242 {
243 struct kms_display *kdpy = kms_display(ndpy);
244 int idx;
245
246 for (idx = 0; idx < kdpy->resources->count_crtcs; idx++) {
247 boolean found_crtc = TRUE;
248 int i, j;
249
250 for (i = 0; i < num_connectors; i++) {
251 drmModeConnectorPtr connector;
252 int encoder_idx = -1;
253
254 connector = drmModeGetConnector(kdpy->fd, connectors[i]);
255 if (!connector) {
256 found_crtc = FALSE;
257 break;
258 }
259
260 /* find an encoder the CRTC supports */
261 for (j = 0; j < connector->count_encoders; j++) {
262 drmModeEncoderPtr encoder =
263 drmModeGetEncoder(kdpy->fd, connector->encoders[j]);
264 if (encoder->possible_crtcs & (1 << idx)) {
265 encoder_idx = j;
266 break;
267 }
268 drmModeFreeEncoder(encoder);
269 }
270
271 drmModeFreeConnector(connector);
272 if (encoder_idx < 0) {
273 found_crtc = FALSE;
274 break;
275 }
276 }
277
278 if (found_crtc)
279 break;
280 }
281
282 if (idx >= kdpy->resources->count_crtcs) {
283 _eglLog(_EGL_WARNING,
284 "failed to find a CRTC that supports the given %d connectors",
285 num_connectors);
286 return 0;
287 }
288
289 return kdpy->resources->crtcs[idx];
290 }
291
292 /**
293 * Remember the original CRTC status and set the CRTC
294 */
295 static boolean
296 kms_display_set_crtc(struct native_display *ndpy, int crtc_idx,
297 uint32_t buffer_id, uint32_t x, uint32_t y,
298 uint32_t *connectors, int num_connectors,
299 drmModeModeInfoPtr mode)
300 {
301 struct kms_display *kdpy = kms_display(ndpy);
302 struct kms_crtc *kcrtc = &kdpy->saved_crtcs[crtc_idx];
303 uint32_t crtc_id;
304 int err;
305
306 if (kcrtc->crtc) {
307 crtc_id = kcrtc->crtc->crtc_id;
308 }
309 else {
310 int count = 0, i;
311
312 /*
313 * Choose the CRTC once. It could be more dynamic, but let's keep it
314 * simple for now.
315 */
316 crtc_id = kms_display_choose_crtc(&kdpy->base,
317 connectors, num_connectors);
318
319 /* save the original CRTC status */
320 kcrtc->crtc = drmModeGetCrtc(kdpy->fd, crtc_id);
321 if (!kcrtc->crtc)
322 return FALSE;
323
324 for (i = 0; i < kdpy->num_connectors; i++) {
325 struct kms_connector *kconn = &kdpy->connectors[i];
326 drmModeConnectorPtr connector = kconn->connector;
327 drmModeEncoderPtr encoder;
328
329 encoder = drmModeGetEncoder(kdpy->fd, connector->encoder_id);
330 if (encoder) {
331 if (encoder->crtc_id == crtc_id) {
332 kcrtc->connectors[count++] = connector->connector_id;
333 if (count >= Elements(kcrtc->connectors))
334 break;
335 }
336 drmModeFreeEncoder(encoder);
337 }
338 }
339
340 kcrtc->num_connectors = count;
341 }
342
343 err = drmModeSetCrtc(kdpy->fd, crtc_id, buffer_id, x, y,
344 connectors, num_connectors, mode);
345 if (err) {
346 drmModeFreeCrtc(kcrtc->crtc);
347 kcrtc->crtc = NULL;
348 kcrtc->num_connectors = 0;
349
350 return FALSE;
351 }
352
353 return TRUE;
354 }
355
356 static boolean
357 kms_display_program(struct native_display *ndpy, int crtc_idx,
358 struct native_surface *nsurf, uint x, uint y,
359 const struct native_connector **nconns, int num_nconns,
360 const struct native_mode *nmode)
361 {
362 struct kms_display *kdpy = kms_display(ndpy);
363 struct kms_surface *ksurf = kms_surface(nsurf);
364 const struct kms_mode *kmode = kms_mode(nmode);
365 uint32_t connector_ids[32];
366 uint32_t buffer_id;
367 drmModeModeInfo mode_tmp, *mode;
368 int i;
369
370 if (num_nconns > Elements(connector_ids)) {
371 _eglLog(_EGL_WARNING, "too many connectors (%d)", num_nconns);
372 num_nconns = Elements(connector_ids);
373 }
374
375 if (ksurf) {
376 if (!kms_surface_init_framebuffers(&ksurf->base, FALSE))
377 return FALSE;
378
379 buffer_id = ksurf->front_fb.buffer_id;
380 /* the mode argument of drmModeSetCrtc is not constified */
381 mode_tmp = kmode->mode;
382 mode = &mode_tmp;
383 }
384 else {
385 /* disable the CRTC */
386 buffer_id = 0;
387 mode = NULL;
388 num_nconns = 0;
389 }
390
391 for (i = 0; i < num_nconns; i++) {
392 struct kms_connector *kconn = kms_connector(nconns[i]);
393 connector_ids[i] = kconn->connector->connector_id;
394 }
395
396 if (!kms_display_set_crtc(&kdpy->base, crtc_idx, buffer_id, x, y,
397 connector_ids, num_nconns, mode)) {
398 _eglLog(_EGL_WARNING, "failed to set CRTC %d", crtc_idx);
399
400 return FALSE;
401 }
402
403 if (kdpy->shown_surfaces[crtc_idx])
404 kdpy->shown_surfaces[crtc_idx]->is_shown = FALSE;
405 kdpy->shown_surfaces[crtc_idx] = ksurf;
406
407 /* remember the settings for buffer swapping */
408 if (ksurf) {
409 uint32_t crtc_id = kdpy->saved_crtcs[crtc_idx].crtc->crtc_id;
410 struct kms_crtc *kcrtc = &ksurf->current_crtc;
411
412 if (kcrtc->crtc)
413 drmModeFreeCrtc(kcrtc->crtc);
414 kcrtc->crtc = drmModeGetCrtc(kdpy->fd, crtc_id);
415
416 assert(num_nconns < Elements(kcrtc->connectors));
417 memcpy(kcrtc->connectors, connector_ids,
418 sizeof(*connector_ids) * num_nconns);
419 kcrtc->num_connectors = num_nconns;
420
421 ksurf->is_shown = TRUE;
422 }
423
424 return TRUE;
425 }
426
427 static const struct native_mode **
428 kms_display_get_modes(struct native_display *ndpy,
429 const struct native_connector *nconn,
430 int *num_modes)
431 {
432 struct kms_display *kdpy = kms_display(ndpy);
433 struct kms_connector *kconn = kms_connector(nconn);
434 const struct native_mode **nmodes_return;
435 int count, i;
436
437 /* delete old data */
438 if (kconn->connector) {
439 drmModeFreeConnector(kconn->connector);
440 FREE(kconn->kms_modes);
441
442 kconn->connector = NULL;
443 kconn->kms_modes = NULL;
444 kconn->num_modes = 0;
445 }
446
447 /* detect again */
448 kconn->connector = drmModeGetConnector(kdpy->fd, kconn->connector_id);
449 if (!kconn->connector)
450 return NULL;
451
452 count = kconn->connector->count_modes;
453 kconn->kms_modes = CALLOC(count, sizeof(*kconn->kms_modes));
454 if (!kconn->kms_modes) {
455 drmModeFreeConnector(kconn->connector);
456 kconn->connector = NULL;
457
458 return NULL;
459 }
460
461 for (i = 0; i < count; i++) {
462 struct kms_mode *kmode = &kconn->kms_modes[i];
463 drmModeModeInfoPtr mode = &kconn->connector->modes[i];
464
465 kmode->mode = *mode;
466
467 kmode->base.desc = kmode->mode.name;
468 kmode->base.width = kmode->mode.hdisplay;
469 kmode->base.height = kmode->mode.vdisplay;
470 kmode->base.refresh_rate = kmode->mode.vrefresh;
471 /* not all kernels have vrefresh = refresh_rate * 1000 */
472 if (kmode->base.refresh_rate > 1000)
473 kmode->base.refresh_rate = (kmode->base.refresh_rate + 500) / 1000;
474 }
475
476 nmodes_return = MALLOC(count * sizeof(*nmodes_return));
477 if (nmodes_return) {
478 for (i = 0; i < count; i++)
479 nmodes_return[i] = &kconn->kms_modes[i].base;
480 if (num_modes)
481 *num_modes = count;
482 }
483
484 return nmodes_return;
485 }
486
487 static const struct native_connector **
488 kms_display_get_connectors(struct native_display *ndpy, int *num_connectors,
489 int *num_crtc)
490 {
491 struct kms_display *kdpy = kms_display(ndpy);
492 const struct native_connector **connectors;
493 int i;
494
495 if (!kdpy->connectors) {
496 kdpy->connectors =
497 CALLOC(kdpy->resources->count_connectors, sizeof(*kdpy->connectors));
498 if (!kdpy->connectors)
499 return NULL;
500
501 for (i = 0; i < kdpy->resources->count_connectors; i++) {
502 struct kms_connector *kconn = &kdpy->connectors[i];
503
504 kconn->connector_id = kdpy->resources->connectors[i];
505 /* kconn->connector is allocated when the modes are asked */
506 }
507
508 kdpy->num_connectors = kdpy->resources->count_connectors;
509 }
510
511 connectors = MALLOC(kdpy->num_connectors * sizeof(*connectors));
512 if (connectors) {
513 for (i = 0; i < kdpy->num_connectors; i++)
514 connectors[i] = &kdpy->connectors[i].base;
515 if (num_connectors)
516 *num_connectors = kdpy->num_connectors;
517 }
518
519 if (num_crtc)
520 *num_crtc = kdpy->resources->count_crtcs;
521
522 return connectors;
523 }
524
525 static struct native_surface *
526 kms_display_create_scanout_surface(struct native_display *ndpy,
527 const struct native_config *nconf,
528 uint width, uint height)
529 {
530 struct kms_surface *ksurf;
531
532 ksurf = kms_display_create_surface(ndpy, nconf, width, height);
533 return &ksurf->base;
534 }
535
536 static struct native_display_modeset kms_display_modeset = {
537 .get_connectors = kms_display_get_connectors,
538 .get_modes = kms_display_get_modes,
539 .create_scanout_surface = kms_display_create_scanout_surface,
540 .program = kms_display_program
541 };
542
543 void
544 kms_display_fini_modeset(struct native_display *ndpy)
545 {
546 struct kms_display *kdpy = kms_display(ndpy);
547 int i;
548
549 if (kdpy->connectors) {
550 for (i = 0; i < kdpy->num_connectors; i++) {
551 struct kms_connector *kconn = &kdpy->connectors[i];
552 if (kconn->connector) {
553 drmModeFreeConnector(kconn->connector);
554 FREE(kconn->kms_modes);
555 }
556 }
557 FREE(kdpy->connectors);
558 }
559
560 if (kdpy->shown_surfaces) {
561 FREE(kdpy->shown_surfaces);
562 kdpy->shown_surfaces = NULL;
563 }
564
565 if (kdpy->saved_crtcs) {
566 for (i = 0; i < kdpy->resources->count_crtcs; i++) {
567 struct kms_crtc *kcrtc = &kdpy->saved_crtcs[i];
568
569 if (kcrtc->crtc) {
570 /* restore crtc */
571 drmModeSetCrtc(kdpy->fd, kcrtc->crtc->crtc_id,
572 kcrtc->crtc->buffer_id, kcrtc->crtc->x, kcrtc->crtc->y,
573 kcrtc->connectors, kcrtc->num_connectors,
574 &kcrtc->crtc->mode);
575
576 drmModeFreeCrtc(kcrtc->crtc);
577 }
578 }
579 FREE(kdpy->saved_crtcs);
580 }
581
582 if (kdpy->resources) {
583 drmModeFreeResources(kdpy->resources);
584 kdpy->resources = NULL;
585 }
586
587 kdpy->base.modeset = NULL;
588 }
589
590 boolean
591 kms_display_init_modeset(struct native_display *ndpy)
592 {
593 struct kms_display *kdpy = kms_display(ndpy);
594
595 /* resources are fixed, unlike crtc, connector, or encoder */
596 kdpy->resources = drmModeGetResources(kdpy->fd);
597 if (!kdpy->resources) {
598 _eglLog(_EGL_DEBUG, "Failed to get KMS resources. Disable modeset.");
599 return FALSE;
600 }
601
602 kdpy->saved_crtcs =
603 CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs));
604 if (!kdpy->saved_crtcs) {
605 kms_display_fini_modeset(&kdpy->base);
606 return FALSE;
607 }
608
609 kdpy->shown_surfaces =
610 CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces));
611 if (!kdpy->shown_surfaces) {
612 kms_display_fini_modeset(&kdpy->base);
613 return FALSE;
614 }
615
616 kdpy->base.modeset = &kms_display_modeset;
617
618 return TRUE;
619 }