summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Bradford <rob@linux.intel.com>2011-11-07 17:16:13 +0000
committerRob Bradford <rob@linux.intel.com>2011-11-28 14:42:10 +0000
commit88f80d3b4670d4181856281e299ae5ad2a0b0fa9 (patch)
treef013cb5876c3d9e7a523f995de2a5e057fb2491d
parentd44e548715da619364d4f82e26e83957af38701d (diff)
downloadcogl-wip/rob/kms-winsys.tar.gz
kms: Add first version of "baremetal" backend for EGL on KMSwip/rob/kms-winsys
To compile this backend - get some dribbly black candles, sacrifice a goat and configure with: ./configure --enable-kms-egl-platform --disable-xlib-egl-platform \ --disable-glx --disable-introspection
-rw-r--r--cogl/Makefile.am5
-rw-r--r--cogl/winsys/cogl-winsys-egl.c128
-rw-r--r--cogl/winsys/cogl-winsys-kms.c390
-rw-r--r--cogl/winsys/cogl-winsys-kms.h99
-rw-r--r--configure.ac26
5 files changed, 634 insertions, 14 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 51f6d422..46a1a8c8 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -370,6 +370,11 @@ if SUPPORT_EGL_PLATFORM_WAYLAND
cogl_public_h += \
$(srcdir)/cogl-wayland-renderer.h
endif
+if SUPPORT_EGL_PLATFORM_KMS
+cogl_sources_c += \
+ $(srcdir)/winsys/cogl-winsys-kms.c \
+ $(srcdir)/winsys/cogl-winsys-kms.h
+endif
if SUPPORT_EGL
cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c \
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c
index ec2842b9..fe998ccb 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -62,7 +62,12 @@
#include <android/native_window.h>
#endif
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+#include "cogl-winsys-kms.h"
+#endif
+
#include <stdlib.h>
+#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -106,6 +111,9 @@ typedef struct _CoglRendererEGL
#ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
gboolean gdl_initialized;
#endif
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ CoglRendererKMS kms_renderer;
+#endif
/* Function pointers for GLX specific extensions */
#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d)
@@ -137,8 +145,13 @@ typedef struct _CoglDisplayEGL
EGLSurface dummy_surface;
#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) || \
- defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT)
+ defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \
+ defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
EGLSurface egl_surface;
+#else
+ CoglDisplayKMS kms_display;
+#endif
int egl_surface_width;
int egl_surface_height;
gboolean have_onscreen;
@@ -175,7 +188,11 @@ typedef struct _CoglOnscreenEGL
struct wl_surface *wayland_surface;
#endif
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ CoglOnscreenKMS kms_onscreen;
+#else
EGLSurface egl_surface;
+#endif
} CoglOnscreenEGL;
#ifdef EGL_KHR_image_pixmap
@@ -434,6 +451,11 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
&egl_renderer->egl_version_major,
&egl_renderer->egl_version_minor);
+#elif defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
+ if (!_cogl_winsys_kms_connect (&egl_renderer->kms_renderer, error))
+ goto error;
+ egl_renderer->edpy = egl_renderer->kms_renderer.dpy;
+ status = EGL_TRUE;
#else
egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
@@ -641,12 +663,14 @@ try_create_context (CoglDisplay *display,
CoglXlibRenderer *xlib_renderer = display->renderer->winsys;
#endif
CoglRendererEGL *egl_renderer = display->renderer->winsys;
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
EGLDisplay edpy;
EGLConfig config;
EGLint config_count = 0;
EGLBoolean status;
- EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS];
EGLint attribs[3];
+#endif
+ EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS];
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
XVisualInfo *xvisinfo;
XSetWindowAttributes attrs;
@@ -660,11 +684,12 @@ try_create_context (CoglDisplay *display,
_COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE);
- edpy = egl_renderer->edpy;
-
if (display->renderer->driver == COGL_DRIVER_GL)
eglBindAPI (EGL_OPENGL_API);
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ edpy = egl_renderer->edpy;
+
status = eglChooseConfig (edpy,
cfg_attribs,
&config, 1,
@@ -695,7 +720,7 @@ try_create_context (CoglDisplay *display,
error_message = "Unable to create a suitable EGL context";
goto fail;
}
-
+#endif
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
xvisinfo = get_visual_info (display, config);
@@ -907,14 +932,24 @@ try_create_context (CoglDisplay *display,
EGL_HEIGHT,
&egl_display->egl_surface_height);
+#elif defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
+ if (!_cogl_winsys_kms_create_context (&egl_renderer->kms_renderer,
+ &egl_display->kms_display,
+ error))
+ return FALSE;
+
+ egl_display->egl_surface_width = egl_display->kms_display.width;
+ egl_display->egl_surface_height = egl_display->kms_display.height;
+ egl_display->egl_context = egl_display->kms_display.egl_context;
#else
#error "Unknown EGL platform"
#endif
return TRUE;
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
fail:
-
+#endif
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_CONTEXT,
"%s", error_message);
@@ -930,6 +965,17 @@ cleanup_context (CoglDisplay *display)
CoglXlibDisplay *xlib_display = display->winsys;
CoglXlibRenderer *xlib_renderer = display->renderer->winsys;
#endif
+#if defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
+ GError *error = NULL;
+
+ if (!_cogl_winsys_kms_destroy_context (&egl_renderer->kms_renderer,
+ &egl_display->kms_display,
+ &error))
+ {
+ g_critical (G_STRLOC ": Error cleaning up KMS rendering state: %s", error->message);
+ g_clear_error (&error);
+ }
+#endif
if (egl_display->egl_context != EGL_NO_CONTEXT)
{
@@ -1108,7 +1154,8 @@ _cogl_winsys_display_setup (CoglDisplay *display,
GError **error)
{
CoglDisplayEGL *egl_display;
-#ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
+#if defined (COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT) || \
+ defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
CoglRendererEGL *egl_renderer = display->renderer->winsys;
#endif
@@ -1131,6 +1178,13 @@ _cogl_winsys_display_setup (CoglDisplay *display,
}
#endif
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ if (!_cogl_winsys_kms_display_setup (&egl_renderer->kms_renderer,
+ &egl_display->kms_display,
+ error))
+ goto error;
+#endif
+
if (!create_context (display, error))
goto error;
@@ -1181,19 +1235,24 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
CoglOnscreenXlib *xlib_onscreen;
Window xwin;
#endif
-#ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT
+#if defined (COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT) || \
+ defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
CoglRendererEGL *egl_renderer = display->renderer->winsys;
#endif
CoglOnscreenEGL *egl_onscreen;
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
EGLint attributes[MAX_EGL_CONFIG_ATTRIBS];
EGLConfig egl_config;
EGLint config_count = 0;
EGLBoolean status;
gboolean need_stencil =
egl_display->stencil_disabled ? FALSE : framebuffer->config.need_stencil;
+#endif
_COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
+
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
egl_attributes_from_framebuffer_config (display,
&framebuffer->config,
need_stencil,
@@ -1222,7 +1281,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
g_return_val_if_fail (status == EGL_TRUE, TRUE);
framebuffer->samples_per_pixel = samples;
}
-
+#endif
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
/* FIXME: We need to explicitly Select for ConfigureNotify events.
@@ -1384,7 +1443,8 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \
- defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT)
+ defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT) || \
+ defined (COGL_HAS_EGL_PLATFORM_KMS_SUPPORT)
if (egl_display->have_onscreen)
{
g_set_error (error, COGL_WINSYS_ERROR,
@@ -1393,7 +1453,16 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
return FALSE;
}
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ if (!_cogl_winsys_kms_onscreen_init (cogl_framebuffer_get_context (framebuffer),
+ &egl_renderer->kms_renderer,
+ &egl_display->kms_display,
+ &egl_onscreen->kms_onscreen,
+ error))
+ return FALSE;
+#else
egl_onscreen->egl_surface = egl_display->egl_surface;
+#endif
_cogl_framebuffer_winsys_update_size (framebuffer,
egl_display->egl_surface_width,
@@ -1411,6 +1480,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *context = framebuffer->context;
+ CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
CoglXlibRenderer *xlib_renderer = context->display->renderer->winsys;
CoglXlibTrapState old_state;
@@ -1418,13 +1488,12 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT)
CoglDisplayEGL *egl_display = context->display->winsys;
#endif
- CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
/* If we never successfully allocated then there's nothing to do */
if (egl_onscreen == NULL)
return;
-
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
{
if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface)
@@ -1432,7 +1501,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
g_warning ("Failed to destroy EGL surface");
egl_onscreen->egl_surface = EGL_NO_SURFACE;
}
-
+#endif
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT
egl_display->have_onscreen = FALSE;
#endif
@@ -1469,6 +1538,11 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
}
#endif
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ _cogl_winsys_kms_onscreen_deinit (&egl_renderer->kms_renderer,
+ &egl_onscreen->kms_onscreen);
+#endif
+
g_slice_free (CoglOnscreenEGL, onscreen->winsys);
onscreen->winsys = NULL;
}
@@ -1477,10 +1551,19 @@ static void
_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
{
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
- CoglContextEGL *egl_context = context->winsys;
CoglDisplayEGL *egl_display = context->display->winsys;
CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ CoglContextEGL *egl_context = context->winsys;
+#endif
+
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ _cogl_winsys_kms_bind (&egl_renderer->kms_renderer,
+ &egl_display->kms_display);
+ return;
+
+#else
if (egl_context->current_surface == egl_onscreen->egl_surface)
return;
@@ -1497,6 +1580,7 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT) || \
defined (COGL_HAS_EGL_PLATFORM_GDL_SUPPORT)
+
return;
#else
#error "Unknown EGL platform"
@@ -1515,6 +1599,8 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
eglSwapInterval (egl_renderer->edpy, 1);
else
eglSwapInterval (egl_renderer->edpy, 0);
+
+#endif
}
static void
@@ -1522,6 +1608,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
const int *user_rectangles,
int n_rectangles)
{
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
@@ -1545,6 +1632,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
n_rectangles,
rectangles) == EGL_FALSE)
g_warning ("Error reported by eglSwapBuffersRegion");
+#endif
}
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
@@ -1569,8 +1657,18 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ CoglDisplayEGL *egl_display = context->display->winsys;
+#endif
+#ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
+ _cogl_winsys_kms_swap_buffers (&egl_renderer->kms_renderer,
+ &egl_display->kms_display,
+ &egl_onscreen->kms_onscreen);
+ return;
+#else
eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface);
+#endif
#ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT
/*
@@ -1595,6 +1693,7 @@ _cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
static void
_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
{
+#ifndef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
CoglContextEGL *egl_context = context->winsys;
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
@@ -1603,6 +1702,7 @@ _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
return;
egl_context->current_surface = EGL_NO_SURFACE;
+#endif
_cogl_winsys_onscreen_bind (onscreen);
}
diff --git a/cogl/winsys/cogl-winsys-kms.c b/cogl/winsys/cogl-winsys-kms.c
new file mode 100644
index 00000000..99c8faa2
--- /dev/null
+++ b/cogl/winsys/cogl-winsys-kms.c
@@ -0,0 +1,390 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Some code inspired by mesa demos eglkms.c.
+ *
+ * Authors:
+ * Rob Bradford <rob@linux.intel.com>
+ * Kristian Høgsberg (from eglkms.c)
+ * Benjamin Franzke (from eglkms.c)
+ */
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl.h"
+
+#include "cogl-util.h"
+#include "cogl-winsys-egl-private.h"
+#include "cogl-winsys-private.h"
+#include "cogl-feature-private.h"
+#include "cogl-context-private.h"
+#include "cogl-framebuffer.h"
+#include "cogl-onscreen-private.h"
+#include "cogl-swap-chain-private.h"
+#include "cogl-renderer-private.h"
+#include "cogl-private.h"
+
+#include "cogl-winsys-kms.h"
+
+static const char device_name[] = "/dev/dri/card0";
+
+static gboolean
+setup_kms (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error)
+{
+ drmModeRes *resources;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ int i;
+
+ resources = drmModeGetResources (kms_renderer->fd);
+ if (!resources)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "drmModeGetResources failed");
+ return FALSE;
+ }
+
+ for (i = 0; i < resources->count_connectors; i++)
+ {
+ connector = drmModeGetConnector (kms_renderer->fd, resources->connectors[i]);
+ if (connector == NULL)
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED &&
+ connector->count_modes > 0)
+ break;
+
+ drmModeFreeConnector(connector);
+ }
+
+ if (i == resources->count_connectors)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "No currently active connector found");
+ return FALSE;
+ }
+
+ for (i = 0; i < resources->count_encoders; i++)
+ {
+ encoder = drmModeGetEncoder (kms_renderer->fd, resources->encoders[i]);
+
+ if (encoder == NULL)
+ continue;
+
+ if (encoder->encoder_id == connector->encoder_id)
+ break;
+
+ drmModeFreeEncoder (encoder);
+ }
+
+ kms_display->connector = connector;
+ kms_display->encoder = encoder;
+ kms_display->mode = connector->modes[0];
+
+ kms_display->saved_crtc = drmModeGetCrtc (kms_renderer->fd,
+ kms_display->encoder->crtc_id);
+
+ return TRUE;
+}
+
+gboolean
+_cogl_winsys_kms_connect (CoglRendererKMS *kms_renderer,
+ GError **error)
+{
+ EGLint major, minor;
+
+ kms_renderer->fd = open (device_name, O_RDWR);
+ if (kms_renderer->fd < 0)
+ {
+ /* Probably permissions error */
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "Couldn't open %s", device_name);
+ return FALSE;
+ }
+
+ kms_renderer->gbm = gbm_create_device (kms_renderer->fd);
+ if (kms_renderer->gbm == NULL)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "Couldn't create gbm device");
+ goto close_fd;
+ }
+
+ kms_renderer->dpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm);
+ if (kms_renderer->dpy == EGL_NO_DISPLAY)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "Couldn't get eglDisplay");
+ goto destroy_gbm_device;
+ }
+
+ if (!eglInitialize (kms_renderer->dpy, &major, &minor))
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "Couldn't initialize EGL");
+ goto egl_terminate;
+ }
+
+ return TRUE;
+egl_terminate:
+ eglTerminate (kms_renderer->dpy);
+destroy_gbm_device:
+ gbm_device_destroy (kms_renderer->gbm);
+close_fd:
+ close (kms_renderer->fd);
+
+ return FALSE;
+}
+
+gboolean
+_cogl_winsys_kms_display_setup (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error)
+{
+ if (!setup_kms (kms_renderer, kms_display, error))
+ return FALSE;
+
+ kms_display->width = kms_display->mode.hdisplay;
+ kms_display->height = kms_display->mode.vdisplay;
+
+ return TRUE;
+}
+
+gboolean
+_cogl_winsys_kms_create_context (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error)
+{
+ kms_display->egl_context = eglCreateContext (kms_renderer->dpy, NULL, EGL_NO_CONTEXT, NULL);
+
+ if (kms_display->egl_context == NULL)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Couldn't create EGL context");
+ return FALSE;
+ }
+
+ if (!eglMakeCurrent (kms_renderer->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, kms_display->egl_context))
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Failed to make context current");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_cogl_winsys_kms_onscreen_init (CoglContext *context,
+ CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ CoglOnscreenKMS *kms_onscreen,
+ GError **error)
+{
+ int i;
+
+ kms_onscreen->cogl_context = context;
+
+ context->glGenRenderbuffers (2, kms_onscreen->color_rb);
+
+ for (i = 0; i < 2; i++)
+ {
+ uint32_t handle, stride;
+
+ kms_onscreen->bo[i] =
+ gbm_bo_create (kms_renderer->gbm,
+ kms_display->mode.hdisplay, kms_display->mode.vdisplay,
+ GBM_BO_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ if (!kms_onscreen->bo[i])
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Failed to allocate buffer");
+ return FALSE;
+ }
+
+ kms_onscreen->image[i] = _cogl_egl_create_image (context,
+ EGL_NATIVE_PIXMAP_KHR,
+ kms_onscreen->bo[i],
+ NULL);
+
+ if (kms_onscreen->image[i] == EGL_NO_IMAGE_KHR)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Failed to create EGL image");
+ return FALSE;
+ }
+
+ context->glBindRenderbuffer (GL_RENDERBUFFER_EXT, kms_onscreen->color_rb[i]);
+ context->glEGLImageTargetRenderbufferStorage (GL_RENDERBUFFER, kms_onscreen->image[i]);
+ context->glBindRenderbuffer (GL_RENDERBUFFER_EXT, 0);
+
+ handle = gbm_bo_get_handle (kms_onscreen->bo[i]).u32;
+ stride = gbm_bo_get_pitch (kms_onscreen->bo[i]);
+
+ if (drmModeAddFB (kms_renderer->fd,
+ kms_display->mode.hdisplay, kms_display->mode.vdisplay,
+ 24, 32,
+ stride,
+ handle,
+ &kms_onscreen->fb_id[i]) != 0)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Failed to create framebuffer from buffer");
+ return FALSE;
+ }
+ }
+
+ context->glGenFramebuffers (1, &kms_onscreen->fb);
+ context->glBindFramebuffer (GL_FRAMEBUFFER_EXT, kms_onscreen->fb);
+
+ context->glGenRenderbuffers(1, &kms_onscreen->depth_rb);
+ context->glBindRenderbuffer(GL_RENDERBUFFER_EXT, kms_onscreen->depth_rb);
+ context->glRenderbufferStorage(GL_RENDERBUFFER_EXT,
+ GL_DEPTH_COMPONENT,
+ kms_display->mode.hdisplay, kms_display->mode.vdisplay);
+ context->glBindRenderbuffer (GL_RENDERBUFFER_EXT, 0);
+
+ context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ kms_onscreen->depth_rb);
+
+ kms_onscreen->current_frame = 0;
+ _cogl_winsys_kms_swap_buffers (kms_renderer, kms_display, kms_onscreen);
+
+ return TRUE;
+}
+
+void
+_cogl_winsys_kms_onscreen_deinit (CoglRendererKMS *kms_renderer,
+ CoglOnscreenKMS *kms_onscreen)
+{
+ int i;
+
+ CoglContext *context = kms_onscreen->cogl_context;
+
+ context->glBindFramebuffer (GL_FRAMEBUFFER_EXT, kms_onscreen->fb);
+ context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+ context->glDeleteRenderbuffers(2, kms_onscreen->color_rb);
+ context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+ context->glDeleteRenderbuffers(1, &kms_onscreen->depth_rb);
+
+ for (i = 0; i < 2; i++)
+ {
+ drmModeRmFB (kms_renderer->fd, kms_onscreen->fb_id[i]);
+ _cogl_egl_destroy_image (context, kms_onscreen->image[i]);
+ gbm_bo_destroy (kms_onscreen->bo[i]);
+ }
+}
+
+gboolean
+_cogl_winsys_kms_destroy_context (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error)
+{
+ int ret;
+
+ /* Restore the saved CRTC - this failing should not propagate an error */
+ ret = drmModeSetCrtc (kms_renderer->fd,
+ kms_display->saved_crtc->crtc_id,
+ kms_display->saved_crtc->buffer_id,
+ kms_display->saved_crtc->x, kms_display->saved_crtc->y,
+ &kms_display->connector->connector_id, 1,
+ &kms_display->saved_crtc->mode);
+ if (ret)
+ {
+ g_critical (G_STRLOC ": Error restoring saved CRTC");
+ }
+
+ drmModeFreeCrtc (kms_display->saved_crtc);
+
+ return TRUE;
+}
+
+void
+_cogl_winsys_kms_swap_buffers (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ CoglOnscreenKMS *kms_onscreen)
+{
+ CoglContext *context = kms_onscreen->cogl_context;
+
+ if (drmModeSetCrtc (kms_renderer->fd,
+ kms_display->encoder->crtc_id,
+ kms_onscreen->fb_id[kms_onscreen->current_frame],
+ 0, 0,
+ &kms_display->connector->connector_id,
+ 1,
+ &kms_display->mode) != 0)
+ {
+ g_error (G_STRLOC ": Setting CRTC failed");
+ }
+
+ /* Update frame that we're drawing to be the new one */
+ kms_onscreen->current_frame ^= 1;
+
+ context->glBindFramebuffer (GL_FRAMEBUFFER_EXT, kms_onscreen->fb);
+ context->glFramebufferRenderbuffer (GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT,
+ kms_onscreen->color_rb[kms_onscreen->current_frame]);
+
+ if (context->glCheckFramebufferStatus (GL_FRAMEBUFFER_EXT) !=
+ GL_FRAMEBUFFER_COMPLETE)
+ {
+ g_error (G_STRLOC ": FBO not complete");
+ }
+}
+
+void
+_cogl_winsys_kms_bind (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display)
+{
+ eglMakeCurrent (kms_renderer->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, kms_display->egl_context);
+}
diff --git a/cogl/winsys/cogl-winsys-kms.h b/cogl/winsys/cogl-winsys-kms.h
new file mode 100644
index 00000000..165550bc
--- /dev/null
+++ b/cogl/winsys/cogl-winsys-kms.h
@@ -0,0 +1,99 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Rob Bradford <rob@linux.intel.com>
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <drm.h>
+#include <xf86drmMode.h>
+#include <gbm.h>
+#include <glib.h>
+
+#include "cogl-winsys-private.h"
+
+typedef struct _CoglRendererKMS
+{
+ int fd;
+ struct gbm_device *gbm;
+ EGLDisplay *dpy;
+} CoglRendererKMS;
+
+typedef struct _CoglDisplayKMS
+{
+ EGLContext egl_context;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ drmModeModeInfo mode;
+ drmModeCrtcPtr saved_crtc;
+ gint width, height;
+} CoglDisplayKMS;
+
+typedef struct _CoglOnscreenKMS
+{
+ CoglContext *cogl_context;
+
+ uint32_t fb_id[2];
+ struct gbm_bo *bo[2];
+ GLuint fb, color_rb[2], depth_rb;
+ EGLImageKHR image[2];
+ gint current_frame;
+} CoglOnscreenKMS;
+
+gboolean
+_cogl_winsys_kms_connect (CoglRendererKMS *kms_renderer,
+ GError **error);
+
+gboolean
+_cogl_winsys_kms_onscreen_init (CoglContext *context,
+ CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ CoglOnscreenKMS *kms_onscreen,
+ GError **error);
+void
+_cogl_winsys_kms_onscreen_deinit (CoglRendererKMS *kms_renderer,
+ CoglOnscreenKMS *kms_onscreen);
+
+gboolean
+_cogl_winsys_kms_display_setup (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error);
+
+void
+_cogl_winsys_kms_swap_buffers (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ CoglOnscreenKMS *kms_onscreen);
+
+void
+_cogl_winsys_kms_bind (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display);
+
+gboolean
+_cogl_winsys_kms_create_context (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error);
+
+gboolean
+_cogl_winsys_kms_destroy_context (CoglRendererKMS *kms_renderer,
+ CoglDisplayKMS *kms_display,
+ GError **error);
diff --git a/configure.ac b/configure.ac
index 0f178615..6f3c40f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -755,6 +755,32 @@ AS_IF([test "x$enable_wayland_egl_platform" == "xyes"],
AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_WAYLAND,
[test "x$enable_wayland_egl_platform" = "xyes"])
+
+AC_ARG_ENABLE(
+ [kms-egl-platform],
+ [AC_HELP_STRING([--enable-kms-egl-platform=@<:@no/yes@:>@], [Enable support for the Wayland egl platform @<:@default=no@:>@])],
+ [],
+ enable_kms_egl_platform=no
+)
+AS_IF([test "x$enable_kms_egl_platform" == "xyes"],
+ [
+ EGL_PLATFORM_COUNT=$((EGL_PLATFORM_COUNT+1))
+ NEED_EGL=yes
+ EGL_PLATFORMS="$EGL_PLATFORMS kms"
+
+ PKG_CHECK_EXISTS([gbm],
+ [
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gbm"
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES libdrm"
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gl"
+ ],
+ [AC_MSG_ERROR([Unable to locate required kms libraries])])
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_PLATFORM_KMS_SUPPORT"
+ ])
+AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_KMS,
+ [test "x$enable_kms_egl_platform" = "xyes"])
+
AC_ARG_ENABLE(
[wayland-egl-server],
[AC_HELP_STRING([--enable-wayland-egl-server=@<:@no/yes@:>@], [Enable server side wayland support @<:@default=no@:>@])],