Merge: doc: fixed some typos and other misc. corrections
[nit.git] / lib / gamnit / egl.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Use of EGL to implement Gamnit on GNU/Linux and Android
16 module egl
17
18 import ::egl
19
20 import gamnit::display
21
22 redef class GamnitDisplay
23
24 # The EGL display
25 var egl_display: EGLDisplay is noautoinit
26
27 # The EGL context
28 var egl_context: EGLContext is noautoinit
29
30 # The EGL surface for the window
31 var window_surface: EGLSurface is noautoinit
32
33 # The selected EGL configuration
34 var egl_config: EGLConfig is noautoinit
35
36 # Setup the EGL display for the given `native_display`
37 protected fun setup_egl_display(native_display: Pointer)
38 do
39 var egl_display = new EGLDisplay(native_display)
40 assert egl_display.is_valid else print "new EGL display is not valid"
41
42 egl_display.initialize
43 assert egl_display.is_valid else print "EGL initialize error: {egl_display.error}"
44
45 self.egl_display = egl_display
46 end
47
48 # Select an EGL config
49 protected fun select_egl_config(red, green, blue, alpha, depth, stencil: Int)
50 do
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
60
61 config_chooser.sample_buffers = 1
62 config_chooser.samples = 4
63
64 config_chooser.close
65
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"
69
70 if debug_gamnit then
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}"
79 end
80 end
81
82 # We use the first one, it is recommended
83 self.egl_config = configs.first
84 end
85
86 # Setup the EGL context for the given `native_window`
87 protected fun setup_egl_context(native_window: Pointer)
88 do
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
92
93 egl_context = egl_display.create_context(egl_config)
94 assert egl_context.is_ok else print "Creating EGL context failed: {egl_display.error}"
95
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}"
98
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}"
101 end
102
103 # Check if the current configuration of `native_window` is still valid
104 #
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
110 do
111 native_window_is_invalid = false
112
113 if not egl_context.is_ok then
114 # Needs recreating
115 egl_context = egl_display.create_context(egl_config)
116 assert egl_context.is_ok else print "Creating EGL context failed: {egl_display.error}"
117 end
118
119 var success = egl_display.make_current(window_surface, window_surface, egl_context)
120 if not success then
121 var error = egl_display.error
122 print "check_egl_context make_current: {error}"
123
124
125 if error.is_bad_native_window then
126 # native_window is invalid
127 native_window_is_invalid = true
128 return true
129
130 else if not error.is_success then
131 # The context is now invalid, rebuild it
132 setup_egl_context native_window
133 return true
134 end
135 end
136 return false
137 end
138
139 # Return value from `check_egl_context`, the current native window is invalid
140 #
141 # We should wait until we are provided a valid window handle.
142 var native_window_is_invalid = false
143
144 redef fun width do return window_surface.attribs(egl_display).width
145
146 redef fun height do return window_surface.attribs(egl_display).height
147
148 # Close the EGL context
149 fun close_egl
150 do
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)
154 end
155
156 redef fun flip
157 do
158 assert glGetError == gl_NO_ERROR
159
160 assert egl_display.is_valid
161
162 egl_display.swap_buffers(window_surface)
163 end
164 end