mutter/clutter/egl/clutter-backend-cex100.c
Damien Lespiau 0a0a59cf7b cex100: Add an API to configure the buffering mode of the GDL plane
GDL planes can be double or triple buffered. Let the user choose between
the two modes befored initalizing Clutter.
2010-09-03 11:13:35 +01:00

369 lines
10 KiB
C

/*
* 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"
#include "clutter-cex100.h"
static gdl_plane_id_t gdl_plane = GDL_PLANE_ID_UPP_C;
static guint gdl_n_buffers = CLUTTER_CEX100_TRIPLE_BUFFERING;
G_DEFINE_TYPE (ClutterBackendCex100,
clutter_backend_cex100,
CLUTTER_TYPE_BACKEND_EGL)
#ifdef CLUTTER_ENABLE_DEBUG
static const gchar *
gdl_get_plane_name (gdl_plane_id_t plane)
{
switch (plane)
{
case GDL_PLANE_ID_UPP_A:
return "UPP_A";
case GDL_PLANE_ID_UPP_B:
return "UPP_B";
case GDL_PLANE_ID_UPP_C:
return "UPP_C";
case GDL_PLANE_ID_UPP_D:
return "UPP_D";
case GDL_PLANE_ID_UPP_E:
return "UPP_E";
default:
g_assert_not_reached ();
}
return NULL; /* never reached */
}
#endif
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 (rc == GDL_SUCCESS)
rc = gdl_plane_set_uint (GDL_PLANE_NUM_GFX_SURFACES, gdl_n_buffers);
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;
CLUTTER_NOTE (BACKEND, "Using the %s plane", gdl_get_plane_name (gdl_plane));
/* 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 ();
}
void
clutter_cex100_set_plane (gdl_plane_id_t plane)
{
g_return_if_fail (plane >= GDL_PLANE_ID_UPP_A && plane <= GDL_PLANE_ID_UPP_E);
gdl_plane = plane;
}
void
clutter_cex100_set_buffering_mode (ClutterCex100BufferingMode mode)
{
g_return_if_fail (mode == CLUTTER_CEX100_DOUBLE_BUFFERING ||
mode == CLUTTER_CEX100_TRIPLE_BUFFERING);
gdl_n_buffers = mode;
}