Compare commits

...

6 Commits

Author SHA1 Message Date
Ray Strode 2cc3013c3f kms-winsys: support drm render nodes
Right now cogl does all rendering and modesetting using
/dev/dri/card0. If rendering were moved to /dev/dri/renderD128
then it would be in a better position to support offloading
rendering operations to a second gpu.

Also, some versions of the vmware driver don't support using
card0 when running on an inactive VT.  The result is crashes
low in the rendering stack.

This commit leaves card0 for modesetting operations, but defers
rendering operations to a render node.  The output is synchronized
to card0 using dma-buf. render nodes can be used even when VT
switched away, so this will fix crashes on vmware.

https://bugzilla.gnome.org/show_bug.cgi?id=753531
2015-08-27 14:49:20 -04:00
Ray Strode e4b5dbb7a1 kms-winsys: rework handling of the drm fd
At the moment the drm fd is stored in the renderer structure twice:
once for reading and once for closing. This is a little messy, and
will only get worse when we start throwing render nodes into the mix,
too.

This commit abstracts the device handling out to another structure.
Rather than having two members for each fd, this commit employees a
boolean to decide whether or not the fd needs to get explicitly closed.

https://bugzilla.gnome.org/show_bug.cgi?id=753531
2015-08-27 14:49:15 -04:00
Ray Strode 268e430548 kms-winsys: rename device_name to card_device_name
The variable device_name is currently used to hold
the name of the drm device to open ("/dev/dri/card0").
We're going to be opening other drm devices in the future
(render nodes), so device_name will become ambiguous.

This commit renames it to card_device_name

https://bugzilla.gnome.org/show_bug.cgi?id=753531
2015-08-27 14:49:10 -04:00
Ray Strode 07aa682054 kms-winsys: clean up error handling in _cogl_winsys_renderer_connect
If cogl fails to open the drm device, initialize gbm, or open the
egl display, then it closes the drm fd, uninitializes gbm, closes the
display and then calls _cogl_winsys_renderer_disconnect which does
most of those things again, on the, now deinitialized, members.

This commit removes the explicit failure handling in renderer_connect and
defers cleanup to disconnect.

https://bugzilla.gnome.org/show_bug.cgi?id=753531
2015-08-27 14:49:04 -04:00
Ray Strode 06bdc4e2c1 kms-winsys: use correct surface format
gbm confusingly has two different format types, and cogl
is using the wrong one in some of its calls to gbm_surface_create

This commit fixes the calls that are wrong.

https://bugzilla.gnome.org/show_bug.cgi?id=753531
2015-08-27 14:48:58 -04:00
Ray Strode 8e6f30ae60 kms-winsys: drop support for old gbm versions
Right now cogl tries to accomodate older gbm versions that
have the function gbm_bo_get_pitch() instead of the more
recently named gbm_bo_get_stride().

This adds an ugly #ifdef in the code. Furthermore, we are
going to rely on newer gbm for dma-buf support anyway.

This commit drops the #ifdef.

https://bugzilla.gnome.org/show_bug.cgi?id=753531
2015-08-27 14:48:51 -04:00
1 changed files with 132 additions and 58 deletions

View File

@ -46,6 +46,7 @@
#include <xf86drmMode.h>
#include <gbm.h>
#include <glib.h>
#include <glob.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <string.h>
@ -66,11 +67,18 @@ static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
static const CoglWinsysVtable *parent_vtable;
typedef struct _CoglRendererKMS
typedef struct _CoglRendererDeviceKMS
{
int fd;
int opened_fd;
struct gbm_device *gbm;
CoglBool is_borrowed;
} CoglRendererDeviceKMS;
typedef struct _CoglRendererKMS
{
struct gbm_device *rendering_gbm;
CoglRendererDeviceKMS card_device;
CoglRendererDeviceKMS render_offload_device;
CoglClosure *swap_notify_idle;
CoglBool page_flips_not_supported;
} CoglRendererKMS;
@ -110,13 +118,15 @@ typedef struct _CoglOnscreenKMS
uint32_t next_fb_id;
struct gbm_bo *current_bo;
struct gbm_bo *next_bo;
struct gbm_bo *card_bo;
CoglBool pending_swap_notify;
EGLSurface *pending_egl_surface;
struct gbm_surface *pending_surface;
} CoglOnscreenKMS;
static const char device_name[] = "/dev/dri/card0";
static const char card_device_name[] = "/dev/dri/card0";
static const char render_offload_device_glob[] = "/dev/dri/renderD*";
static void
_cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
@ -124,10 +134,20 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
eglTerminate (egl_renderer->edpy);
if (egl_renderer->edpy != EGL_NO_DISPLAY)
eglTerminate (egl_renderer->edpy);
if (kms_renderer->opened_fd >= 0)
close (kms_renderer->opened_fd);
if (kms_renderer->card_device.gbm != NULL)
gbm_device_destroy (kms_renderer->card_device.gbm);
if (kms_renderer->render_offload_device.gbm != NULL)
gbm_device_destroy (kms_renderer->render_offload_device.gbm);
if (!kms_renderer->card_device.is_borrowed && kms_renderer->card_device.fd >= 0)
close (kms_renderer->card_device.fd);
if (!kms_renderer->render_offload_device.is_borrowed && kms_renderer->render_offload_device.fd >= 0)
close (kms_renderer->render_offload_device.fd);
g_slice_free (CoglRendererKMS, kms_renderer);
g_slice_free (CoglRendererEGL, egl_renderer);
@ -187,7 +207,7 @@ free_current_bo (CoglOnscreen *onscreen)
if (kms_onscreen->current_fb_id)
{
drmModeRmFB (kms_renderer->fd,
drmModeRmFB (kms_renderer->card_device.fd,
kms_onscreen->current_fb_id);
kms_onscreen->current_fb_id = 0;
}
@ -246,6 +266,8 @@ process_flip (CoglFlipKMS *flip)
kms_onscreen->current_bo = kms_onscreen->next_bo;
kms_onscreen->next_bo = NULL;
g_clear_pointer (&kms_onscreen->card_bo, gbm_bo_destroy);
cogl_object_unref (flip->onscreen);
g_slice_free (CoglFlipKMS, flip);
@ -275,7 +297,7 @@ handle_drm_event (CoglRendererKMS *kms_renderer)
memset (&evctx, 0, sizeof evctx);
evctx.version = DRM_EVENT_CONTEXT_VERSION;
evctx.page_flip_handler = page_flip_handler;
drmHandleEvent (kms_renderer->fd, &evctx);
drmHandleEvent (kms_renderer->card_device.fd, &evctx);
}
static void
@ -297,6 +319,8 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
{
CoglRendererEGL *egl_renderer;
CoglRendererKMS *kms_renderer;
glob_t glob_buffer = { 0 };
int ret;
renderer->winsys = g_slice_new0 (CoglRendererEGL);
egl_renderer = renderer->winsys;
@ -305,50 +329,89 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
egl_renderer->platform = g_slice_new0 (CoglRendererKMS);
kms_renderer = egl_renderer->platform;
kms_renderer->fd = -1;
kms_renderer->opened_fd = -1;
egl_renderer->edpy = EGL_NO_DISPLAY;
kms_renderer->render_offload_device.fd = -1;
ret = glob (render_offload_device_glob, 0, NULL, &glob_buffer);
if (ret != GLOB_NOMATCH)
{
kms_renderer->render_offload_device.fd = open (glob_buffer.gl_pathv[0], O_RDWR);
if (kms_renderer->render_offload_device.fd < 0)
g_debug ("could not open '%s': %m", glob_buffer.gl_pathv[0]);
}
globfree (&glob_buffer);
if (kms_renderer->render_offload_device.fd >= 0)
{
kms_renderer->render_offload_device.gbm = gbm_create_device (kms_renderer->render_offload_device.fd);
if (kms_renderer->render_offload_device.gbm != NULL)
{
egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->render_offload_device.gbm);
if (egl_renderer->edpy != EGL_NO_DISPLAY)
{
kms_renderer->rendering_gbm = kms_renderer->render_offload_device.gbm;
}
else
{
gbm_device_destroy (kms_renderer->render_offload_device.gbm);
kms_renderer->render_offload_device.gbm = NULL;
}
}
}
kms_renderer->card_device.fd = -1;
if (renderer->kms_fd >= 0)
{
kms_renderer->fd = renderer->kms_fd;
kms_renderer->card_device.fd = renderer->kms_fd;
kms_renderer->card_device.is_borrowed = TRUE;
}
else
{
kms_renderer->opened_fd = open (device_name, O_RDWR);
kms_renderer->fd = kms_renderer->opened_fd;
if (kms_renderer->fd < 0)
kms_renderer->card_device.fd = open (card_device_name, O_RDWR);
if (kms_renderer->card_device.fd < 0)
{
/* Probably permissions error */
_cogl_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Couldn't open %s", device_name);
"Couldn't open %s", card_device_name);
return FALSE;
}
}
kms_renderer->gbm = gbm_create_device (kms_renderer->fd);
if (kms_renderer->gbm == NULL)
kms_renderer->card_device.gbm = gbm_create_device (kms_renderer->card_device.fd);
if (kms_renderer->card_device.gbm == NULL)
{
_cogl_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Couldn't create gbm device");
goto close_fd;
COGL_WINSYS_ERROR_INIT,
"Couldn't create gbm device");
goto fail;
}
egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm);
if (egl_renderer->edpy == EGL_NO_DISPLAY)
{
_cogl_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Couldn't get eglDisplay");
goto destroy_gbm_device;
egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->card_device.gbm);
if (egl_renderer->edpy == EGL_NO_DISPLAY)
{
_cogl_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_INIT,
"Couldn't get eglDisplay");
goto fail;
}
kms_renderer->rendering_gbm = kms_renderer->card_device.gbm;
}
if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
goto egl_terminate;
goto fail;
_cogl_poll_renderer_add_fd (renderer,
kms_renderer->fd,
kms_renderer->card_device.fd,
COGL_POLL_FD_EVENT_IN,
NULL, /* no prepare callback */
dispatch_kms_events,
@ -356,14 +419,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
return TRUE;
egl_terminate:
eglTerminate (egl_renderer->edpy);
destroy_gbm_device:
gbm_device_destroy (kms_renderer->gbm);
close_fd:
if (kms_renderer->opened_fd >= 0)
close (kms_renderer->opened_fd);
fail:
_cogl_winsys_renderer_disconnect (renderer);
return FALSE;
@ -567,7 +623,7 @@ setup_crtc_modes (CoglDisplay *display, int fb_id)
{
CoglKmsCrtc *crtc = l->data;
int ret = drmModeSetCrtc (kms_renderer->fd,
int ret = drmModeSetCrtc (kms_renderer->card_device.fd,
crtc->id,
fb_id, crtc->x, crtc->y,
crtc->connectors, crtc->count,
@ -599,7 +655,7 @@ flip_all_crtcs (CoglDisplay *display, CoglFlipKMS *flip, int fb_id)
if (!kms_renderer->page_flips_not_supported)
{
ret = drmModePageFlip (kms_renderer->fd,
ret = drmModePageFlip (kms_renderer->card_device.fd,
crtc->id, fb_id,
DRM_MODE_PAGE_FLIP_EVENT, flip);
if (ret)
@ -653,7 +709,7 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
kms_display = g_slice_new0 (CoglDisplayKMS);
egl_display->platform = kms_display;
resources = drmModeGetResources (kms_renderer->fd);
resources = drmModeGetResources (kms_renderer->card_device.fd);
if (!resources)
{
_cogl_set_error (error, COGL_WINSYS_ERROR,
@ -663,7 +719,7 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
}
output0 = find_output (0,
kms_renderer->fd,
kms_renderer->card_device.fd,
resources,
NULL,
0, /* n excluded connectors */
@ -682,7 +738,7 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
{
int exclude_connector = output0->connector->connector_id;
output1 = find_output (1,
kms_renderer->fd,
kms_renderer->card_device.fd,
resources,
&exclude_connector,
1, /* n excluded connectors */
@ -782,7 +838,7 @@ _cogl_winsys_egl_display_destroy (CoglDisplay *display)
GList *l;
for (l = kms_display->outputs; l; l = l->next)
output_free (kms_renderer->fd, l->data);
output_free (kms_renderer->card_device.fd, l->data);
g_list_free (kms_display->outputs);
kms_display->outputs = NULL;
@ -805,7 +861,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0)
{
kms_display->dummy_gbm_surface =
gbm_surface_create (kms_renderer->gbm,
gbm_surface_create (kms_renderer->rendering_gbm,
16, 16,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_RENDERING);
@ -880,7 +936,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
CoglRendererKMS *kms_renderer = egl_renderer->platform;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
uint32_t handle, stride;
uint32_t handle = 0, stride;
CoglFlipKMS *flip;
/* If we already have a pending swap then block until it completes */
@ -910,16 +966,32 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
}
/* Now we need to set the CRTC to whatever is the front buffer */
kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface);
#if (COGL_VERSION_ENCODE (COGL_GBM_MAJOR, COGL_GBM_MINOR, COGL_GBM_MICRO) >= \
COGL_VERSION_ENCODE (8, 1, 0))
stride = gbm_bo_get_stride (kms_onscreen->next_bo);
#else
stride = gbm_bo_get_pitch (kms_onscreen->next_bo);
#endif
handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32;
if (drmModeAddFB (kms_renderer->fd,
if (kms_renderer->render_offload_device.gbm != NULL)
{
struct gbm_import_fd_data dma_buf_data = { 0 };
dma_buf_data.fd = gbm_bo_get_fd (kms_onscreen->next_bo);
dma_buf_data.width = gbm_bo_get_width (kms_onscreen->next_bo);
dma_buf_data.height = gbm_bo_get_height (kms_onscreen->next_bo);
dma_buf_data.stride = stride;
dma_buf_data.format = gbm_bo_get_format (kms_onscreen->next_bo);
kms_onscreen->card_bo = gbm_bo_import (kms_renderer->card_device.gbm,
GBM_BO_IMPORT_FD,
&dma_buf_data,
GBM_BO_USE_SCANOUT);
close (dma_buf_data.fd);
if (kms_onscreen->card_bo != NULL)
handle = gbm_bo_get_handle (kms_onscreen->card_bo).u32;
}
if (handle == 0)
handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32;
if (drmModeAddFB (kms_renderer->card_device.fd,
kms_display->width,
kms_display->height,
24, /* depth */
@ -929,6 +1001,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
&kms_onscreen->next_fb_id))
{
g_warning ("Failed to create new back buffer handle: %m");
g_clear_pointer (&kms_onscreen->card_bo, gbm_bo_destroy);
gbm_surface_release_buffer (kms_onscreen->surface,
kms_onscreen->next_bo);
kms_onscreen->next_bo = NULL;
@ -951,7 +1024,8 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
if (flip->pending == 0)
{
drmModeRmFB (kms_renderer->fd, kms_onscreen->next_fb_id);
drmModeRmFB (kms_renderer->card_device.fd, kms_onscreen->next_fb_id);
g_clear_pointer (&kms_onscreen->card_bo, gbm_bo_destroy);
gbm_surface_release_buffer (kms_onscreen->surface,
kms_onscreen->next_bo);
kms_onscreen->next_bo = NULL;
@ -1026,10 +1100,10 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
egl_onscreen->platform = kms_onscreen;
kms_onscreen->surface =
gbm_surface_create (kms_renderer->gbm,
gbm_surface_create (kms_renderer->rendering_gbm,
kms_display->width,
kms_display->height,
GBM_BO_FORMAT_XRGB8888,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT |
GBM_BO_USE_RENDERING);
@ -1168,7 +1242,7 @@ cogl_kms_renderer_get_gbm (CoglRenderer *renderer)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
return kms_renderer->gbm;
return kms_renderer->card_device.gbm;
}
else
return NULL;
@ -1183,7 +1257,7 @@ cogl_kms_renderer_get_kms_fd (CoglRenderer *renderer)
{
CoglRendererEGL *egl_renderer = renderer->winsys;
CoglRendererKMS *kms_renderer = egl_renderer->platform;
return kms_renderer->fd;
return kms_renderer->card_device.fd;
}
else
return -1;
@ -1227,9 +1301,9 @@ cogl_kms_display_set_layout (CoglDisplay *display,
/* Need to drop the GBM surface and create a new one */
new_surface = gbm_surface_create (kms_renderer->gbm,
new_surface = gbm_surface_create (kms_renderer->rendering_gbm,
width, height,
GBM_BO_FORMAT_XRGB8888,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT |
GBM_BO_USE_RENDERING);