/* * 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 . * * Authors: * Tao Zhao * Damien Lespiau */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #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; NativeWindowType window; 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 }; 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; } window = (NativeWindowType) gdl_plane; 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; }