lib/egl: move `report_egl_error` from Object to `EGLDisplay`
[nit.git] / lib / egl.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Interface between rendering APIs (OpenGL, OpenGL ES, etc.) and the native windowing system.
18 #
19 # Most services of this module are a direct wrapper of the underlying
20 # C library. If a method or class is not documented in Nit, refer to
21 # the official documentation by the Khronos Group at:
22 # http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/
23 module egl is
24 pkgconfig
25 ldflags("-lEGL")@android
26 end
27
28 import android::aware
29
30 in "C Header" `{
31 #include <EGL/egl.h>
32 `}
33
34 extern class EGLNativeDisplayType `{ EGLNativeDisplayType `}
35 new from_x11(handle: Pointer) `{ return (EGLNativeDisplayType)handle; `}
36 end
37
38 extern class EGLDisplay `{ EGLDisplay `}
39 new current `{ return eglGetCurrentDisplay(); `}
40 new(handle: Pointer) `{ return eglGetDisplay(handle); `}
41
42 fun is_valid: Bool `{ return self != EGL_NO_DISPLAY; `}
43
44 fun initialize: Bool `{
45 EGLBoolean r = eglInitialize(self, NULL, NULL);
46 if (r == EGL_FALSE) {
47 fprintf(stderr, "Unable to eglInitialize");
48 return 0;
49 }
50 return 1;
51 `}
52
53 fun major_version: Int `{
54 EGLint val;
55 eglInitialize(self, &val, NULL);
56 return val;
57 `}
58 fun minor_version: Int `{
59 EGLint val;
60 eglInitialize(self, NULL, &val);
61 return val;
62 `}
63
64 # TODO if useful
65 # Returns all configs supported by the hardware
66 #fun get_configs: nullable Array[EGLConfig] import Array[EGLConfig].with_native `{
67
68 # Returns some configs compatible with the specified `attributes`
69 fun choose_configs(attribs: Array[Int]): nullable Array[EGLConfig] import Array[Int].length, Array[Int].[], Array[EGLConfig], Array[EGLConfig].add, Array[EGLConfig].as nullable, report_egl_error `{
70 EGLConfig *configs;
71 int n_configs;
72 int n_attribs = Array_of_Int_length(attribs);
73 int i;
74 int *c_attribs = malloc(sizeof(int)*n_attribs);
75 for (i = 0; i < n_attribs; i ++) {
76 c_attribs[i] = Array_of_Int__index(attribs, i);
77 }
78
79 // get number of configs
80 EGLBoolean r = eglChooseConfig(self, c_attribs, NULL, 0, &n_configs);
81
82 if (r == EGL_FALSE) {
83 EGLDisplay_report_egl_error(self, "failed to get number of available configs.");
84 return null_Array_of_EGLConfig();
85 } else if (n_configs == 0) {
86 EGLDisplay_report_egl_error(self, "no config available.");
87 return null_Array_of_EGLConfig();
88 }
89
90 configs = (EGLConfig*)malloc(sizeof(EGLConfig)*n_configs);
91
92 r = eglChooseConfig(self, c_attribs, configs, n_configs, &n_configs);
93
94 if (r == EGL_FALSE) {
95 EGLDisplay_report_egl_error(self, "failed to load config.");
96 return null_Array_of_EGLConfig();
97 } else {
98 Array_of_EGLConfig array = new_Array_of_EGLConfig();
99 for (i=0; i < n_configs; i++)
100 Array_of_EGLConfig_add(array, configs[i]);
101
102 return Array_of_EGLConfig_as_nullable(array);
103 }
104 `}
105
106 private fun report_egl_error(cmsg: NativeString)
107 do
108 var msg = cmsg.to_s
109 print "libEGL error: {msg}"
110 end
111
112 # Can be used directly, but it is preferable to use a `EGLConfigAttribs`
113 fun config_attrib(config: EGLConfig, attribute: Int): Int `{
114 EGLint val;
115 EGLBoolean r = eglGetConfigAttrib(self, config, attribute, &val);
116 if (r == EGL_FALSE)
117 return -1;
118 else
119 return val;
120 `}
121
122 fun terminate: Bool `{
123 return eglTerminate(self) == EGL_TRUE;
124 `}
125
126 fun create_window_surface(config: EGLConfig, native_window: Pointer, attribs: Array[Int]): EGLSurface `{
127 EGLSurface surface = eglCreateWindowSurface(self, config, (EGLNativeWindowType)native_window, NULL);
128 return surface;
129 `}
130
131 # TODO add share_context
132 fun create_context(config: EGLConfig): EGLContext `{
133 EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE}; // TODO move out!
134 EGLContext context = eglCreateContext(self, config, EGL_NO_CONTEXT, context_attribs);
135 return context;
136 `}
137
138 fun make_current(draw, read: EGLSurface, context: EGLContext): Bool `{
139 if (eglMakeCurrent(self, draw, read, context) == EGL_FALSE) {
140 fprintf(stderr, "Unable to eglMakeCurrent");
141 return 0;
142 }
143 return 1;
144 `}
145
146 # Can be used directly, but it is preferable to use a `EGLSurfaceAttribs`
147 fun query_surface(surface: EGLSurface, attribute: Int): Int `{
148 int val;
149 EGLBoolean r = eglQuerySurface(self, surface, attribute, &val);
150 if (r == EGL_FALSE)
151 return -1;
152 else
153 return val;
154 `}
155
156 fun destroy_context(context: EGLContext): Bool `{
157 return eglDestroyContext(self, context);
158 `}
159
160 fun destroy_surface(surface: EGLSurface): Bool `{
161 return eglDestroySurface(self, surface);
162 `}
163
164 fun error: EGLError `{ return eglGetError(); `}
165
166 # Utility method for easier debugging
167 fun assert_no_egl_error
168 do
169 var error = self.error
170 if not error.is_success then
171 print "EGL error: {error}"
172 abort
173 end
174 end
175
176 private fun query_string(name: Int): String import NativeString.to_s `{
177 return NativeString_to_s((char *)eglQueryString(self, name));
178 `}
179
180 fun vendor: String do return query_string(0x3053)
181
182 fun version: String do return query_string(0x3054)
183
184 fun extensions: Array[String] do return query_string(0x3055).split_with(" ")
185
186 fun client_apis: Array[String] do return query_string(0x308D).split_with(" ")
187
188 fun swap_buffers(surface: EGLSurface) `{ eglSwapBuffers(self, surface); `}
189 end
190
191 extern class EGLConfig `{ EGLConfig `}
192 fun attribs(display: EGLDisplay): EGLConfigAttribs do
193 return new EGLConfigAttribs(display, self)
194 end
195 end
196
197 extern class EGLSurface `{ EGLSurface `}
198 new current_draw `{ return eglGetCurrentSurface(EGL_DRAW); `}
199 new current_read `{ return eglGetCurrentSurface(EGL_READ); `}
200 new none `{ return EGL_NO_SURFACE; `}
201
202 fun is_ok: Bool `{ return self != EGL_NO_SURFACE; `}
203
204 fun attribs(display: EGLDisplay): EGLSurfaceAttribs do
205 return new EGLSurfaceAttribs(display, self)
206 end
207 end
208
209 extern class EGLContext `{ EGLContext `}
210 new current `{ return eglGetCurrentContext(); `}
211 new none `{ return EGL_NO_CONTEXT; `}
212
213 fun is_ok: Bool `{ return self != EGL_NO_CONTEXT; `}
214 end
215
216 # Attributes of a config for a given EGL display
217 class EGLConfigAttribs
218 var display: EGLDisplay
219 var config: EGLConfig
220
221 fun buffer_size: Int do return display.config_attrib(config, 0x3020)
222 fun alpha_size: Int do return display.config_attrib(config, 0x3021)
223 fun blue_size: Int do return display.config_attrib(config, 0x3022)
224 fun green_size: Int do return display.config_attrib(config, 0x3023)
225 fun red_size: Int do return display.config_attrib(config, 0x3024)
226 fun depth_size: Int do return display.config_attrib(config, 0x3025)
227 fun stencil_size: Int do return display.config_attrib(config, 0x3026)
228
229 fun native_visual_id: Int do return display.config_attrib(config, 0x302E)
230 fun native_visual_type: Int do return display.config_attrib(config, 0x302F)
231
232 fun caveat: EGLConfigCaveat do
233 return new EGLConfigCaveat.from_i(display.config_attrib(config, 0x3027))
234 end
235
236 fun conformant: EGLConformant do
237 return new EGLConformant.from_i(display.config_attrib(config, 0x3042))
238 end
239 end
240
241 extern class EGLConfigCaveat `{ EGLint `}
242 new from_i(val: Int) `{ return (EGLint)val; `}
243 fun to_i: Int `{ return self; `}
244
245 new none `{ return EGL_NONE; `}
246 fun is_none: Bool `{ return self == EGL_NONE; `}
247
248 new dont_care `{ return EGL_DONT_CARE; `}
249 fun is_dont_care: Bool `{ return self == EGL_DONT_CARE; `}
250
251 new slow `{ return EGL_SLOW_CONFIG; `}
252 fun is_slow: Bool `{ return self == EGL_SLOW_CONFIG; `}
253
254 # Obselete since EGL 1.3, use EGL_CONFORMANT instead
255 new non_conformant `{ return EGL_NON_CONFORMANT_CONFIG; `}
256 fun is_non_conformant: Bool `{ return self == EGL_NON_CONFORMANT_CONFIG; `}
257
258 redef fun to_s
259 do
260 if is_none then return "EGL_NONE"
261 if is_dont_care then return "EGL_DONT_CARE"
262 if is_slow then return "EGL_SLOW_CONFIG"
263 if is_non_conformant then return "EGL_NON_CONFORMANT"
264 return "Unknown or invalid value"
265 end
266 end
267
268 extern class EGLConformant `{ EGLint `}
269 new `{ return (EGLint)0; `}
270 new from_i(val: Int) `{ return (EGLint)val; `}
271 fun to_i: Int `{ return self; `}
272
273 fun opengl: Bool `{ return self & EGL_OPENGL_BIT; `}
274 fun with_opengl: EGLConformant `{ return self | EGL_OPENGL_BIT; `}
275
276 fun opengl_es: Bool `{ return self & EGL_OPENGL_ES_BIT; `}
277 fun with_opengl_es: EGLConformant `{ return self | EGL_OPENGL_ES_BIT; `}
278
279 fun opengl_es2: Bool `{ return self & EGL_OPENGL_ES2_BIT; `}
280 fun with_opengl_es2: EGLConformant `{ return self | EGL_OPENGL_ES2_BIT; `}
281
282 fun openvg: Bool `{ return self & EGL_OPENVG_BIT; `}
283 fun with_openvg: EGLConformant `{ return self | EGL_OPENVG_BIT; `}
284
285 fun to_a: Array[String]
286 do
287 var features = new Array[String]
288 if opengl then features.add("OpenGL")
289 if opengl_es then features.add("OpenGL ES")
290 if opengl_es2 then features.add("OpenGL ES2")
291 if openvg then features.add("OpenVG")
292 return features
293 end
294
295 redef fun to_s do return to_a.join(", ")
296 end
297
298 # Attributes of a surface for a given EGL display
299 class EGLSurfaceAttribs
300 var display: EGLDisplay
301 var surface: EGLSurface
302
303 fun height: Int do return display.query_surface(surface, 0x3056)
304 fun width: Int do return display.query_surface(surface, 0x3057)
305 fun largest_pbuffer: Int do return display.query_surface(surface, 0x3058)
306 fun texture_format: Int do return display.query_surface(surface, 0x3080)
307 fun texture_target: Int do return display.query_surface(surface, 0x3081)
308 fun mipmap_texture: Int do return display.query_surface(surface, 0x3082)
309 fun mipmap_level: Int do return display.query_surface(surface, 0x3083)
310 fun render_buffer: Int do return display.query_surface(surface, 0x3086)
311 fun vg_colorspace: Int do return display.query_surface(surface, 0x3087)
312 fun vg_alpha_format: Int do return display.query_surface(surface, 0x3088)
313 fun horizontal_resolution: Int do return display.query_surface(surface, 0x3090)
314 fun vertical_resolution: Int do return display.query_surface(surface, 0x3091)
315 fun pixel_aspect_ratio: Int do return display.query_surface(surface, 0x3092)
316 fun swap_behavior: Int do return display.query_surface(surface, 0x3093)
317 fun multisample_resolve: Int do return display.query_surface(surface, 0x3099)
318 end
319
320 extern class EGLError `{ EGLint `}
321 fun is_success: Bool `{ return self == EGL_SUCCESS; `}
322
323 fun is_not_initialized: Bool `{ return self == EGL_NOT_INITIALIZED; `}
324 fun is_bad_access: Bool `{ return self == EGL_BAD_ACCESS; `}
325 fun is_bad_alloc: Bool `{ return self == EGL_BAD_ALLOC; `}
326 fun is_bad_attribute: Bool `{ return self == EGL_BAD_ATTRIBUTE; `}
327 fun is_bad_config: Bool `{ return self == EGL_BAD_CONFIG; `}
328 fun is_bad_context: Bool `{ return self == EGL_BAD_CONTEXT; `}
329 fun is_bad_current_surface: Bool `{ return self == EGL_BAD_CURRENT_SURFACE; `}
330 fun is_bad_display: Bool `{ return self == EGL_BAD_DISPLAY; `}
331 fun is_bad_match: Bool `{ return self == EGL_BAD_MATCH; `}
332 fun is_bad_native_pixmap: Bool `{ return self == EGL_BAD_NATIVE_PIXMAP; `}
333 fun is_bad_native_window: Bool `{ return self == EGL_BAD_NATIVE_WINDOW; `}
334 fun is_bad_parameter: Bool `{ return self == EGL_BAD_PARAMETER; `}
335 fun is_bad_surface: Bool `{ return self == EGL_BAD_SURFACE; `}
336 fun is_context_lost: Bool `{ return self == EGL_CONTEXT_LOST; `}
337
338 redef fun to_s
339 do
340 if is_not_initialized then return "Not initialized"
341 if is_bad_access then return "Bad access"
342 if is_bad_alloc then return "Bad allocation"
343 if is_bad_attribute then return "Bad attribute"
344 if is_bad_config then return "Bad configuration"
345 if is_bad_context then return "Bad context"
346 if is_bad_current_surface then return "Bad current surface"
347 if is_bad_display then return "Bad display"
348 if is_bad_match then return "Bad match"
349 if is_bad_native_pixmap then return "Bad native pixmap"
350 if is_bad_native_window then return "Bad native window"
351 if is_bad_parameter then return "Bad parameter"
352 if is_bad_surface then return "Bad surface"
353 if is_context_lost then return "Context lost"
354 return "Unknown error" # this is not good
355 end
356 end
357
358 extern class EGLContextAttribute `{ EGLint `}
359 new buffer_size `{ return EGL_BUFFER_SIZE; `}
360 new alpha_size `{ return EGL_ALPHA_SIZE; `}
361 new blue_size `{ return EGL_BLUE_SIZE; `}
362 new green_size `{ return EGL_GREEN_SIZE; `}
363 new red_size `{ return EGL_RED_SIZE; `}
364 new depth_size `{ return EGL_DEPTH_SIZE; `}
365 new stencil_size `{ return EGL_STENCIL_SIZE; `}
366 new config_caveat `{ return EGL_CONFIG_CAVEAT; `}
367 new config_id `{ return EGL_CONFIG_ID; `}
368 new level `{ return EGL_LEVEL; `}
369 new max_pbuffer_height `{ return EGL_MAX_PBUFFER_HEIGHT; `}
370 new max_pbuffer_pixels `{ return EGL_MAX_PBUFFER_PIXELS; `}
371 new max_pbuffer_width `{ return EGL_MAX_PBUFFER_WIDTH; `}
372 new native_renderable `{ return EGL_NATIVE_RENDERABLE; `}
373 new native_visual_id `{ return EGL_NATIVE_VISUAL_ID; `}
374 new native_visual_type `{ return EGL_NATIVE_VISUAL_TYPE; `}
375 new samples `{ return EGL_SAMPLES; `}
376 new sample_buffers `{ return EGL_SAMPLE_BUFFERS; `}
377 new surface_type `{ return EGL_SURFACE_TYPE; `}
378 new transparent_type `{ return EGL_TRANSPARENT_TYPE; `}
379 new transparent_blue_value `{ return EGL_TRANSPARENT_BLUE_VALUE; `}
380 new transparent_green_value `{ return EGL_TRANSPARENT_GREEN_VALUE; `}
381 new transparent_red_value `{ return EGL_TRANSPARENT_RED_VALUE; `}
382 new bind_to_texture_rgb `{ return EGL_BIND_TO_TEXTURE_RGB; `}
383 new bind_to_texture_rgba `{ return EGL_BIND_TO_TEXTURE_RGBA; `}
384 new min_swap_interval `{ return EGL_MIN_SWAP_INTERVAL; `}
385 new max_swap_interval `{ return EGL_MAX_SWAP_INTERVAL; `}
386 new limunance_size `{ return EGL_LUMINANCE_SIZE; `}
387 new alpha_mask_size `{ return EGL_ALPHA_MASK_SIZE; `}
388 new color_buffer_type `{ return EGL_COLOR_BUFFER_TYPE; `}
389 new renderable_type `{ return EGL_RENDERABLE_TYPE; `}
390 new match_native_pixmap `{ return EGL_MATCH_NATIVE_PIXMAP; `}
391 new conformant `{ return EGL_CONFORMANT; `}
392
393 # Attrib list terminator
394 new none `{ return EGL_NONE; `}
395 end
396
397 # Utility class to choose an EGLConfig
398 class EGLConfigChooser
399 var array = new Array[Int]
400 var closed = false
401 protected var inserted_attribs = new Array[Int]
402
403 protected fun insert_attrib_key(key: Int)
404 do
405 assert not inserted_attribs.has(key) else
406 print "Duplicate attrib passed to EGLConfigChooser"
407 end
408 array.add key
409 end
410
411 protected fun insert_attrib_with_val(key, val: Int)
412 do
413 insert_attrib_key key
414 array.add val
415 end
416
417 fun close do
418 insert_attrib_key 0x3038
419 closed = true
420 end
421
422 fun surface_type=(flag: Int) do insert_attrib_with_val(0x3033, flag)
423 fun surface_type_egl do surface_type = 4
424
425 # Set which client rendering APIs are supported
426 fun renderable_type=(flag: Int) do insert_attrib_with_val(0x3040, flag)
427
428 # Set EGL as the only supported rendering API
429 fun renderable_type_egl do renderable_type = 4
430
431 fun blue_size=(size: Int) do insert_attrib_with_val(0x3022, size)
432 fun green_size=(size: Int) do insert_attrib_with_val(0x3023, size)
433 fun red_size=(size: Int) do insert_attrib_with_val(0x3024, size)
434
435 fun buffer_size=(size: Int) do insert_attrib_with_val(0x3020, size)
436 fun alpha_size=(size: Int) do insert_attrib_with_val(0x3021, size)
437 fun depth_size=(size: Int) do insert_attrib_with_val(0x3025, size)
438 fun stencil_size=(size: Int) do insert_attrib_with_val(0x3026, size)
439 fun sample_buffers=(size: Int) do insert_attrib_with_val(0x3031, size)
440
441 fun caveat=(caveat: EGLConfigCaveat) do insert_attrib_with_val(0x3050, caveat.to_i)
442
443 fun conformant=(conformant: EGLConformant) do insert_attrib_with_val(0x3042, conformant.to_i)
444
445 fun choose(display: EGLDisplay): nullable Array[EGLConfig]
446 do
447 assert closed else print "EGLConfigChooser not closed."
448 return display.choose_configs(array)
449 end
450 end
451
452 fun egl_bind_opengl_api: Bool `{ return eglBindAPI(EGL_OPENGL_API); `}
453 fun egl_bind_opengl_es_api: Bool `{ return eglBindAPI(EGL_OPENGL_ES_API); `}
454 fun egl_bind_openvg_api: Bool `{ return eglBindAPI(EGL_OPENVG_API); `}
455
456 # Handle to the default display to use with EGL
457 fun egl_default_display: Pointer `{ return EGL_DEFAULT_DISPLAY; `}