4 * An object oriented GL/GLES Abstraction/Utility Layer
6 * Copyright (C) 2011 Intel Corporation.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 * Robert Bragg <robert@linux.intel.com>
34 #include "cogl-util.h"
35 #include "cogl-internal.h"
36 #include "cogl-private.h"
37 #include "cogl-object.h"
38 #include "cogl-context-private.h"
40 #include "cogl-renderer.h"
41 #include "cogl-renderer-private.h"
42 #include "cogl-display-private.h"
43 #include "cogl-winsys-private.h"
44 #include "cogl-winsys-stub-private.h"
45 #include "cogl-config-private.h"
47 #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT
48 #include "cogl-winsys-egl-x11-private.h"
50 #ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT
51 #include "cogl-winsys-egl-wayland-private.h"
53 #ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
54 #include "cogl-winsys-egl-kms-private.h"
56 #ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
57 #include "cogl-winsys-egl-gdl-private.h"
59 #ifdef COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT
60 #include "cogl-winsys-egl-android-private.h"
62 #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT
63 #include "cogl-winsys-egl-null-private.h"
65 #ifdef COGL_HAS_GLX_SUPPORT
66 #include "cogl-winsys-glx-private.h"
68 #ifdef COGL_HAS_WGL_SUPPORT
69 #include "cogl-winsys-wgl-private.h"
71 #ifdef COGL_HAS_SDL_SUPPORT
72 #include "cogl-winsys-sdl-private.h"
75 #if COGL_HAS_XLIB_SUPPORT
76 #include "cogl-xlib-renderer.h"
79 typedef const CoglWinsysVtable *(*CoglWinsysVtableGetter) (void);
81 static CoglWinsysVtableGetter _cogl_winsys_vtable_getters[] =
83 #ifdef COGL_HAS_GLX_SUPPORT
84 _cogl_winsys_glx_get_vtable,
86 #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT
87 _cogl_winsys_egl_xlib_get_vtable,
89 #ifdef COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT
90 _cogl_winsys_egl_wayland_get_vtable,
92 #ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT
93 _cogl_winsys_egl_kms_get_vtable,
95 #ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
96 _cogl_winsys_egl_gdl_get_vtable,
98 #ifdef COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT
99 _cogl_winsys_egl_android_get_vtable,
101 #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT
102 _cogl_winsys_egl_null_get_vtable,
104 #ifdef COGL_HAS_WGL_SUPPORT
105 _cogl_winsys_wgl_get_vtable,
107 #ifdef COGL_HAS_SDL_SUPPORT
108 _cogl_winsys_sdl_get_vtable,
110 _cogl_winsys_stub_get_vtable,
113 static void _cogl_renderer_free (CoglRenderer *renderer);
115 COGL_OBJECT_DEFINE (Renderer, renderer);
117 typedef struct _CoglNativeFilterClosure
119 CoglNativeFilterFunc func;
121 } CoglNativeFilterClosure;
124 cogl_renderer_error_quark (void)
126 return g_quark_from_static_string ("cogl-renderer-error-quark");
129 static const CoglWinsysVtable *
130 _cogl_renderer_get_winsys (CoglRenderer *renderer)
132 return renderer->winsys_vtable;
136 native_filter_closure_free (CoglNativeFilterClosure *closure)
138 g_slice_free (CoglNativeFilterClosure, closure);
142 _cogl_renderer_free (CoglRenderer *renderer)
144 const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer);
145 winsys->renderer_disconnect (renderer);
147 #ifndef HAVE_DIRECTLY_LINKED_GL_LIBRARY
148 if (renderer->libgl_module)
149 g_module_close (renderer->libgl_module);
152 g_slist_foreach (renderer->event_filters,
153 (GFunc) native_filter_closure_free,
155 g_slist_free (renderer->event_filters);
161 cogl_renderer_new (void)
163 CoglRenderer *renderer = g_new0 (CoglRenderer, 1);
167 renderer->connected = FALSE;
168 renderer->event_filters = NULL;
170 #ifdef COGL_HAS_XLIB_SUPPORT
171 renderer->xlib_enable_event_retrieval = TRUE;
174 return _cogl_renderer_object_new (renderer);
177 #if COGL_HAS_XLIB_SUPPORT
179 cogl_xlib_renderer_set_foreign_display (CoglRenderer *renderer,
182 _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
184 /* NB: Renderers are considered immutable once connected */
185 _COGL_RETURN_IF_FAIL (!renderer->connected);
187 renderer->foreign_xdpy = xdisplay;
189 /* If the application is using a foreign display then we can assume
190 it will also do its own event retrieval */
191 cogl_xlib_renderer_set_event_retrieval_enabled (renderer, FALSE);
195 cogl_xlib_renderer_get_foreign_display (CoglRenderer *renderer)
197 _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL);
199 return renderer->foreign_xdpy;
203 cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer,
206 _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
207 /* NB: Renderers are considered immutable once connected */
208 _COGL_RETURN_IF_FAIL (!renderer->connected);
210 renderer->xlib_enable_event_retrieval = enable;
212 #endif /* COGL_HAS_XLIB_SUPPORT */
215 cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
216 CoglOnscreenTemplate *onscreen_template,
219 CoglDisplay *display;
221 if (!cogl_renderer_connect (renderer, error))
224 display = cogl_display_new (renderer, onscreen_template);
225 if (!cogl_display_setup (display, error))
227 cogl_object_unref (display);
231 cogl_object_unref (display);
237 _cogl_renderer_choose_driver (CoglRenderer *renderer,
240 const char *driver_name = g_getenv ("COGL_DRIVER");
241 const char *libgl_name;
244 driver_name = _cogl_config_driver;
247 if (renderer->driver_override == COGL_DRIVER_GL ||
248 (renderer->driver_override == COGL_DRIVER_ANY &&
249 (driver_name == NULL || !g_ascii_strcasecmp (driver_name, "gl"))))
251 renderer->driver = COGL_DRIVER_GL;
252 libgl_name = COGL_GL_LIBNAME;
257 #ifdef HAVE_COGL_GLES2
258 if (renderer->driver_override == COGL_DRIVER_GLES2 ||
259 (renderer->driver_override == COGL_DRIVER_ANY &&
260 (driver_name == NULL || !g_ascii_strcasecmp (driver_name, "gles2"))))
262 renderer->driver = COGL_DRIVER_GLES2;
263 libgl_name = COGL_GLES2_LIBNAME;
268 #ifdef HAVE_COGL_GLES
269 if (renderer->driver_override == COGL_DRIVER_GLES1 ||
270 (renderer->driver_override == COGL_DRIVER_ANY &&
271 (driver_name == NULL || !g_ascii_strcasecmp (driver_name, "gles1"))))
273 renderer->driver = COGL_DRIVER_GLES1;
274 libgl_name = COGL_GLES1_LIBNAME;
281 COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND,
282 "No suitable driver found");
287 #ifndef HAVE_DIRECTLY_LINKED_GL_LIBRARY
289 renderer->libgl_module = g_module_open (libgl_name,
292 if (renderer->libgl_module == NULL)
294 g_set_error (error, COGL_DRIVER_ERROR,
295 COGL_DRIVER_ERROR_FAILED_TO_LOAD_LIBRARY,
296 "Failed to dynamically open the GL library \"%s\"",
301 #endif /* HAVE_DIRECTLY_LINKED_GL_LIBRARY */
306 /* Final connection API */
309 cogl_renderer_connect (CoglRenderer *renderer, GError **error)
312 GString *error_message;
314 if (renderer->connected)
317 /* The driver needs to be chosen before connecting the renderer
318 because eglInitialize requires the library containing the GL API
319 to be loaded before its called */
320 if (!_cogl_renderer_choose_driver (renderer, error))
323 error_message = g_string_new ("");
324 for (i = 0; i < G_N_ELEMENTS (_cogl_winsys_vtable_getters); i++)
326 const CoglWinsysVtable *winsys = _cogl_winsys_vtable_getters[i]();
327 GError *tmp_error = NULL;
329 gboolean constraints_failed = FALSE;
331 if (renderer->winsys_id_override != COGL_WINSYS_ID_ANY)
333 if (renderer->winsys_id_override != winsys->id)
338 char *user_choice = getenv ("COGL_RENDERER");
340 user_choice = _cogl_config_renderer;
342 g_ascii_strcasecmp (winsys->name, user_choice) != 0)
346 for (l = renderer->constraints; l; l = l->next)
348 CoglRendererConstraint constraint = GPOINTER_TO_UINT (l->data);
349 if (!(winsys->constraints & constraint))
351 constraints_failed = TRUE;
355 if (constraints_failed)
358 /* At least temporarily we will associate this winsys with
359 * the renderer in-case ->renderer_connect calls API that
360 * wants to query the current winsys... */
361 renderer->winsys_vtable = winsys;
363 if (!winsys->renderer_connect (renderer, &tmp_error))
365 g_string_append_c (error_message, '\n');
366 g_string_append (error_message, tmp_error->message);
367 g_error_free (tmp_error);
371 renderer->connected = TRUE;
372 g_string_free (error_message, TRUE);
377 if (!renderer->connected)
379 renderer->winsys_vtable = NULL;
380 g_set_error (error, COGL_WINSYS_ERROR,
381 COGL_WINSYS_ERROR_INIT,
382 "Failed to connected to any renderer: %s",
384 g_string_free (error_message, TRUE);
392 _cogl_renderer_handle_native_event (CoglRenderer *renderer,
397 /* Pass the event on to all of the registered filters in turn */
398 for (l = renderer->event_filters; l; l = next)
400 CoglNativeFilterClosure *closure = l->data;
402 /* The next pointer is taken now so that we can handle the
403 closure being removed during emission */
406 if (closure->func (event, closure->data) == COGL_FILTER_REMOVE)
407 return COGL_FILTER_REMOVE;
410 /* If the backend for the renderer also wants to see the events, it
411 should just register its own filter */
413 return COGL_FILTER_CONTINUE;
417 _cogl_renderer_add_native_filter (CoglRenderer *renderer,
418 CoglNativeFilterFunc func,
421 CoglNativeFilterClosure *closure;
423 closure = g_slice_new (CoglNativeFilterClosure);
424 closure->func = func;
425 closure->data = data;
427 renderer->event_filters = g_slist_prepend (renderer->event_filters, closure);
431 _cogl_renderer_remove_native_filter (CoglRenderer *renderer,
432 CoglNativeFilterFunc func,
435 GSList *l, *prev = NULL;
437 for (l = renderer->event_filters; l; prev = l, l = l->next)
439 CoglNativeFilterClosure *closure = l->data;
441 if (closure->func == func && closure->data == data)
443 native_filter_closure_free (closure);
445 prev->next = g_slist_delete_link (prev->next, l);
447 renderer->event_filters =
448 g_slist_delete_link (renderer->event_filters, l);
455 cogl_renderer_set_winsys_id (CoglRenderer *renderer,
456 CoglWinsysID winsys_id)
458 _COGL_RETURN_IF_FAIL (!renderer->connected);
460 renderer->winsys_id_override = winsys_id;
464 cogl_renderer_get_winsys_id (CoglRenderer *renderer)
466 _COGL_RETURN_VAL_IF_FAIL (renderer->connected, 0);
468 return renderer->winsys_vtable->id;
472 _cogl_renderer_get_proc_address (CoglRenderer *renderer,
475 const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer);
477 return winsys->renderer_get_proc_address (renderer, name);
481 cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer)
485 _COGL_GET_CONTEXT (ctx, 0);
487 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2)
488 if (ctx->driver == COGL_DRIVER_GL || ctx->driver == COGL_DRIVER_GLES2)
489 GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n));
496 cogl_renderer_add_constraint (CoglRenderer *renderer,
497 CoglRendererConstraint constraint)
499 g_return_if_fail (!renderer->connected);
500 renderer->constraints = g_list_prepend (renderer->constraints,
501 GUINT_TO_POINTER (constraint));
505 cogl_renderer_remove_constraint (CoglRenderer *renderer,
506 CoglRendererConstraint constraint)
508 g_return_if_fail (!renderer->connected);
509 renderer->constraints = g_list_remove (renderer->constraints,
510 GUINT_TO_POINTER (constraint));
514 cogl_renderer_set_driver (CoglRenderer *renderer,
517 _COGL_RETURN_IF_FAIL (!renderer->connected);
518 renderer->driver_override = driver;
522 cogl_renderer_get_driver (CoglRenderer *renderer)
524 _COGL_RETURN_VAL_IF_FAIL (renderer->connected, 0);
526 return renderer->driver;