[cogl/wip/rob/kms-winsys] kms: Add first version of "baremetal" backend for EGL on KMS



commit 9fb6f9870f79bd9a53cd77e4c917d089f9762c50
Author: Rob Bradford <rob linux intel com>
Date:   Mon Nov 7 17:16:13 2011 +0000

    kms: Add first version of "baremetal" backend for EGL on KMS
    
    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

 cogl/Makefile.am              |    5 +
 cogl/winsys/cogl-winsys-egl.c |  128 ++++++++++++--
 cogl/winsys/cogl-winsys-kms.c |  388 +++++++++++++++++++++++++++++++++++++++++
 cogl/winsys/cogl-winsys-kms.h |   99 +++++++++++
 configure.ac                  |   26 +++
 5 files changed, 632 insertions(+), 14 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 51f6d42..46a1a8c 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 ec2842b..fe998cc 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 0000000..243d2f1
--- /dev/null
+++ b/cogl/winsys/cogl-winsys-kms.c
@@ -0,0 +1,388 @@
+/*
+ * 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];
+
+  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_display->saved_crtc = drmModeGetCrtc (kms_renderer->fd, kms_display->encoder->crtc_id);
+  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 0000000..165550b
--- /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 0f17861..6f3c40f 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@:>@])],



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]