2 * Mesa 3-D graphics library
5 * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 #include "pipe/p_screen.h"
27 #include "pipe/p_context.h"
28 #include "util/u_debug.h"
29 #include "util/u_memory.h"
30 #include "util/u_inlines.h"
31 #include "util/u_pointer.h"
32 #include "util/u_string.h"
35 #include "native_kms.h"
36 #include "state_tracker/drm_driver.h"
39 kms_surface_validate(struct native_surface
*nsurf
, uint attachment_mask
,
40 unsigned int *seq_num
, struct pipe_resource
**textures
,
41 int *width
, int *height
)
43 struct kms_surface
*ksurf
= kms_surface(nsurf
);
45 if (!resource_surface_add_resources(ksurf
->rsurf
, attachment_mask
))
48 resource_surface_get_resources(ksurf
->rsurf
, textures
, attachment_mask
);
51 *seq_num
= ksurf
->sequence_number
;
53 *width
= ksurf
->width
;
55 *height
= ksurf
->height
;
61 * Add textures as DRM framebuffers.
64 kms_surface_init_framebuffers(struct native_surface
*nsurf
, boolean need_back
)
66 struct kms_surface
*ksurf
= kms_surface(nsurf
);
67 struct kms_display
*kdpy
= ksurf
->kdpy
;
68 int num_framebuffers
= (need_back
) ? 2 : 1;
71 for (i
= 0; i
< num_framebuffers
; i
++) {
72 struct kms_framebuffer
*fb
;
73 enum native_attachment natt
;
74 struct winsys_handle whandle
;
78 fb
= &ksurf
->front_fb
;
79 natt
= NATIVE_ATTACHMENT_FRONT_LEFT
;
83 natt
= NATIVE_ATTACHMENT_BACK_LEFT
;
87 /* make sure the texture has been allocated */
88 resource_surface_add_resources(ksurf
->rsurf
, 1 << natt
);
90 resource_surface_get_single_resource(ksurf
->rsurf
, natt
);
95 /* already initialized */
99 /* TODO detect the real value */
100 fb
->is_passive
= TRUE
;
102 memset(&whandle
, 0, sizeof(whandle
));
103 whandle
.type
= DRM_API_HANDLE_TYPE_KMS
;
105 if (!kdpy
->base
.screen
->resource_get_handle(kdpy
->base
.screen
,
106 fb
->texture
, &whandle
))
109 block_bits
= util_format_get_blocksizebits(ksurf
->color_format
);
110 err
= drmModeAddFB(kdpy
->fd
, ksurf
->width
, ksurf
->height
,
111 block_bits
, block_bits
, whandle
.stride
, whandle
.handle
,
123 kms_surface_flush_frontbuffer(struct native_surface
*nsurf
)
125 #ifdef DRM_MODE_FEATURE_DIRTYFB
126 struct kms_surface
*ksurf
= kms_surface(nsurf
);
127 struct kms_display
*kdpy
= ksurf
->kdpy
;
129 if (ksurf
->front_fb
.is_passive
)
130 drmModeDirtyFB(kdpy
->fd
, ksurf
->front_fb
.buffer_id
, NULL
, 0);
137 kms_surface_swap_buffers(struct native_surface
*nsurf
)
139 struct kms_surface
*ksurf
= kms_surface(nsurf
);
140 struct kms_crtc
*kcrtc
= &ksurf
->current_crtc
;
141 struct kms_display
*kdpy
= ksurf
->kdpy
;
142 struct kms_framebuffer tmp_fb
;
145 if (!ksurf
->back_fb
.buffer_id
) {
146 if (!kms_surface_init_framebuffers(&ksurf
->base
, TRUE
))
150 if (ksurf
->is_shown
&& kcrtc
->crtc
) {
151 err
= drmModeSetCrtc(kdpy
->fd
, kcrtc
->crtc
->crtc_id
,
152 ksurf
->back_fb
.buffer_id
, kcrtc
->crtc
->x
, kcrtc
->crtc
->y
,
153 kcrtc
->connectors
, kcrtc
->num_connectors
, &kcrtc
->crtc
->mode
);
158 /* swap the buffers */
159 tmp_fb
= ksurf
->front_fb
;
160 ksurf
->front_fb
= ksurf
->back_fb
;
161 ksurf
->back_fb
= tmp_fb
;
163 resource_surface_swap_buffers(ksurf
->rsurf
,
164 NATIVE_ATTACHMENT_FRONT_LEFT
, NATIVE_ATTACHMENT_BACK_LEFT
, FALSE
);
165 /* the front/back textures are swapped */
166 ksurf
->sequence_number
++;
167 kdpy
->event_handler
->invalid_surface(&kdpy
->base
,
168 &ksurf
->base
, ksurf
->sequence_number
);
174 kms_surface_wait(struct native_surface
*nsurf
)
180 kms_surface_destroy(struct native_surface
*nsurf
)
182 struct kms_surface
*ksurf
= kms_surface(nsurf
);
184 if (ksurf
->current_crtc
.crtc
)
185 drmModeFreeCrtc(ksurf
->current_crtc
.crtc
);
187 if (ksurf
->front_fb
.buffer_id
)
188 drmModeRmFB(ksurf
->kdpy
->fd
, ksurf
->front_fb
.buffer_id
);
189 pipe_resource_reference(&ksurf
->front_fb
.texture
, NULL
);
191 if (ksurf
->back_fb
.buffer_id
)
192 drmModeRmFB(ksurf
->kdpy
->fd
, ksurf
->back_fb
.buffer_id
);
193 pipe_resource_reference(&ksurf
->back_fb
.texture
, NULL
);
195 resource_surface_destroy(ksurf
->rsurf
);
199 static struct kms_surface
*
200 kms_display_create_surface(struct native_display
*ndpy
,
201 const struct native_config
*nconf
,
202 uint width
, uint height
)
204 struct kms_display
*kdpy
= kms_display(ndpy
);
205 struct kms_config
*kconf
= kms_config(nconf
);
206 struct kms_surface
*ksurf
;
208 ksurf
= CALLOC_STRUCT(kms_surface
);
213 ksurf
->color_format
= kconf
->base
.color_format
;
214 ksurf
->width
= width
;
215 ksurf
->height
= height
;
217 ksurf
->rsurf
= resource_surface_create(kdpy
->base
.screen
,
219 PIPE_BIND_RENDER_TARGET
|
220 PIPE_BIND_SAMPLER_VIEW
|
221 PIPE_BIND_DISPLAY_TARGET
|
228 resource_surface_set_size(ksurf
->rsurf
, ksurf
->width
, ksurf
->height
);
230 ksurf
->base
.destroy
= kms_surface_destroy
;
231 ksurf
->base
.swap_buffers
= kms_surface_swap_buffers
;
232 ksurf
->base
.flush_frontbuffer
= kms_surface_flush_frontbuffer
;
233 ksurf
->base
.validate
= kms_surface_validate
;
234 ksurf
->base
.wait
= kms_surface_wait
;
240 * Choose a CRTC that supports all given connectors.
243 kms_display_choose_crtc(struct native_display
*ndpy
,
244 uint32_t *connectors
, int num_connectors
)
246 struct kms_display
*kdpy
= kms_display(ndpy
);
249 for (idx
= 0; idx
< kdpy
->resources
->count_crtcs
; idx
++) {
250 boolean found_crtc
= TRUE
;
253 for (i
= 0; i
< num_connectors
; i
++) {
254 drmModeConnectorPtr connector
;
255 int encoder_idx
= -1;
257 connector
= drmModeGetConnector(kdpy
->fd
, connectors
[i
]);
263 /* find an encoder the CRTC supports */
264 for (j
= 0; j
< connector
->count_encoders
; j
++) {
265 drmModeEncoderPtr encoder
=
266 drmModeGetEncoder(kdpy
->fd
, connector
->encoders
[j
]);
267 if (encoder
->possible_crtcs
& (1 << idx
)) {
271 drmModeFreeEncoder(encoder
);
274 drmModeFreeConnector(connector
);
275 if (encoder_idx
< 0) {
285 if (idx
>= kdpy
->resources
->count_crtcs
) {
286 _eglLog(_EGL_WARNING
,
287 "failed to find a CRTC that supports the given %d connectors",
292 return kdpy
->resources
->crtcs
[idx
];
296 * Remember the original CRTC status and set the CRTC
299 kms_display_set_crtc(struct native_display
*ndpy
, int crtc_idx
,
300 uint32_t buffer_id
, uint32_t x
, uint32_t y
,
301 uint32_t *connectors
, int num_connectors
,
302 drmModeModeInfoPtr mode
)
304 struct kms_display
*kdpy
= kms_display(ndpy
);
305 struct kms_crtc
*kcrtc
= &kdpy
->saved_crtcs
[crtc_idx
];
310 crtc_id
= kcrtc
->crtc
->crtc_id
;
316 * Choose the CRTC once. It could be more dynamic, but let's keep it
319 crtc_id
= kms_display_choose_crtc(&kdpy
->base
,
320 connectors
, num_connectors
);
322 /* save the original CRTC status */
323 kcrtc
->crtc
= drmModeGetCrtc(kdpy
->fd
, crtc_id
);
327 for (i
= 0; i
< kdpy
->num_connectors
; i
++) {
328 struct kms_connector
*kconn
= &kdpy
->connectors
[i
];
329 drmModeConnectorPtr connector
= kconn
->connector
;
330 drmModeEncoderPtr encoder
;
332 encoder
= drmModeGetEncoder(kdpy
->fd
, connector
->encoder_id
);
334 if (encoder
->crtc_id
== crtc_id
) {
335 kcrtc
->connectors
[count
++] = connector
->connector_id
;
336 if (count
>= Elements(kcrtc
->connectors
))
339 drmModeFreeEncoder(encoder
);
343 kcrtc
->num_connectors
= count
;
346 err
= drmModeSetCrtc(kdpy
->fd
, crtc_id
, buffer_id
, x
, y
,
347 connectors
, num_connectors
, mode
);
349 drmModeFreeCrtc(kcrtc
->crtc
);
351 kcrtc
->num_connectors
= 0;
360 kms_display_program(struct native_display
*ndpy
, int crtc_idx
,
361 struct native_surface
*nsurf
, uint x
, uint y
,
362 const struct native_connector
**nconns
, int num_nconns
,
363 const struct native_mode
*nmode
)
365 struct kms_display
*kdpy
= kms_display(ndpy
);
366 struct kms_surface
*ksurf
= kms_surface(nsurf
);
367 const struct kms_mode
*kmode
= kms_mode(nmode
);
368 uint32_t connector_ids
[32];
370 drmModeModeInfo mode_tmp
, *mode
;
373 if (num_nconns
> Elements(connector_ids
)) {
374 _eglLog(_EGL_WARNING
, "too many connectors (%d)", num_nconns
);
375 num_nconns
= Elements(connector_ids
);
379 if (!kms_surface_init_framebuffers(&ksurf
->base
, FALSE
))
382 buffer_id
= ksurf
->front_fb
.buffer_id
;
383 /* the mode argument of drmModeSetCrtc is not constified */
384 mode_tmp
= kmode
->mode
;
388 /* disable the CRTC */
394 for (i
= 0; i
< num_nconns
; i
++) {
395 struct kms_connector
*kconn
= kms_connector(nconns
[i
]);
396 connector_ids
[i
] = kconn
->connector
->connector_id
;
399 if (!kms_display_set_crtc(&kdpy
->base
, crtc_idx
, buffer_id
, x
, y
,
400 connector_ids
, num_nconns
, mode
)) {
401 _eglLog(_EGL_WARNING
, "failed to set CRTC %d", crtc_idx
);
406 if (kdpy
->shown_surfaces
[crtc_idx
])
407 kdpy
->shown_surfaces
[crtc_idx
]->is_shown
= FALSE
;
408 kdpy
->shown_surfaces
[crtc_idx
] = ksurf
;
410 /* remember the settings for buffer swapping */
412 uint32_t crtc_id
= kdpy
->saved_crtcs
[crtc_idx
].crtc
->crtc_id
;
413 struct kms_crtc
*kcrtc
= &ksurf
->current_crtc
;
416 drmModeFreeCrtc(kcrtc
->crtc
);
417 kcrtc
->crtc
= drmModeGetCrtc(kdpy
->fd
, crtc_id
);
419 assert(num_nconns
< Elements(kcrtc
->connectors
));
420 memcpy(kcrtc
->connectors
, connector_ids
,
421 sizeof(*connector_ids
) * num_nconns
);
422 kcrtc
->num_connectors
= num_nconns
;
424 ksurf
->is_shown
= TRUE
;
430 static const struct native_mode
**
431 kms_display_get_modes(struct native_display
*ndpy
,
432 const struct native_connector
*nconn
,
435 struct kms_display
*kdpy
= kms_display(ndpy
);
436 struct kms_connector
*kconn
= kms_connector(nconn
);
437 const struct native_mode
**nmodes_return
;
440 /* delete old data */
441 if (kconn
->connector
) {
442 drmModeFreeConnector(kconn
->connector
);
443 FREE(kconn
->kms_modes
);
445 kconn
->connector
= NULL
;
446 kconn
->kms_modes
= NULL
;
447 kconn
->num_modes
= 0;
451 kconn
->connector
= drmModeGetConnector(kdpy
->fd
, kconn
->connector_id
);
452 if (!kconn
->connector
)
455 count
= kconn
->connector
->count_modes
;
456 kconn
->kms_modes
= CALLOC(count
, sizeof(*kconn
->kms_modes
));
457 if (!kconn
->kms_modes
) {
458 drmModeFreeConnector(kconn
->connector
);
459 kconn
->connector
= NULL
;
464 for (i
= 0; i
< count
; i
++) {
465 struct kms_mode
*kmode
= &kconn
->kms_modes
[i
];
466 drmModeModeInfoPtr mode
= &kconn
->connector
->modes
[i
];
470 kmode
->base
.desc
= kmode
->mode
.name
;
471 kmode
->base
.width
= kmode
->mode
.hdisplay
;
472 kmode
->base
.height
= kmode
->mode
.vdisplay
;
473 kmode
->base
.refresh_rate
= kmode
->mode
.vrefresh
;
474 /* not all kernels have vrefresh = refresh_rate * 1000 */
475 if (kmode
->base
.refresh_rate
> 1000)
476 kmode
->base
.refresh_rate
= (kmode
->base
.refresh_rate
+ 500) / 1000;
479 nmodes_return
= MALLOC(count
* sizeof(*nmodes_return
));
481 for (i
= 0; i
< count
; i
++)
482 nmodes_return
[i
] = &kconn
->kms_modes
[i
].base
;
487 return nmodes_return
;
490 static const struct native_connector
**
491 kms_display_get_connectors(struct native_display
*ndpy
, int *num_connectors
,
494 struct kms_display
*kdpy
= kms_display(ndpy
);
495 const struct native_connector
**connectors
;
498 if (!kdpy
->connectors
) {
500 CALLOC(kdpy
->resources
->count_connectors
, sizeof(*kdpy
->connectors
));
501 if (!kdpy
->connectors
)
504 for (i
= 0; i
< kdpy
->resources
->count_connectors
; i
++) {
505 struct kms_connector
*kconn
= &kdpy
->connectors
[i
];
507 kconn
->connector_id
= kdpy
->resources
->connectors
[i
];
508 /* kconn->connector is allocated when the modes are asked */
511 kdpy
->num_connectors
= kdpy
->resources
->count_connectors
;
514 connectors
= MALLOC(kdpy
->num_connectors
* sizeof(*connectors
));
516 for (i
= 0; i
< kdpy
->num_connectors
; i
++)
517 connectors
[i
] = &kdpy
->connectors
[i
].base
;
519 *num_connectors
= kdpy
->num_connectors
;
523 *num_crtc
= kdpy
->resources
->count_crtcs
;
528 static struct native_surface
*
529 kms_display_create_scanout_surface(struct native_display
*ndpy
,
530 const struct native_config
*nconf
,
531 uint width
, uint height
)
533 struct kms_surface
*ksurf
;
535 ksurf
= kms_display_create_surface(ndpy
, nconf
, width
, height
);
540 kms_display_is_format_supported(struct native_display
*ndpy
,
541 enum pipe_format fmt
, boolean is_color
)
543 return ndpy
->screen
->is_format_supported(ndpy
->screen
,
544 fmt
, PIPE_TEXTURE_2D
, 0,
545 (is_color
) ? PIPE_BIND_RENDER_TARGET
:
546 PIPE_BIND_DEPTH_STENCIL
, 0);
549 static const struct native_config
**
550 kms_display_get_configs(struct native_display
*ndpy
, int *num_configs
)
552 struct kms_display
*kdpy
= kms_display(ndpy
);
553 const struct native_config
**configs
;
557 struct native_config
*nconf
;
558 enum pipe_format format
;
560 kdpy
->config
= CALLOC(1, sizeof(*kdpy
->config
));
564 nconf
= &kdpy
->config
->base
;
567 (1 << NATIVE_ATTACHMENT_FRONT_LEFT
) |
568 (1 << NATIVE_ATTACHMENT_BACK_LEFT
);
570 format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
571 if (!kms_display_is_format_supported(&kdpy
->base
, format
, TRUE
)) {
572 format
= PIPE_FORMAT_A8R8G8B8_UNORM
;
573 if (!kms_display_is_format_supported(&kdpy
->base
, format
, TRUE
))
574 format
= PIPE_FORMAT_NONE
;
576 if (format
== PIPE_FORMAT_NONE
) {
582 nconf
->color_format
= format
;
584 nconf
->scanout_bit
= TRUE
;
587 configs
= MALLOC(sizeof(*configs
));
589 configs
[0] = &kdpy
->config
->base
;
598 kms_display_get_param(struct native_display
*ndpy
,
599 enum native_param_type param
)
613 kms_display_destroy(struct native_display
*ndpy
)
615 struct kms_display
*kdpy
= kms_display(ndpy
);
621 if (kdpy
->connectors
) {
622 for (i
= 0; i
< kdpy
->num_connectors
; i
++) {
623 struct kms_connector
*kconn
= &kdpy
->connectors
[i
];
624 if (kconn
->connector
) {
625 drmModeFreeConnector(kconn
->connector
);
626 FREE(kconn
->kms_modes
);
629 FREE(kdpy
->connectors
);
632 if (kdpy
->shown_surfaces
)
633 FREE(kdpy
->shown_surfaces
);
635 if (kdpy
->saved_crtcs
) {
636 for (i
= 0; i
< kdpy
->resources
->count_crtcs
; i
++) {
637 struct kms_crtc
*kcrtc
= &kdpy
->saved_crtcs
[i
];
641 drmModeSetCrtc(kdpy
->fd
, kcrtc
->crtc
->crtc_id
,
642 kcrtc
->crtc
->buffer_id
, kcrtc
->crtc
->x
, kcrtc
->crtc
->y
,
643 kcrtc
->connectors
, kcrtc
->num_connectors
,
646 drmModeFreeCrtc(kcrtc
->crtc
);
649 FREE(kdpy
->saved_crtcs
);
653 drmModeFreeResources(kdpy
->resources
);
655 if (kdpy
->base
.screen
)
656 kdpy
->base
.screen
->destroy(kdpy
->base
.screen
);
665 * Initialize KMS and pipe screen.
668 kms_display_init_screen(struct native_display
*ndpy
)
670 struct kms_display
*kdpy
= kms_display(ndpy
);
675 drmVersionPtr version
= drmGetVersion(fd
);
676 if (!version
|| strcmp(version
->name
, driver_descriptor
.driver_name
)) {
678 _eglLog(_EGL_WARNING
, "unknown driver name %s", version
->name
);
679 drmFreeVersion(version
);
682 _eglLog(_EGL_WARNING
, "invalid fd %d", fd
);
688 drmFreeVersion(version
);
691 fd
= drmOpen(driver_descriptor
.driver_name
, NULL
);
695 _eglLog(_EGL_WARNING
, "failed to open DRM device");
700 if (drmSetMaster(fd
)) {
701 _eglLog(_EGL_WARNING
, "failed to become DRM master");
706 kdpy
->base
.screen
= driver_descriptor
.create_screen(fd
);
707 if (!kdpy
->base
.screen
) {
708 _eglLog(_EGL_WARNING
, "failed to create DRM screen");
718 static struct native_display_modeset kms_display_modeset
= {
719 .get_connectors
= kms_display_get_connectors
,
720 .get_modes
= kms_display_get_modes
,
721 .create_scanout_surface
= kms_display_create_scanout_surface
,
722 .program
= kms_display_program
725 static struct native_display
*
726 kms_create_display(int fd
, struct native_event_handler
*event_handler
)
728 struct kms_display
*kdpy
;
730 kdpy
= CALLOC_STRUCT(kms_display
);
734 kdpy
->event_handler
= event_handler
;
736 if (!kms_display_init_screen(&kdpy
->base
)) {
737 kms_display_destroy(&kdpy
->base
);
741 /* resources are fixed, unlike crtc, connector, or encoder */
742 kdpy
->resources
= drmModeGetResources(kdpy
->fd
);
743 if (!kdpy
->resources
) {
744 kms_display_destroy(&kdpy
->base
);
749 CALLOC(kdpy
->resources
->count_crtcs
, sizeof(*kdpy
->saved_crtcs
));
750 if (!kdpy
->saved_crtcs
) {
751 kms_display_destroy(&kdpy
->base
);
755 kdpy
->shown_surfaces
=
756 CALLOC(kdpy
->resources
->count_crtcs
, sizeof(*kdpy
->shown_surfaces
));
757 if (!kdpy
->shown_surfaces
) {
758 kms_display_destroy(&kdpy
->base
);
762 kdpy
->base
.destroy
= kms_display_destroy
;
763 kdpy
->base
.get_param
= kms_display_get_param
;
764 kdpy
->base
.get_configs
= kms_display_get_configs
;
766 kdpy
->base
.modeset
= &kms_display_modeset
;
771 static struct native_display
*
772 native_create_display(void *dpy
, struct native_event_handler
*event_handler
)
774 struct native_display
*ndpy
;
777 /* well, this makes fd 0 being ignored */
778 fd
= (dpy
) ? (int) pointer_to_intptr(dpy
) : -1;
779 ndpy
= kms_create_display(fd
, event_handler
);
785 kms_init_platform(struct native_platform
*nplat
)
787 static char kms_name
[32];
792 util_snprintf(kms_name
, sizeof(kms_name
), "KMS/%s", driver_descriptor
.name
);
794 nplat
->name
= kms_name
;
795 nplat
->create_probe
= NULL
;
796 nplat
->get_probe_result
= NULL
;
797 nplat
->create_display
= native_create_display
;
800 static struct native_platform kms_platform
;
802 const struct native_platform
*
803 native_get_platform(void)
805 kms_init_platform(&kms_platform
);
806 return &kms_platform
;