| 1 | module sapp |
| 2 | |
| 3 | // EGL initialization and teardown. |
| 4 | // Shared between Wayland and X11 backends. |
| 5 | |
| 6 | fn sapp_egl_choose_config() EGLConfig { |
| 7 | sample_count := if g_sapp_state.desc.sample_count > 1 { |
| 8 | EGLint(g_sapp_state.desc.sample_count) |
| 9 | } else { |
| 10 | EGLint(0) |
| 11 | } |
| 12 | alpha_size := if g_sapp_state.desc.alpha { EGLint(8) } else { EGLint(0) } |
| 13 | sample_buffers := if g_sapp_state.desc.sample_count > 1 { EGLint(1) } else { EGLint(0) } |
| 14 | |
| 15 | config_attrs := [ |
| 16 | egl_surface_type, |
| 17 | egl_window_bit, |
| 18 | egl_renderable_type, |
| 19 | egl_opengl_bit, |
| 20 | egl_red_size, |
| 21 | EGLint(8), |
| 22 | egl_green_size, |
| 23 | EGLint(8), |
| 24 | egl_blue_size, |
| 25 | EGLint(8), |
| 26 | egl_alpha_size, |
| 27 | alpha_size, |
| 28 | egl_depth_size, |
| 29 | EGLint(24), |
| 30 | egl_stencil_size, |
| 31 | EGLint(8), |
| 32 | egl_sample_buffers, |
| 33 | sample_buffers, |
| 34 | egl_samples, |
| 35 | sample_count, |
| 36 | egl_none, |
| 37 | ]! |
| 38 | |
| 39 | mut egl_configs := unsafe { [32]EGLConfig{} } |
| 40 | mut config_count := EGLint(0) |
| 41 | if C.eglChooseConfig(g_sapp_state.egl.display, &config_attrs[0], &egl_configs[0], 32, &config_count) == 0 |
| 42 | || config_count == 0 { |
| 43 | eprintln('sokol_app: EGL: no configs found') |
| 44 | return egl_configs[0] |
| 45 | } |
| 46 | |
| 47 | mut config := egl_configs[0] |
| 48 | for i in 0 .. int(config_count) { |
| 49 | c := egl_configs[i] |
| 50 | mut r := EGLint(0) |
| 51 | mut g := EGLint(0) |
| 52 | mut b := EGLint(0) |
| 53 | mut a := EGLint(0) |
| 54 | mut d := EGLint(0) |
| 55 | mut s := EGLint(0) |
| 56 | mut n := EGLint(0) |
| 57 | if C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_red_size, &r) != 0 |
| 58 | && C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_green_size, &g) != 0 |
| 59 | && C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_blue_size, &b) != 0 |
| 60 | && C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_alpha_size, &a) != 0 |
| 61 | && C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_depth_size, &d) != 0 |
| 62 | && C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_stencil_size, &s) != 0 |
| 63 | && C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_samples, &n) != 0 && r == 8 |
| 64 | && g == 8 && b == 8 && a == alpha_size && d == 24 && s == 8 && n == sample_count { |
| 65 | config = c |
| 66 | break |
| 67 | } |
| 68 | } |
| 69 | return config |
| 70 | } |
| 71 | |
| 72 | fn sapp_egl_create_context(config EGLConfig) { |
| 73 | gl_major := if g_sapp_state.desc.gl.major_version != 0 { |
| 74 | g_sapp_state.desc.gl.major_version |
| 75 | } else { |
| 76 | 4 |
| 77 | } |
| 78 | gl_minor := if g_sapp_state.desc.gl.minor_version != 0 { |
| 79 | g_sapp_state.desc.gl.minor_version |
| 80 | } else { |
| 81 | 1 |
| 82 | } |
| 83 | |
| 84 | ctx_attrs := [ |
| 85 | egl_context_major_version, |
| 86 | EGLint(gl_major), |
| 87 | egl_context_minor_version, |
| 88 | EGLint(gl_minor), |
| 89 | egl_context_opengl_profile_mask, |
| 90 | egl_context_opengl_core_profile_bit, |
| 91 | egl_none, |
| 92 | ]! |
| 93 | |
| 94 | g_sapp_state.egl.context = C.eglCreateContext(g_sapp_state.egl.display, config, unsafe { nil }, |
| 95 | &ctx_attrs[0]) |
| 96 | if g_sapp_state.egl.context == unsafe { nil } { |
| 97 | eprintln('sokol_app: EGL: failed to create context') |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | fn sapp_egl_create_surface(native_window voidptr) { |
| 102 | config := sapp_egl_choose_config() |
| 103 | g_sapp_state.egl.config = config |
| 104 | g_sapp_state.egl.surface = C.eglCreateWindowSurface(g_sapp_state.egl.display, config, |
| 105 | native_window, unsafe { nil }) |
| 106 | if g_sapp_state.egl.surface == unsafe { nil } { |
| 107 | eprintln('sokol_app: EGL: failed to create window surface') |
| 108 | } |
| 109 | if g_sapp_state.egl.context == unsafe { nil } { |
| 110 | sapp_egl_create_context(config) |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | fn sapp_egl_make_current() { |
| 115 | if C.eglMakeCurrent(g_sapp_state.egl.display, g_sapp_state.egl.surface, |
| 116 | g_sapp_state.egl.surface, g_sapp_state.egl.context) == 0 { |
| 117 | eprintln('sokol_app: EGL: eglMakeCurrent failed') |
| 118 | } |
| 119 | mut fb := i32(0) |
| 120 | C.glGetIntegerv(gl_framebuffer_binding, &fb) |
| 121 | g_sapp_state.gl.framebuffer = u32(fb) |
| 122 | C.eglSwapInterval(g_sapp_state.egl.display, EGLint(g_sapp_state.swap_interval)) |
| 123 | } |
| 124 | |
| 125 | $if sokol_wayland ? { |
| 126 | fn sapp_egl_init_wayland() { |
| 127 | if C.eglBindAPI(egl_opengl_api) == 0 { |
| 128 | eprintln('sokol_app: EGL: failed to bind OpenGL API') |
| 129 | } |
| 130 | |
| 131 | g_sapp_state.egl.display = C.eglGetDisplay(voidptr(g_sapp_state.wl.display)) |
| 132 | if g_sapp_state.egl.display == unsafe { nil } { |
| 133 | eprintln('sokol_app: EGL: failed to get display') |
| 134 | } |
| 135 | |
| 136 | mut major := EGLint(0) |
| 137 | mut minor := EGLint(0) |
| 138 | if C.eglInitialize(g_sapp_state.egl.display, &major, &minor) == 0 { |
| 139 | eprintln('sokol_app: EGL: failed to initialize') |
| 140 | } |
| 141 | g_sapp_state.gl.major = int(major) |
| 142 | g_sapp_state.gl.minor = int(minor) |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | fn sapp_egl_init_x11() { |
| 147 | if C.eglBindAPI(egl_opengl_api) == 0 { |
| 148 | eprintln('sokol_app: EGL: failed to bind OpenGL API') |
| 149 | } |
| 150 | |
| 151 | g_sapp_state.egl.display = C.eglGetDisplay(voidptr(g_sapp_state.x11.display)) |
| 152 | if g_sapp_state.egl.display == unsafe { nil } { |
| 153 | eprintln('sokol_app: EGL: failed to get display') |
| 154 | } |
| 155 | |
| 156 | mut major := EGLint(0) |
| 157 | mut minor := EGLint(0) |
| 158 | if C.eglInitialize(g_sapp_state.egl.display, &major, &minor) == 0 { |
| 159 | eprintln('sokol_app: EGL: failed to initialize') |
| 160 | } |
| 161 | g_sapp_state.gl.major = int(major) |
| 162 | g_sapp_state.gl.minor = int(minor) |
| 163 | |
| 164 | config := sapp_egl_choose_config() |
| 165 | |
| 166 | mut visual_id := EGLint(0) |
| 167 | if C.eglGetConfigAttrib(g_sapp_state.egl.display, config, EGLint(0x302E), &visual_id) == 0 { |
| 168 | eprintln('sokol_app: EGL: failed to get native visual ID') |
| 169 | } |
| 170 | |
| 171 | mut visual_info_template := C.XVisualInfo{} |
| 172 | visual_info_template.visualid = VisualID(visual_id) |
| 173 | |
| 174 | mut num_visuals := 0 |
| 175 | visual_info := C.XGetVisualInfo(g_sapp_state.x11.display, visual_id_mask, |
| 176 | &visual_info_template, &num_visuals) |
| 177 | if visual_info == unsafe { nil } { |
| 178 | eprintln('sokol_app: EGL: failed to get visual info') |
| 179 | } |
| 180 | |
| 181 | x11_create_window(visual_info.visual, visual_info.depth) |
| 182 | C.XFree(visual_info) |
| 183 | |
| 184 | g_sapp_state.egl.surface = C.eglCreateWindowSurface(g_sapp_state.egl.display, config, |
| 185 | EGLNativeWindowType(g_sapp_state.x11.window), unsafe { nil }) |
| 186 | if g_sapp_state.egl.surface == unsafe { nil } { |
| 187 | eprintln('sokol_app: EGL: failed to create window surface') |
| 188 | } |
| 189 | |
| 190 | sapp_egl_create_context(config) |
| 191 | sapp_egl_make_current() |
| 192 | } |
| 193 | |
| 194 | fn sapp_egl_destroy() { |
| 195 | if g_sapp_state.egl.display != unsafe { nil } { |
| 196 | C.eglMakeCurrent(g_sapp_state.egl.display, unsafe { nil }, unsafe { nil }, unsafe { nil }) |
| 197 | |
| 198 | if g_sapp_state.egl.context != unsafe { nil } { |
| 199 | C.eglDestroyContext(g_sapp_state.egl.display, g_sapp_state.egl.context) |
| 200 | g_sapp_state.egl.context = unsafe { nil } |
| 201 | } |
| 202 | |
| 203 | if g_sapp_state.egl.surface != unsafe { nil } { |
| 204 | C.eglDestroySurface(g_sapp_state.egl.display, g_sapp_state.egl.surface) |
| 205 | g_sapp_state.egl.surface = unsafe { nil } |
| 206 | } |
| 207 | |
| 208 | C.eglTerminate(g_sapp_state.egl.display) |
| 209 | g_sapp_state.egl.display = unsafe { nil } |
| 210 | } |
| 211 | } |
| 212 | |