"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / winsys / cogl-winsys-egl-gdl.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2011 Intel Corporation.
7  *
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.
12  *
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.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see
20  * <http://www.gnu.org/licenses/>.
21  *
22  *
23  * Authors:
24  *   Robert Bragg <robert@linux.intel.com>
25  *   Neil Roberts <neil@linux.intel.com>
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "cogl-winsys-egl-gdl-private.h"
33 #include "cogl-winsys-egl-private.h"
34 #include "cogl-renderer-private.h"
35 #include "cogl-framebuffer-private.h"
36 #include "cogl-onscreen-private.h"
37 #include "cogl-onscreen-template-private.h"
38 #include "cogl-swap-chain-private.h"
39
40 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
41
42 typedef struct _CoglRendererGDL
43 {
44   gboolean gdl_initialized;
45 } CoglRendererGDL;
46
47 typedef struct _CoglDisplayGDL
48 {
49   int egl_surface_width;
50   int egl_surface_height;
51   gboolean have_onscreen;
52 } CoglDisplayGDL;
53
54 static void
55 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
56 {
57   CoglRendererEGL *egl_renderer = renderer->winsys;
58   CoglRendererGDL *gdl_renderer = egl_renderer->platform;
59
60   if (gdl_renderer->gdl_initialized)
61     gdl_close ();
62
63   eglTerminate (egl_renderer->edpy);
64
65   g_slice_free (CoglRendererEGL, egl_renderer);
66 }
67
68 static gboolean
69 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
70                                GError **error)
71 {
72   CoglRendererEGL *egl_renderer;
73   CoglRendererGDL *gdl_renderer;
74   gdl_ret_t rc = GDL_SUCCESS;
75   gdl_display_info_t gdl_display_info;
76
77   renderer->winsys = g_slice_new0 (CoglRendererEGL);
78   egl_renderer = renderer->winsys;
79
80   gdl_renderer = g_slice_new0 (CoglRendererGDL);
81   egl_renderer->platform = gdl_renderer;
82
83   egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
84
85   egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
86
87   if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
88     goto error;
89
90   /* Check we can talk to the GDL library */
91   rc = gdl_init (NULL);
92   if (rc != GDL_SUCCESS)
93     {
94       g_set_error (error, COGL_WINSYS_ERROR,
95                    COGL_WINSYS_ERROR_INIT,
96                    "GDL initialize failed. %s",
97                    gdl_get_error_string (rc));
98       goto error;
99     }
100
101   rc = gdl_get_display_info (GDL_DISPLAY_ID_0, &gdl_display_info);
102   if (rc != GDL_SUCCESS)
103     {
104       g_set_error (error, COGL_WINSYS_ERROR,
105                    COGL_WINSYS_ERROR_INIT,
106                    "GDL failed to get display information: %s",
107                    gdl_get_error_string (rc));
108       gdl_close ();
109       goto error;
110     }
111
112   gdl_close ();
113
114   return TRUE;
115
116 error:
117   _cogl_winsys_renderer_disconnect (renderer);
118   return FALSE;
119 }
120
121 static gboolean
122 _cogl_winsys_egl_context_created (CoglDisplay *display,
123                                   GError **error)
124 {
125   CoglRenderer *renderer = display->renderer;
126   CoglRendererEGL *egl_renderer = renderer->winsys;
127   CoglDisplayEGL *egl_display = display->winsys;
128   CoglDisplayGDL *gdl_display = egl_display->platform;
129   const char *error_message;
130
131   egl_display->egl_surface =
132     eglCreateWindowSurface (egl_renderer->edpy,
133                             egl_display->egl_config,
134                             (NativeWindowType) display->gdl_plane,
135                             NULL);
136
137   if (egl_display->egl_surface == EGL_NO_SURFACE)
138     {
139       error_message = "Unable to create EGL window surface";
140       goto fail;
141     }
142
143   if (!eglMakeCurrent (egl_renderer->edpy,
144                        egl_display->egl_surface,
145                        egl_display->egl_surface,
146                        egl_display->egl_context))
147     {
148       error_message = "Unable to eglMakeCurrent with egl surface";
149       goto fail;
150     }
151
152   eglQuerySurface (egl_renderer->edpy,
153                    egl_display->egl_surface,
154                    EGL_WIDTH,
155                    &gdl_display->egl_surface_width);
156
157   eglQuerySurface (egl_renderer->edpy,
158                    egl_display->egl_surface,
159                    EGL_HEIGHT,
160                    &gdl_display->egl_surface_height);
161
162   return TRUE;
163
164  fail:
165   g_set_error (error, COGL_WINSYS_ERROR,
166                COGL_WINSYS_ERROR_CREATE_CONTEXT,
167                "%s", error_message);
168   return FALSE;
169 }
170
171 static gboolean
172 gdl_plane_init (CoglDisplay *display, GError **error)
173 {
174   gboolean ret = TRUE;
175   gdl_color_space_t colorSpace = GDL_COLOR_SPACE_RGB;
176   gdl_pixel_format_t pixfmt = GDL_PF_ARGB_32;
177   gdl_rectangle_t dstRect;
178   gdl_display_info_t display_info;
179   gdl_ret_t rc = GDL_SUCCESS;
180
181   if (!display->gdl_plane)
182     {
183       g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
184                    "No GDL plane specified with "
185                    "cogl_gdl_display_set_plane");
186       return FALSE;
187     }
188
189   rc = gdl_init (NULL);
190   if (rc != GDL_SUCCESS)
191     {
192       g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
193                    "GDL initialize failed. %s", gdl_get_error_string (rc));
194       return FALSE;
195     }
196
197   rc = gdl_get_display_info (GDL_DISPLAY_ID_0, &display_info);
198   if (rc != GDL_SUCCESS)
199     {
200       g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
201                    "GDL failed to get display infomation: %s",
202                    gdl_get_error_string (rc));
203       gdl_close ();
204       return FALSE;
205     }
206
207   dstRect.origin.x = 0;
208   dstRect.origin.y = 0;
209   dstRect.width = display_info.tvmode.width;
210   dstRect.height = display_info.tvmode.height;
211
212   /* Configure the plane attribute. */
213   rc = gdl_plane_reset (display->gdl_plane);
214   if (rc == GDL_SUCCESS)
215     rc = gdl_plane_config_begin (display->gdl_plane);
216
217   if (rc == GDL_SUCCESS)
218     rc = gdl_plane_set_attr (GDL_PLANE_SRC_COLOR_SPACE, &colorSpace);
219
220   if (rc == GDL_SUCCESS)
221     rc = gdl_plane_set_attr (GDL_PLANE_PIXEL_FORMAT, &pixfmt);
222
223   if (rc == GDL_SUCCESS)
224     rc = gdl_plane_set_attr (GDL_PLANE_DST_RECT, &dstRect);
225
226   /* Default to triple buffering if the swap_chain doesn't have an explicit
227    * length */
228   if (rc == GDL_SUCCESS)
229     {
230       if (display->onscreen_template->config.swap_chain &&
231           display->onscreen_template->config.swap_chain->length != -1)
232         rc = gdl_plane_set_uint (GDL_PLANE_NUM_GFX_SURFACES,
233                                  display->onscreen_template->
234                                  config.swap_chain->length);
235       else
236         rc = gdl_plane_set_uint (GDL_PLANE_NUM_GFX_SURFACES, 3);
237     }
238
239   if (rc == GDL_SUCCESS)
240     rc = gdl_plane_config_end (GDL_FALSE);
241   else
242     gdl_plane_config_end (GDL_TRUE);
243
244   if (rc != GDL_SUCCESS)
245     {
246       g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
247                    "GDL configuration failed: %s.", gdl_get_error_string (rc));
248       ret = FALSE;
249     }
250
251   gdl_close ();
252
253   return ret;
254 }
255
256 static gboolean
257 _cogl_winsys_egl_display_setup (CoglDisplay *display,
258                                 GError **error)
259 {
260   CoglDisplayEGL *egl_display = display->winsys;
261   CoglDisplayGDL *gdl_display;
262
263   gdl_display = g_slice_new0 (CoglDisplayGDL);
264   egl_display->platform = gdl_display;
265
266   if (!gdl_plane_init (display, error))
267     return FALSE;
268
269   return TRUE;
270 }
271
272 static void
273 _cogl_winsys_egl_display_destroy (CoglDisplay *display)
274 {
275   CoglDisplayEGL *egl_display = display->winsys;
276
277   g_slice_free (CoglDisplayGDL, egl_display->platform);
278 }
279
280 static void
281 _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
282 {
283   CoglRenderer *renderer = display->renderer;
284   CoglRendererEGL *egl_renderer = renderer->winsys;
285   CoglDisplayEGL *egl_display = display->winsys;
286
287   if (egl_display->egl_surface != EGL_NO_SURFACE)
288     {
289       eglDestroySurface (egl_renderer->edpy, egl_display->egl_surface);
290       egl_display->egl_surface = EGL_NO_SURFACE;
291     }
292 }
293
294 static gboolean
295 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
296                                 EGLConfig egl_config,
297                                 GError **error)
298 {
299   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
300   CoglContext *context = framebuffer->context;
301   CoglDisplay *display = context->display;
302   CoglDisplayEGL *egl_display = display->winsys;
303   CoglDisplayGDL *gdl_display = egl_display->platform;
304   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
305
306   if (gdl_display->have_onscreen)
307     {
308       g_set_error (error, COGL_WINSYS_ERROR,
309                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
310                    "EGL platform only supports a single onscreen window");
311       return FALSE;
312     }
313
314   egl_onscreen->egl_surface = egl_display->egl_surface;
315
316   _cogl_framebuffer_winsys_update_size (framebuffer,
317                                         gdl_display->egl_surface_width,
318                                         gdl_display->egl_surface_height);
319   gdl_display->have_onscreen = TRUE;
320
321   return TRUE;
322 }
323
324 static int
325 _cogl_winsys_egl_add_config_attributes (CoglDisplay *display,
326                                         CoglFramebufferConfig *config,
327                                         EGLint *attributes)
328 {
329   int i = 0;
330
331   /* XXX: Why does the GDL platform choose these by default? */
332   attributes[i++] = EGL_BIND_TO_TEXTURE_RGBA;
333   attributes[i++] = EGL_TRUE;
334   attributes[i++] = EGL_BIND_TO_TEXTURE_RGB;
335   attributes[i++] = EGL_TRUE;
336
337   return i;
338 }
339
340 static const CoglWinsysEGLVtable
341 _cogl_winsys_egl_vtable =
342   {
343     .display_setup = _cogl_winsys_egl_display_setup,
344     .display_destroy = _cogl_winsys_egl_display_destroy,
345     .context_created = _cogl_winsys_egl_context_created,
346     .cleanup_context = _cogl_winsys_egl_cleanup_context,
347     .onscreen_init = _cogl_winsys_egl_onscreen_init,
348     .add_config_attributes = _cogl_winsys_egl_add_config_attributes
349   };
350
351 const CoglWinsysVtable *
352 _cogl_winsys_egl_gdl_get_vtable (void)
353 {
354   static gboolean vtable_inited = FALSE;
355   static CoglWinsysVtable vtable;
356
357   if (!vtable_inited)
358     {
359       /* The EGL_GDL winsys is a subclass of the EGL winsys so we
360          start by copying its vtable */
361
362       vtable = *_cogl_winsys_egl_get_vtable ();
363
364       vtable.id = COGL_WINSYS_ID_EGL_GDL;
365       vtable.name = "EGL_GDL";
366
367       vtable.renderer_connect = _cogl_winsys_renderer_connect;
368       vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect;
369
370       vtable_inited = TRUE;
371     }
372
373   return &vtable;
374 }