1 /*
2 * Cogl
3 *
4 * A Low Level GPU Graphics and Utilities API
5 *
6 * Copyright (C) 2011 Intel Corporation.
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 *
29 * Authors:
30 * Robert Bragg <robert@linux.intel.com>
31 * Neil Roberts <neil@linux.intel.com>
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <android/native_window.h>
39
40 #include "cogl-winsys-egl-android-private.h"
41 #include "cogl-winsys-egl-private.h"
42 #include "cogl-renderer-private.h"
43 #include "cogl-framebuffer-private.h"
44 #include "cogl-onscreen-private.h"
45 #include "cogl-private.h"
46
47 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
48
49 typedef struct _CoglDisplayAndroid
50 {
51 int egl_surface_width;
52 int egl_surface_height;
53 CoglBool have_onscreen;
54 } CoglDisplayAndroid;
55
56 static ANativeWindow *android_native_window;
57
58 void
cogl_android_set_native_window(ANativeWindow * window)59 cogl_android_set_native_window (ANativeWindow *window)
60 {
61 _cogl_init ();
62
63 android_native_window = window;
64 }
65
66 static void
_cogl_winsys_renderer_disconnect(CoglRenderer * renderer)67 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
68 {
69 CoglRendererEGL *egl_renderer = renderer->winsys;
70
71 eglTerminate (egl_renderer->edpy);
72
73 g_slice_free (CoglRendererEGL, egl_renderer);
74 }
75
76 static CoglBool
_cogl_winsys_renderer_connect(CoglRenderer * renderer,CoglError ** error)77 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
78 CoglError **error)
79 {
80 CoglRendererEGL *egl_renderer;
81
82 renderer->winsys = g_slice_new0 (CoglRendererEGL);
83 egl_renderer = renderer->winsys;
84
85 egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
86
87 egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
88
89 if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
90 goto error;
91
92 return TRUE;
93
94 error:
95 _cogl_winsys_renderer_disconnect (renderer);
96 return FALSE;
97 }
98
99 static CoglBool
_cogl_winsys_egl_context_created(CoglDisplay * display,CoglError ** error)100 _cogl_winsys_egl_context_created (CoglDisplay *display,
101 CoglError **error)
102 {
103 CoglRenderer *renderer = display->renderer;
104 CoglRendererEGL *egl_renderer = renderer->winsys;
105 CoglDisplayEGL *egl_display = display->winsys;
106 CoglDisplayAndroid *android_display = egl_display->platform;
107 const char *error_message;
108 EGLint format;
109
110 if (android_native_window == NULL)
111 {
112 error_message = "No ANativeWindow window specified with "
113 "cogl_android_set_native_window()";
114 goto fail;
115 }
116
117 /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
118 * guaranteed to be accepted by ANativeWindow_setBuffersGeometry ().
119 * As soon as we picked a EGLConfig, we can safely reconfigure the
120 * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
121 eglGetConfigAttrib (egl_renderer->edpy,
122 egl_display->egl_config,
123 EGL_NATIVE_VISUAL_ID, &format);
124
125 ANativeWindow_setBuffersGeometry (android_native_window,
126 0,
127 0,
128 format);
129
130 egl_display->egl_surface =
131 eglCreateWindowSurface (egl_renderer->edpy,
132 egl_display->egl_config,
133 (EGLNativeWindowType) android_native_window,
134 NULL);
135 if (egl_display->egl_surface == EGL_NO_SURFACE)
136 {
137 error_message = "Unable to create EGL window surface";
138 goto fail;
139 }
140
141 if (!_cogl_winsys_egl_make_current (display,
142 egl_display->egl_surface,
143 egl_display->egl_surface,
144 egl_display->egl_context))
145 {
146 error_message = "Unable to eglMakeCurrent with egl surface";
147 goto fail;
148 }
149
150 eglQuerySurface (egl_renderer->edpy,
151 egl_display->egl_surface,
152 EGL_WIDTH,
153 &android_display->egl_surface_width);
154
155 eglQuerySurface (egl_renderer->edpy,
156 egl_display->egl_surface,
157 EGL_HEIGHT,
158 &android_display->egl_surface_height);
159
160 return TRUE;
161
162 fail:
163 _cogl_set_error (error, COGL_WINSYS_ERROR,
164 COGL_WINSYS_ERROR_CREATE_CONTEXT,
165 "%s", error_message);
166 return FALSE;
167 }
168
169 static CoglBool
_cogl_winsys_egl_display_setup(CoglDisplay * display,CoglError ** error)170 _cogl_winsys_egl_display_setup (CoglDisplay *display,
171 CoglError **error)
172 {
173 CoglDisplayEGL *egl_display = display->winsys;
174 CoglDisplayAndroid *android_display;
175
176 android_display = g_slice_new0 (CoglDisplayAndroid);
177 egl_display->platform = android_display;
178
179 return TRUE;
180 }
181
182 static void
_cogl_winsys_egl_display_destroy(CoglDisplay * display)183 _cogl_winsys_egl_display_destroy (CoglDisplay *display)
184 {
185 CoglDisplayEGL *egl_display = display->winsys;
186
187 g_slice_free (CoglDisplayAndroid, egl_display->platform);
188 }
189
190 static CoglBool
_cogl_winsys_egl_onscreen_init(CoglOnscreen * onscreen,EGLConfig egl_config,CoglError ** error)191 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
192 EGLConfig egl_config,
193 CoglError **error)
194 {
195 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
196 CoglContext *context = framebuffer->context;
197 CoglDisplay *display = context->display;
198 CoglDisplayEGL *egl_display = display->winsys;
199 CoglDisplayAndroid *android_display = egl_display->platform;
200 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
201
202 if (android_display->have_onscreen)
203 {
204 _cogl_set_error (error, COGL_WINSYS_ERROR,
205 COGL_WINSYS_ERROR_CREATE_ONSCREEN,
206 "EGL platform only supports a single onscreen window");
207 return FALSE;
208 }
209
210 egl_onscreen->egl_surface = egl_display->egl_surface;
211
212 _cogl_framebuffer_winsys_update_size (framebuffer,
213 android_display->egl_surface_width,
214 android_display->egl_surface_height);
215
216 android_display->have_onscreen = TRUE;
217
218 return TRUE;
219 }
220
221 static const CoglWinsysEGLVtable
222 _cogl_winsys_egl_vtable =
223 {
224 .display_setup = _cogl_winsys_egl_display_setup,
225 .display_destroy = _cogl_winsys_egl_display_destroy,
226 .context_created = _cogl_winsys_egl_context_created,
227 .onscreen_init = _cogl_winsys_egl_onscreen_init,
228 };
229
230 const CoglWinsysVtable *
_cogl_winsys_egl_android_get_vtable(void)231 _cogl_winsys_egl_android_get_vtable (void)
232 {
233 static CoglBool vtable_inited = FALSE;
234 static CoglWinsysVtable vtable;
235
236 if (!vtable_inited)
237 {
238 /* The EGL_ANDROID winsys is a subclass of the EGL winsys so we
239 start by copying its vtable */
240
241 vtable = *_cogl_winsys_egl_get_vtable ();
242
243 vtable.id = COGL_WINSYS_ID_EGL_ANDROID;
244 vtable.name = "EGL_ANDROID";
245
246 vtable.renderer_connect = _cogl_winsys_renderer_connect;
247 vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect;
248
249 vtable_inited = TRUE;
250 }
251
252 return &vtable;
253 }
254