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