"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / winsys / cogl-winsys-egl-android.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 <android/native_window.h>
33
34 #include "cogl-winsys-egl-android-private.h"
35 #include "cogl-winsys-egl-private.h"
36 #include "cogl-renderer-private.h"
37 #include "cogl-framebuffer-private.h"
38 #include "cogl-onscreen-private.h"
39 #include "cogl-private.h"
40
41 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
42
43 typedef struct _CoglDisplayAndroid
44 {
45   int egl_surface_width;
46   int egl_surface_height;
47   gboolean have_onscreen;
48 } CoglDisplayAndroid;
49
50 static ANativeWindow *android_native_window;
51
52 void
53 cogl_android_set_native_window (ANativeWindow *window)
54 {
55   _cogl_init ();
56
57   android_native_window = window;
58 }
59
60 static void
61 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
62 {
63   CoglRendererEGL *egl_renderer = renderer->winsys;
64
65   eglTerminate (egl_renderer->edpy);
66
67   g_slice_free (CoglRendererEGL, egl_renderer);
68 }
69
70 static gboolean
71 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
72                                GError **error)
73 {
74   CoglRendererEGL *egl_renderer;
75
76   renderer->winsys = g_slice_new0 (CoglRendererEGL);
77   egl_renderer = renderer->winsys;
78
79   egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
80
81   egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
82
83   if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
84     goto error;
85
86   return TRUE;
87
88 error:
89   _cogl_winsys_renderer_disconnect (renderer);
90   return FALSE;
91 }
92
93 static gboolean
94 _cogl_winsys_egl_context_created (CoglDisplay *display,
95                                   GError **error)
96 {
97   CoglRenderer *renderer = display->renderer;
98   CoglRendererEGL *egl_renderer = renderer->winsys;
99   CoglDisplayEGL *egl_display = display->winsys;
100   CoglDisplayAndroid *android_display = egl_display->platform;
101   const char *error_message;
102   EGLint format;
103
104   if (android_native_window == NULL)
105     {
106       error_message = "No ANativeWindow window specified with "
107         "cogl_android_set_native_window()";
108       goto fail;
109     }
110
111   /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
112    * guaranteed to be accepted by ANativeWindow_setBuffersGeometry ().
113    * As soon as we picked a EGLConfig, we can safely reconfigure the
114    * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
115   eglGetConfigAttrib (egl_renderer->edpy,
116                       egl_display->egl_config,
117                       EGL_NATIVE_VISUAL_ID, &format);
118
119   ANativeWindow_setBuffersGeometry (android_native_window,
120                                     0,
121                                     0,
122                                     format);
123
124   egl_display->egl_surface =
125     eglCreateWindowSurface (egl_renderer->edpy,
126                             egl_display->egl_config,
127                             (NativeWindowType) android_native_window,
128                             NULL);
129   if (egl_display->egl_surface == EGL_NO_SURFACE)
130     {
131       error_message = "Unable to create EGL window surface";
132       goto fail;
133     }
134
135   if (!eglMakeCurrent (egl_renderer->edpy,
136                        egl_display->egl_surface,
137                        egl_display->egl_surface,
138                        egl_display->egl_context))
139     {
140       error_message = "Unable to eglMakeCurrent with egl surface";
141       goto fail;
142     }
143
144   eglQuerySurface (egl_renderer->edpy,
145                    egl_display->egl_surface,
146                    EGL_WIDTH,
147                    &android_display->egl_surface_width);
148
149   eglQuerySurface (egl_renderer->edpy,
150                    egl_display->egl_surface,
151                    EGL_HEIGHT,
152                    &android_display->egl_surface_height);
153
154   return TRUE;
155
156  fail:
157   g_set_error (error, COGL_WINSYS_ERROR,
158                COGL_WINSYS_ERROR_CREATE_CONTEXT,
159                "%s", error_message);
160   return FALSE;
161 }
162
163 static gboolean
164 _cogl_winsys_egl_display_setup (CoglDisplay *display,
165                                 GError **error)
166 {
167   CoglDisplayEGL *egl_display = display->winsys;
168   CoglDisplayAndroid *android_display;
169
170   android_display = g_slice_new0 (CoglDisplayAndroid);
171   egl_display->platform = android_display;
172
173   return TRUE;
174 }
175
176 static void
177 _cogl_winsys_egl_display_destroy (CoglDisplay *display)
178 {
179   CoglDisplayEGL *egl_display = display->winsys;
180
181   g_slice_free (CoglDisplayAndroid, egl_display->platform);
182 }
183
184 static gboolean
185 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
186                                 EGLConfig egl_config,
187                                 GError **error)
188 {
189   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
190   CoglContext *context = framebuffer->context;
191   CoglDisplay *display = context->display;
192   CoglDisplayEGL *egl_display = display->winsys;
193   CoglDisplayAndroid *android_display = egl_display->platform;
194   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
195
196   if (android_display->have_onscreen)
197     {
198       g_set_error (error, COGL_WINSYS_ERROR,
199                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
200                    "EGL platform only supports a single onscreen window");
201       return FALSE;
202     }
203
204   egl_onscreen->egl_surface = egl_display->egl_surface;
205
206   _cogl_framebuffer_winsys_update_size (framebuffer,
207                                         android_display->egl_surface_width,
208                                         android_display->egl_surface_height);
209
210   android_display->have_onscreen = TRUE;
211
212   return TRUE;
213 }
214
215 static const CoglWinsysEGLVtable
216 _cogl_winsys_egl_vtable =
217   {
218     .display_setup = _cogl_winsys_egl_display_setup,
219     .display_destroy = _cogl_winsys_egl_display_destroy,
220     .context_created = _cogl_winsys_egl_context_created,
221     .onscreen_init = _cogl_winsys_egl_onscreen_init,
222   };
223
224 const CoglWinsysVtable *
225 _cogl_winsys_egl_android_get_vtable (void)
226 {
227   static gboolean vtable_inited = FALSE;
228   static CoglWinsysVtable vtable;
229
230   if (!vtable_inited)
231     {
232       /* The EGL_ANDROID winsys is a subclass of the EGL winsys so we
233          start by copying its vtable */
234
235       vtable = *_cogl_winsys_egl_get_vtable ();
236
237       vtable.id = COGL_WINSYS_ID_EGL_ANDROID;
238       vtable.name = "EGL_ANDROID";
239
240       vtable.renderer_connect = _cogl_winsys_renderer_connect;
241       vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect;
242
243       vtable_inited = TRUE;
244     }
245
246   return &vtable;
247 }