cex100: Add a Clutter EGL backend for CE3100/CE4100 SoCs
authorDamien Lespiau <damien.lespiau@gmail.com>
Thu, 12 Aug 2010 13:25:17 +0000 (09:25 -0400)
committerDamien Lespiau <damien.lespiau@intel.com>
Fri, 3 Sep 2010 10:13:35 +0000 (11:13 +0100)
Intel CE3100 and CE4100 SoCs are designed for TVs. They have separate
framebuffers that are blended together by a piece of hardware to make
the final output. The library that allows you to initialize and
configure those planes is called GDL. A EGL GDL winsys can then be
use with those planes as NativeWindowType to select which plane to use.

This patch adds a new ClutterBackendCex100 backend that can be
selected at compile time with the new --with-flavour=cex100 option.

clutter/cogl/cogl/Makefile.am
clutter/egl/Makefile.am
clutter/egl/clutter-backend-cex100.c [new file with mode: 0644]
clutter/egl/clutter-backend-cex100.h [new file with mode: 0644]
clutter/egl/clutter-backend-egl.c
configure.ac

index 696f3a4..9ba4e4f 100644 (file)
@@ -206,6 +206,10 @@ if SUPPORT_EGL_PLATFORM_POWERVR_NULL
 libclutter_cogl_la_SOURCES += \
        $(srcdir)/winsys/cogl-egl.c
 endif
+if SUPPORT_EGL_PLATFORM_POWERVR_GDL
+libclutter_cogl_la_SOURCES += \
+       $(srcdir)/winsys/cogl-egl.c
+endif
 if SUPPORT_EGL_PLATFORM_FRUITY
 libclutter_cogl_la_SOURCES += \
        $(srcdir)/winsys/cogl-fruity.c
index c3c7842..0559cc9 100644 (file)
@@ -40,3 +40,6 @@ if USE_TSLIB
 libclutter_egl_la_SOURCES += clutter-event-tslib.c
 endif
 
+if SUPPORT_CEX100
+libclutter_egl_la_SOURCES += clutter-backend-cex100.c clutter-backend-cex100.h
+endif
diff --git a/clutter/egl/clutter-backend-cex100.c b/clutter/egl/clutter-backend-cex100.c
new file mode 100644 (file)
index 0000000..aee9b02
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010  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:
+ *   Tao Zhao <tao.zhao@intel.com>
+ *   Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "clutter-debug.h"
+#include "clutter-main.h"
+
+#include "clutter-backend-cex100.h"
+
+static gdl_plane_id_t gdl_plane = GDL_PLANE_ID_UPP_C;
+
+G_DEFINE_TYPE (ClutterBackendCex100,
+               clutter_backend_cex100,
+               CLUTTER_TYPE_BACKEND_EGL)
+
+static gboolean
+gdl_plane_init (gdl_display_id_t   dpy,
+                gdl_plane_id_t     plane,
+                gdl_pixel_format_t pixfmt)
+{
+  gboolean ret = TRUE;
+
+  gdl_color_space_t   colorSpace = GDL_COLOR_SPACE_RGB;
+  gdl_rectangle_t     dstRect;
+  gdl_display_info_t  display_info;
+  gdl_ret_t           rc = GDL_SUCCESS;
+
+  if (GDL_DISPLAY_ID_0 != dpy && GDL_DISPLAY_ID_1 != dpy)
+    {
+      g_warning ("Invalid display ID, must be GDL_DISPLAY_ID_0 or "
+                 "GDL_DISPLAY_ID_1.");
+      return FALSE;
+    }
+
+  /* Init GDL library */
+  rc = gdl_init (NULL);
+  if (rc != GDL_SUCCESS)
+    {
+      g_warning ("GDL initialize failed. %s", gdl_get_error_string (rc));
+      return FALSE;
+    }
+
+  rc = gdl_get_display_info (dpy, &display_info);
+  if (rc != GDL_SUCCESS)
+    {
+      g_warning ("GDL failed to get display infomation: %s",
+                 gdl_get_error_string (rc));
+      gdl_close ();
+      return FALSE;
+    }
+
+  dstRect.origin.x = 0;
+  dstRect.origin.y = 0;
+  dstRect.width = display_info.tvmode.width;
+  dstRect.height = display_info.tvmode.height;
+
+  /* Configure the plane attribute. */
+  rc = gdl_plane_reset (plane);
+  if (rc == GDL_SUCCESS)
+    rc = gdl_plane_config_begin (plane);
+
+  if (rc == GDL_SUCCESS)
+    rc = gdl_plane_set_attr (GDL_PLANE_SRC_COLOR_SPACE, &colorSpace);
+
+  if (rc == GDL_SUCCESS)
+    rc = gdl_plane_set_attr (GDL_PLANE_PIXEL_FORMAT, &pixfmt);
+
+  if (rc == GDL_SUCCESS)
+    rc = gdl_plane_set_attr (GDL_PLANE_DST_RECT, &dstRect);
+
+#if 0
+  /*
+   * Change the number of back buffers for the eglWindowSurface, Default
+   * value is 3, could be changed to 2, means one front buffer and one back
+   * buffer.
+   *
+   * TODO: Make a new API to tune that;
+   */
+  if (rc == GDL_SUCCESS)
+    rc = gdl_plane_set_uint (GDL_PLANE_NUM_GFX_SURFACES, 2);
+#endif
+
+  if (rc == GDL_SUCCESS)
+    rc = gdl_plane_config_end (GDL_FALSE);
+  else
+    gdl_plane_config_end (GDL_TRUE);
+
+  if (rc != GDL_SUCCESS)
+    {
+      g_warning ("GDL configuration failed: %s.", gdl_get_error_string (rc));
+      ret = FALSE;
+    }
+
+  gdl_close ();
+
+  return ret;
+}
+
+/*
+ * ClutterBackendEGL implementation
+ */
+
+static gboolean
+clutter_backend_cex100_create_context (ClutterBackend  *backend,
+                                      GError         **error)
+{
+  ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
+  EGLConfig configs[2];
+  EGLint config_count;
+  EGLBoolean status;
+
+  if (backend_egl->egl_context != EGL_NO_CONTEXT)
+    return TRUE;
+
+  /* Start by initializing the GDL plane */
+  if (!gdl_plane_init (GDL_DISPLAY_ID_0, gdl_plane, GDL_PF_ARGB_32))
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "Could not initialize the GDL plane");
+      return FALSE;
+    }
+
+  NativeWindowType window = (NativeWindowType) gdl_plane;
+  EGLint cfg_attribs[] = {
+      EGL_BUFFER_SIZE,     EGL_DONT_CARE,
+      EGL_RED_SIZE,        8,
+      EGL_GREEN_SIZE,      8,
+      EGL_BLUE_SIZE,       8,
+      EGL_DEPTH_SIZE,      16,
+      EGL_ALPHA_SIZE,      8,
+      EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
+      EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
+#ifdef HAVE_COGL_GLES2
+      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+#else /* HAVE_COGL_GLES2 */
+      EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
+#endif /* HAVE_COGL_GLES2 */
+      EGL_NONE
+  };
+
+  status = eglGetConfigs (backend_egl->edpy,
+                          configs,
+                          2,
+                          &config_count);
+
+  if (status != EGL_TRUE)
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "No EGL configurations found");
+      return FALSE;
+    }
+
+  status = eglChooseConfig (backend_egl->edpy,
+                            cfg_attribs,
+                            configs,
+                            G_N_ELEMENTS (configs),
+                            &config_count);
+
+  if (status != EGL_TRUE)
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "Unable to select a valid EGL configuration");
+      return FALSE;
+    }
+
+  CLUTTER_NOTE (BACKEND, "Got %i configs", config_count);
+
+  if (status != EGL_TRUE)
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "Unable to Make Current Context for NULL");
+      return FALSE;
+    }
+
+  if (G_UNLIKELY (backend_egl->egl_surface != EGL_NO_SURFACE))
+    {
+      eglDestroySurface (backend_egl->edpy, backend_egl->egl_surface);
+      backend_egl->egl_surface = EGL_NO_SURFACE;
+    }
+
+  if (G_UNLIKELY (backend_egl->egl_context != NULL))
+    {
+      eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
+      backend_egl->egl_context = NULL;
+    }
+
+  backend_egl->egl_surface = eglCreateWindowSurface (backend_egl->edpy,
+                                                     configs[0],
+                                                     window,
+                                                     NULL);
+
+  if (backend_egl->egl_surface == EGL_NO_SURFACE)
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "Unable to create EGL window surface");
+
+      return FALSE;
+    }
+
+#ifdef HAVE_COGL_GLES2
+    {
+      static const EGLint attribs[3] = {
+          EGL_CONTEXT_CLIENT_VERSION, 2,
+          EGL_NONE
+      };
+
+      backend_egl->egl_context = eglCreateContext (backend_egl->edpy,
+                                                   configs[0],
+                                                   EGL_NO_CONTEXT,
+                                                   attribs);
+    }
+#else
+  /* Seems some GLES implementations 1.x do not like attribs... */
+  backend_egl->egl_context = eglCreateContext (backend_egl->edpy,
+                                               configs[0],
+                                               EGL_NO_CONTEXT,
+                                               NULL);
+#endif
+
+  if (backend_egl->egl_context == EGL_NO_CONTEXT)
+    {
+      g_set_error (error, CLUTTER_INIT_ERROR,
+                   CLUTTER_INIT_ERROR_BACKEND,
+                   "Unable to create a suitable EGL context");
+      return FALSE;
+    }
+
+  CLUTTER_NOTE (GL, "Created EGL Context");
+
+  CLUTTER_NOTE (BACKEND, "Setting context");
+
+  /*
+   * eglnative can have only one stage, so we store the EGL surface in the
+   * backend itself, instead of the StageWindow implementation, and we make it
+   * current immediately to make sure the Cogl and Clutter can query the EGL
+   * context for features.
+   */
+  status = eglMakeCurrent (backend_egl->edpy,
+                           backend_egl->egl_surface,
+                           backend_egl->egl_surface,
+                           backend_egl->egl_context);
+
+  eglQuerySurface (backend_egl->edpy,
+                   backend_egl->egl_surface,
+                   EGL_WIDTH,
+                   &backend_egl->surface_width);
+
+  eglQuerySurface (backend_egl->edpy,
+                   backend_egl->egl_surface,
+                   EGL_HEIGHT,
+                   &backend_egl->surface_height);
+
+  CLUTTER_NOTE (BACKEND, "EGL surface is %ix%i",
+                backend_egl->surface_width,
+                backend_egl->surface_height);
+
+  /*
+   * For EGL backend, it needs to clear all the back buffers of the window
+   * surface before drawing anything, otherwise the image will be blinking
+   * heavily.  The default eglWindowSurface has 3 gdl surfaces as the back
+   * buffer, that's why glClear should be called 3 times.
+   */
+  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
+  glClear (GL_COLOR_BUFFER_BIT);
+  eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
+
+  glClear (GL_COLOR_BUFFER_BIT);
+  eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
+
+  glClear (GL_COLOR_BUFFER_BIT);
+  eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
+
+  return TRUE;
+}
+
+/*
+ * GObject implementation
+ */
+
+static void
+clutter_backend_cex100_class_init (ClutterBackendCex100Class *klass)
+{
+  ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
+
+  backend_class->create_context   = clutter_backend_cex100_create_context;
+}
+
+static void
+clutter_backend_cex100_init (ClutterBackendCex100 *self)
+{
+}
+
+/* every backend must implement this function */
+GType
+_clutter_backend_impl_get_type (void)
+{
+  return clutter_backend_cex100_get_type ();
+}
diff --git a/clutter/egl/clutter-backend-cex100.h b/clutter/egl/clutter-backend-cex100.h
new file mode 100644 (file)
index 0000000..79e03d0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010  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/>.
+ *
+ * Author:
+ *   Damien Lespiau <damien.lespiau@intel.com>
+ */
+
+#ifndef __CLUTTER_BACKEND_CEX100_H__
+#define __CLUTTER_BACKEND_CEX100_H__
+
+#include <libgdl.h>
+
+#include <glib-object.h>
+
+#include <clutter/egl/clutter-backend-egl.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_BACKEND_CEX100             (clutter_backend_cex100_get_type())
+#define CLUTTER_BACKEND_CEX100(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_CEX100, ClutterBackendCex100))
+#define CLUTTER_BACKEND_CEX100_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_CEX100, ClutterBackendCex100Class))
+#define CLUTTER_IS_BACKEND_CEX100(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_CEX100))
+#define CLUTTER_IS_BACKEND_CEX100_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_CEX100))
+#define CLUTTER_BACKEND_CEX100_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_CEX100, ClutterBackendCex100Class))
+
+typedef struct _ClutterBackendCex100 ClutterBackendCex100;
+typedef struct _ClutterBackendCex100Class ClutterBackendCex100Class;
+
+struct _ClutterBackendCex100
+{
+  ClutterBackendEGL parent;
+};
+
+struct _ClutterBackendCex100Class
+{
+  ClutterBackendEGLClass parent_class;
+};
+
+GType   clutter_backend_cex100_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BACKEND_CEX100_H__ */
index d5e8ad5..dafa685 100644 (file)
@@ -780,11 +780,13 @@ _clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
 #endif
 }
 
+#ifdef CLUTTER_EGL_BACKEND_GENERIC
 GType
 _clutter_backend_impl_get_type (void)
 {
   return _clutter_backend_egl_get_type ();
 }
+#endif
 
 #ifdef COGL_HAS_XLIB_SUPPORT
 EGLDisplay
index 6465596..5b241a5 100644 (file)
@@ -138,7 +138,7 @@ experimental_backend=no
 experimental_image=no
 
 AC_ARG_WITH([flavour],
-            [AC_HELP_STRING([--with-flavour=@<:@glx/opengl-egl-xlib/eglx/eglnative/osx/win32/fruity@:>@],
+            [AC_HELP_STRING([--with-flavour=@<:@glx/opengl-egl-xlib/eglx/eglnative/osx/win32/fruity/cex100@:>@],
                             [Select the Clutter window system backend])],
             [CLUTTER_FLAVOUR=$with_flavour])
 
@@ -194,6 +194,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
         [
           cogl_gl_headers="GL/gl.h"
           CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGL"
+          CLUTTER_EGL_BACKEND="generic"
 
           SUPPORT_X11=1
           SUPPORT_XLIB=1
@@ -217,6 +218,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
         [
           # the GL header is defined in the COGL checks above
           CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGL"
+          CLUTTER_EGL_BACKEND="generic"
 
           SUPPORT_X11=1
           SUPPORT_XLIB=1
@@ -235,6 +237,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
         [
           # the GL header is defined in the COGL checks above
           CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGLNATIVE"
+          CLUTTER_EGL_BACKEND="cex100"
 
           SUPPORT_EGL=1
           SUPPORT_EGL_PLATFORM_POWERVR_NULL=1
@@ -253,6 +256,35 @@ AS_CASE([$CLUTTER_FLAVOUR],
           CLUTTER_SONAME_INFIX=eglnative
         ],
 
+        [cex100],
+        [
+          CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_EGL"
+
+          SUPPORT_EGL=1
+          SUPPORT_EGL_PLATFORM_POWERVR_GDL=1
+
+          COGL_DRIVER="gles"
+
+          # The cex100 is a small specialization of the EGL backend
+          CLUTTER_WINSYS=egl
+          CLUTTER_SONAME_INFIX=cex100
+
+          found_gdl=no
+          AC_CHECK_HEADERS([libgdl.h], found_gdl=yes)
+          AS_IF([test x"$found_gdl" = "xno"],
+                AC_CHECK_HEADERS([CE4100/libgdl.h],
+                                 [
+                                   FLAVOUR_CFLAGS="-I/usr/include/CE4100"
+                                   found_gdl=yes
+                                 ])
+               )
+
+          AS_IF([test x"$found_gdl" = "xno"],
+                AC_MSG_ERROR([libgdl.h not found]))
+
+          FLAVOUR_LIBS="$FLAVOUR_LIBS -lgdl"
+        ],
+
         [fruity],
         [
           experimental_backend="yes"
@@ -343,6 +375,12 @@ AS_IF([test "x$SUPPORT_EGL" = "x1"],
         AC_DEFINE([COGL_HAS_EGL_SUPPORT], [1], [Cogl supports GLES using the EGL API])
       ])
 
+AS_IF([test "x$CLUTTER_EGL_BACKEND" = "xgeneric"],
+      AC_DEFINE([CLUTTER_EGL_BACKEND_GENERIC], [1], [Use Generic EGL backend]))
+
+AS_IF([test "x$CLUTTER_EGL_BACKEND" = "xcex100"],
+      AC_DEFINE([CLUTTER_EGL_BACKEND_CEX100], [1], [Use CEX100 EGL backend]))
+
 AS_IF([test "x$SUPPORT_EGL_POWERVR_X11" = "x1"],
       [
         AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT], [1],
@@ -355,6 +393,13 @@ AS_IF([test "x$SUPPORT_EGL_POWERVR_NULL" = "x1"],
                   [Cogl supports OpenGLES using the EGL API with PowerVR NULL platform typedefs])
       ])
 
+AS_IF([test "x$SUPPORT_EGL_POWERVR_GDL" = "x1"],
+      [
+        AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_GDL_SUPPORT], [1],
+                  [Cogl supports OpenGLES using the EGL API with PowerVR GDL platform typedefs])
+      ])
+
+
 # winsys conditionals for use in automake files...
 AM_CONDITIONAL(SUPPORT_GLX, [test "x$SUPPORT_GLX" = "x1"])
 AM_CONDITIONAL(SUPPORT_X11, [test "x$SUPPORT_X11" = "x1"])
@@ -362,9 +407,11 @@ AM_CONDITIONAL(SUPPORT_XLIB, [test "x$SUPPORT_XLIB" = "x1"])
 AM_CONDITIONAL(SUPPORT_EGL, [test "x$SUPPORT_EGL" = "x1"])
 AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_POWERVR_X11, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_X11" = "x1"])
 AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_POWERVR_NULL, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_NULL" = "x1"])
+AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_POWERVR_GDL, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"])
 AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_FRUITY, [test "x$CLUTTER_WINSYS" = "xfruity"])
 AM_CONDITIONAL(SUPPORT_OSX, [test "x$CLUTTER_WINSYS" = "xosx"])
 AM_CONDITIONAL(SUPPORT_WIN32, [test "x$CLUTTER_WINSYS" = "xwin32"])
+AM_CONDITIONAL(SUPPORT_CEX100, [test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"])
 
 dnl === COGL driver backend =====================================================