1 # This file is part of NIT (http://www.nitlanguage.org).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Use of EGL to implement Gamnit on GNU/Linux and Android
20 import gamnit
::display
22 redef class GamnitDisplay
25 var egl_display
: EGLDisplay is noautoinit
28 var egl_context
: EGLContext is noautoinit
30 # The EGL surface for the window
31 var window_surface
: EGLSurface is noautoinit
33 # The selected EGL configuration
34 var egl_config
: EGLConfig is noautoinit
36 # Setup the EGL display for the given `native_display`
37 protected fun setup_egl_display
(native_display
: Pointer)
39 var egl_display
= new EGLDisplay(native_display
)
40 assert egl_display
.is_valid
else print
"new EGL display is not valid"
42 egl_display
.initialize
43 assert egl_display
.is_valid
else print
"EGL initialize error: {egl_display.error}"
45 self.egl_display
= egl_display
48 # Select an EGL config
49 protected fun select_egl_config
(red
, green
, blue
, alpha
, depth
, stencil
: Int)
51 var config_chooser
= new EGLConfigChooser
52 config_chooser
.renderable_type_egl
53 config_chooser
.surface_type_egl
54 config_chooser
.red_size
= red
55 config_chooser
.green_size
= green
56 config_chooser
.blue_size
= blue
57 if alpha
> 0 then config_chooser
.alpha_size
= alpha
58 if depth
> 0 then config_chooser
.depth_size
= depth
59 if stencil
> 0 then config_chooser
.stencil_size
= stencil
61 config_chooser
.sample_buffers
= 1
62 config_chooser
.samples
= 4
66 var configs
= config_chooser
.choose
(egl_display
)
67 assert configs
!= null else print
"Choosing EGL config failed: {egl_display.error}"
68 assert not configs
.is_empty
else print
"Found no EGL config"
71 print
"EGL available configurations:"
72 for config
in configs
do
73 var attribs
= config
.attribs
(egl_display
)
74 print
"* Conformant to: {attribs.conformant}"
75 print
" Caveats: {attribs.caveat}"
76 print
" Size of RGBA: {attribs.red_size} {attribs.green_size} {attribs.blue_size} {attribs.alpha_size}"
77 print
" Buffer, depth, stencil: {attribs.buffer_size} {attribs.depth_size} {attribs.stencil_size}"
78 print
" Sample buffers, samples: {attribs.sample_buffers} {attribs.samples}"
82 # We use the first one, it is recommended
83 self.egl_config
= configs
.first
86 # Setup the EGL context for the given `native_window`
87 protected fun setup_egl_context
(native_window
: Pointer)
89 var window_surface
= egl_display
.create_window_surface
(egl_config
, native_window
, [0])
90 assert window_surface
.is_ok
else print
"Creating EGL window surface failed: {egl_display.error}"
91 self.window_surface
= window_surface
93 egl_context
= egl_display
.create_context
(egl_config
)
94 assert egl_context
.is_ok
else print
"Creating EGL context failed: {egl_display.error}"
96 var make_current_res
= egl_display
.make_current
(window_surface
, window_surface
, egl_context
)
97 assert make_current_res
else print
"Creating EGL make current failed: {egl_display.error}"
99 # TODO make the API selection configurable per platform
100 assert egl_bind_opengl_es_api
else print
"EGL bind API failed: {egl_display.error}"
103 # Check if the current configuration of `native_window` is still valid
105 # There is two return values:
106 # * Returns `true` if the Gamnit services should be recreated.
107 # * Sets `native_window_is_invalid` if the system provided window handle is invalid.
108 # We should wait until we are provided a valid window handle.
109 fun check_egl_context
(native_window
: Pointer): Bool
111 native_window_is_invalid
= false
113 if not egl_context
.is_ok
then
115 egl_context
= egl_display
.create_context
(egl_config
)
116 assert egl_context
.is_ok
else print
"Creating EGL context failed: {egl_display.error}"
119 var success
= egl_display
.make_current
(window_surface
, window_surface
, egl_context
)
121 var error
= egl_display
.error
122 print
"check_egl_context make_current: {error}"
125 if error
.is_bad_native_window
then
126 # native_window is invalid
127 native_window_is_invalid
= true
130 else if not error
.is_success
then
131 # The context is now invalid, rebuild it
132 setup_egl_context native_window
139 # Return value from `check_egl_context`, the current native window is invalid
141 # We should wait until we are provided a valid window handle.
142 var native_window_is_invalid
= false
144 redef fun width
do return window_surface
.attribs
(egl_display
).width
146 redef fun height
do return window_surface
.attribs
(egl_display
).height
148 # Close the EGL context
151 egl_display
.make_current
(new EGLSurface.none
, new EGLSurface.none
, new EGLContext.none
)
152 egl_display
.destroy_context
(egl_context
)
153 egl_display
.destroy_surface
(window_surface
)
158 assert glGetError
== gl_NO_ERROR
160 assert egl_display
.is_valid
162 egl_display
.swap_buffers
(window_surface
)