Merge branch 'hardening_types'
[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 # EGL is an interface between the rendering APIs OpenGL, OpenGL ES, etc.
18 # and the native windowing system.
19 #
20 # Most services of this module are a direct wrapper of the underlying
21 # C library. If a method or class is not documented in Nit, refer to
22 # the official documentation by the Khronos Group at:
23 # http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/
24 module egl is pkgconfig("egl")
25
26 in "C Header" `{
27 #include <EGL/egl.h>
28 `}
29
30 extern class EGLNativeDisplayType `{ EGLNativeDisplayType `}
31 new from_x11(handle: Pointer) `{ return (EGLNativeDisplayType)handle; `}
32 end
33
34 extern class EGLDisplay `{ EGLDisplay `}
35 new current `{ return eglGetCurrentDisplay(); `}
36 new(handle: Pointer) `{ return eglGetDisplay(handle); `}
37
38 fun is_valid: Bool `{ return recv != EGL_NO_DISPLAY; `}
39
40 fun initialize: Bool `{
41 EGLBoolean r = eglInitialize(recv, NULL, NULL);
42 if (r == EGL_FALSE) {
43 fprintf(stderr, "Unable to eglInitialize");
44 return 0;
45 }
46 return 1;
47 `}
48
49 fun major_version: Int `{
50 EGLint val;
51 eglInitialize(recv, &val, NULL);
52 return val;
53 `}
54 fun minor_version: Int `{
55 EGLint val;
56 eglInitialize(recv, NULL, &val);
57 return val;
58 `}
59
60 # TODO if useful
61 # Returns all configs supported by the hardware
62 #fun get_configs: nullable Array[EGLConfig] import Array[EGLConfig].with_native `{
63
64 # Returns some configs compatible with the specified `attributes`
65 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 `{
66 EGLConfig *configs;
67 int n_configs;
68 int n_attribs = Array_of_Int_length(attribs);
69 int i;
70 int *c_attribs = malloc(sizeof(int)*n_attribs);
71 for (i = 0; i < n_attribs; i ++) {
72 c_attribs[i] = Array_of_Int__index(attribs, i);
73 }
74
75 // get number of configs
76 EGLBoolean r = eglChooseConfig(recv, c_attribs, NULL, 0, &n_configs);
77
78 if (r == EGL_FALSE) {
79 EGLDisplay_report_egl_error(recv, "failed to get number of available configs.");
80 return null_Array_of_EGLConfig();
81 } else if (n_configs == 0) {
82 EGLDisplay_report_egl_error(recv, "no config available.");
83 return null_Array_of_EGLConfig();
84 }
85
86 configs = (EGLConfig*)malloc(sizeof(EGLConfig)*n_configs);
87
88 r = eglChooseConfig(recv, c_attribs, configs, n_configs, &n_configs);
89
90 if (r == EGL_FALSE) {
91 EGLDisplay_report_egl_error(recv, "failed to load config.");
92 return null_Array_of_EGLConfig();
93 } else {
94 Array_of_EGLConfig array = new_Array_of_EGLConfig();
95 for (i=0; i < n_configs; i++)
96 Array_of_EGLConfig_add(array, configs[i]);
97
98 return Array_of_EGLConfig_as_nullable(array);
99 }
100 `}
101
102 # Can be used directly, but it is preferable to use a `EGLConfigAttribs`
103 fun config_attrib(config: EGLConfig, attribute: Int): Int `{
104 EGLint val;
105 EGLBoolean r = eglGetConfigAttrib(recv, config, attribute, &val);
106 if (r == EGL_FALSE)
107 return -1;
108 else
109 return val;
110 `}
111
112 fun terminate: Bool `{
113 return eglTerminate(recv) == EGL_TRUE;
114 `}
115
116 fun create_window_surface(config: EGLConfig, native_window: Pointer, attribs: Array[Int]): EGLSurface `{
117 EGLSurface surface = eglCreateWindowSurface(recv, config, (EGLNativeWindowType)native_window, NULL);
118 return surface;
119 `}
120
121 # TODO add share_context
122 fun create_context(config: EGLConfig): EGLContext `{
123 EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE}; // TODO move out!
124 EGLContext context = eglCreateContext(recv, config, EGL_NO_CONTEXT, context_attribs);
125 return context;
126 `}
127
128 fun make_current(draw, read: EGLSurface, context: EGLContext): Bool `{
129 if (eglMakeCurrent(recv, draw, read, context) == EGL_FALSE) {
130 fprintf(stderr, "Unable to eglMakeCurrent");
131 return 0;
132 }
133 return 1;
134 `}
135
136 # Can be used directly, but it is preferable to use a `EGLSurfaceAttribs`
137 fun query_surface(surface: EGLSurface, attribute: Int): Int `{
138 int val;
139 EGLBoolean r = eglQuerySurface(recv, surface, attribute, &val);
140 if (r == EGL_FALSE)
141 return -1;
142 else
143 return val;
144 `}
145
146 fun destroy_context(context: EGLContext): Bool `{
147 return eglDestroyContext(recv, context);
148 `}
149
150 fun destroy_surface(surface: EGLSurface): Bool `{
151 return eglDestroySurface(recv, surface);
152 `}
153
154 fun error: EGLError `{ return eglGetError(); `}
155
156 # Utility method for easier debugging
157 fun assert_no_egl_error
158 do
159 var error = self.error
160 if not error.is_success then
161 print "EGL error: {error}"
162 abort
163 end
164 end
165
166 private fun query_string(name: Int): String import NativeString.to_s `{
167 return (void*)(long)NativeString_to_s(eglQueryString(recv, name));
168 `}
169
170 fun vendor: String do return query_string("3053".to_hex)
171
172 fun version: String do return query_string("3054".to_hex)
173
174 fun extensions: Array[String] do return query_string("3055".to_hex).split_with(" ")
175
176 fun client_apis: Array[String] do return query_string("308D".to_hex).split_with(" ")
177
178 fun swap_buffers(surface: EGLSurface) `{ eglSwapBuffers(recv, surface); `}
179 end
180
181 extern class EGLConfig `{ EGLConfig `}
182 fun attribs(display: EGLDisplay): EGLConfigAttribs do
183 return new EGLConfigAttribs(display, self)
184 end
185 end
186
187 extern class EGLSurface `{ EGLSurface `}
188 new current_draw `{ return eglGetCurrentSurface(EGL_DRAW); `}
189 new current_read `{ return eglGetCurrentSurface(EGL_READ); `}
190 new none `{ return EGL_NO_SURFACE; `}
191
192 fun is_ok: Bool `{ return recv != EGL_NO_SURFACE; `}
193
194 fun attribs(display: EGLDisplay): EGLSurfaceAttribs do
195 return new EGLSurfaceAttribs(display, self)
196 end
197 end
198
199 extern class EGLContext `{ EGLContext `}
200 new current `{ return eglGetCurrentContext(); `}
201 new none `{ return EGL_NO_CONTEXT; `}
202
203 fun is_ok: Bool `{ return recv != EGL_NO_CONTEXT; `}
204 end
205
206 # Attributes of a config for a given EGL display
207 class EGLConfigAttribs
208 var display: EGLDisplay
209 var config: EGLConfig
210
211 fun alpha_size: Int do return display.config_attrib(config, "3021".to_hex)
212 fun native_visual_id: Int do return display.config_attrib(config, "302E".to_hex)
213 fun native_visual_type: Int do return display.config_attrib(config, "302F".to_hex)
214 end
215
216 # Attributes of a surface for a given EGL display
217 class EGLSurfaceAttribs
218 var display: EGLDisplay
219 var surface: EGLSurface
220
221 fun height: Int do return display.query_surface(surface, "3056".to_hex)
222 fun width: Int do return display.query_surface(surface, "3057".to_hex)
223 fun largest_pbuffer: Int do return display.query_surface(surface, "3058".to_hex)
224 fun texture_format: Int do return display.query_surface(surface, "3080".to_hex)
225 fun texture_target: Int do return display.query_surface(surface, "3081".to_hex)
226 fun mipmap_texture: Int do return display.query_surface(surface, "3082".to_hex)
227 fun mipmap_level: Int do return display.query_surface(surface, "3083".to_hex)
228 fun render_buffer: Int do return display.query_surface(surface, "3086".to_hex)
229 fun vg_colorspace: Int do return display.query_surface(surface, "3087".to_hex)
230 fun vg_alpha_format: Int do return display.query_surface(surface, "3088".to_hex)
231 fun horizontal_resolution: Int do return display.query_surface(surface, "3090".to_hex)
232 fun vertical_resolution: Int do return display.query_surface(surface, "3091".to_hex)
233 fun pixel_aspect_ratio: Int do return display.query_surface(surface, "3092".to_hex)
234 fun swap_behavior: Int do return display.query_surface(surface, "3093".to_hex)
235 fun multisample_resolve: Int do return display.query_surface(surface, "3099".to_hex)
236 end
237
238 extern class EGLError `{ EGLint `}
239 fun is_success: Bool `{ return recv == EGL_SUCCESS; `}
240
241 fun is_not_initialized: Bool `{ return recv == EGL_NOT_INITIALIZED; `}
242 fun is_bad_access: Bool `{ return recv == EGL_BAD_ACCESS; `}
243 fun is_bad_alloc: Bool `{ return recv == EGL_BAD_ALLOC; `}
244 fun is_bad_attribute: Bool `{ return recv == EGL_BAD_ATTRIBUTE; `}
245 fun is_bad_config: Bool `{ return recv == EGL_BAD_CONFIG; `}
246 fun is_bad_context: Bool `{ return recv == EGL_BAD_CONTEXT; `}
247 fun is_bad_current_surface: Bool `{ return recv == EGL_BAD_CURRENT_SURFACE; `}
248 fun is_bad_display: Bool `{ return recv == EGL_BAD_DISPLAY; `}
249 fun is_bad_match: Bool `{ return recv == EGL_BAD_MATCH; `}
250 fun is_bad_native_pixmap: Bool `{ return recv == EGL_BAD_NATIVE_PIXMAP; `}
251 fun is_bad_native_window: Bool `{ return recv == EGL_BAD_NATIVE_WINDOW; `}
252 fun is_bad_parameter: Bool `{ return recv == EGL_BAD_PARAMETER; `}
253 fun is_bad_surface: Bool `{ return recv == EGL_BAD_SURFACE; `}
254 fun is_context_lost: Bool `{ return recv == EGL_CONTEXT_LOST; `}
255
256 redef fun to_s
257 do
258 if is_not_initialized then return "Not initialized"
259 if is_bad_access then return "Bad access"
260 if is_bad_alloc then return "Bad allocation"
261 if is_bad_attribute then return "Bad attribute"
262 if is_bad_config then return "Bad configuration"
263 if is_bad_context then return "Bad context"
264 if is_bad_current_surface then return "Bad current surface"
265 if is_bad_display then return "Bad display"
266 if is_bad_match then return "Bad match"
267 if is_bad_native_pixmap then return "Bad native pixmap"
268 if is_bad_native_window then return "Bad native window"
269 if is_bad_parameter then return "Bad parameter"
270 if is_bad_surface then return "Bad surface"
271 if is_context_lost then return "Context lost"
272 return "Unknown error" # this is not good
273 end
274 end
275
276 extern class EGLContextAttribute `{ EGLint `}
277 new buffer_size `{ return EGL_BUFFER_SIZE; `}
278 new alpha_size `{ return EGL_ALPHA_SIZE; `}
279 new blue_size `{ return EGL_BLUE_SIZE; `}
280 new green_size `{ return EGL_GREEN_SIZE; `}
281 new red_size `{ return EGL_RED_SIZE; `}
282 new depth_size `{ return EGL_DEPTH_SIZE; `}
283 new stencil_size `{ return EGL_STENCIL_SIZE; `}
284 new config_caveat `{ return EGL_CONFIG_CAVEAT; `}
285 new config_id `{ return EGL_CONFIG_ID; `}
286 new level `{ return EGL_LEVEL; `}
287 new max_pbuffer_height `{ return EGL_MAX_PBUFFER_HEIGHT; `}
288 new max_pbuffer_pixels `{ return EGL_MAX_PBUFFER_PIXELS; `}
289 new max_pbuffer_width `{ return EGL_MAX_PBUFFER_WIDTH; `}
290 new native_renderable `{ return EGL_NATIVE_RENDERABLE; `}
291 new native_visual_id `{ return EGL_NATIVE_VISUAL_ID; `}
292 new native_visual_type `{ return EGL_NATIVE_VISUAL_TYPE; `}
293 new samples `{ return EGL_SAMPLES; `}
294 new sample_buffers `{ return EGL_SAMPLE_BUFFERS; `}
295 new surface_type `{ return EGL_SURFACE_TYPE; `}
296 new transparent_type `{ return EGL_TRANSPARENT_TYPE; `}
297 new transparent_blue_value `{ return EGL_TRANSPARENT_BLUE_VALUE; `}
298 new transparent_green_value `{ return EGL_TRANSPARENT_GREEN_VALUE; `}
299 new transparent_red_value `{ return EGL_TRANSPARENT_RED_VALUE; `}
300 new bind_to_texture_rgb `{ return EGL_BIND_TO_TEXTURE_RGB; `}
301 new bind_to_texture_rgba `{ return EGL_BIND_TO_TEXTURE_RGBA; `}
302 new min_swap_interval `{ return EGL_MIN_SWAP_INTERVAL; `}
303 new max_swap_interval `{ return EGL_MAX_SWAP_INTERVAL; `}
304 new limunance_size `{ return EGL_LUMINANCE_SIZE; `}
305 new alpha_mask_size `{ return EGL_ALPHA_MASK_SIZE; `}
306 new color_buffer_type `{ return EGL_COLOR_BUFFER_TYPE; `}
307 new renderable_type `{ return EGL_RENDERABLE_TYPE; `}
308 new match_native_pixmap `{ return EGL_MATCH_NATIVE_PIXMAP; `}
309 new conformant `{ return EGL_CONFORMANT; `}
310
311 # Attrib list terminator
312 new none `{ return EGL_NONE; `}
313 end
314
315 # Utility class to choose an EGLConfig
316 class EGLConfigChooser
317 var array = new Array[Int]
318 var closed = false
319 protected var inserted_attribs = new Array[Int]
320
321 protected fun insert_attrib_key(key: Int)
322 do
323 assert not inserted_attribs.has(key) else
324 print "Duplicate attrib passed to EGLConfigChooser"
325 end
326 array.add key
327 end
328
329 protected fun insert_attrib_with_val(key, val: Int)
330 do
331 insert_attrib_key key
332 array.add val
333 end
334
335 fun close do
336 insert_attrib_key "3038".to_hex
337 closed = true
338 end
339
340 fun surface_type=(flag: Int) do insert_attrib_with_val("3033".to_hex, flag)
341 fun surface_type_egl do surface_type = 4
342
343 fun blue_size=(size: Int) do insert_attrib_with_val("3022".to_hex, size)
344 fun green_size=(size: Int) do insert_attrib_with_val("3023".to_hex, size)
345 fun red_size=(size: Int) do insert_attrib_with_val("3024".to_hex, size)
346
347 fun alpha_size=(size: Int) do insert_attrib_with_val("3021".to_hex, size)
348 fun depth_size=(size: Int) do insert_attrib_with_val("3025".to_hex, size)
349 fun stencil_size=(size: Int) do insert_attrib_with_val("3026".to_hex, size)
350 fun sample_buffers=(size: Int) do insert_attrib_with_val("3031".to_hex, size)
351
352 fun choose(display: EGLDisplay): nullable Array[EGLConfig]
353 do
354 assert closed else print "EGLConfigChooser not closed."
355 return display.choose_configs(array)
356 end
357 end
358
359 redef class Object
360 private fun report_egl_error(cmsg: NativeString)
361 do
362 var msg = cmsg.to_s
363 print "libEGL error: {msg}"
364 end
365 end
366
367 protected fun egl_bind_opengl_api: Bool `{ return eglBindAPI(EGL_OPENGL_API); `}
368 protected fun egl_bind_opengl_es_api: Bool `{ return eglBindAPI(EGL_OPENGL_ES_API); `}
369 protected fun egl_bind_openvg_api: Bool `{ return eglBindAPI(EGL_OPENVG_API); `}