1 // Copyright 2012 Intel Corporation
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice, this
9 // list of conditions and the following disclaimer.
10 //
11 // - Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 #include <EGL/egl.h>
27 #include <EGL/eglext.h>
28
29 #include "wcore_error.h"
30
31 #include "wegl_config.h"
32 #include "wegl_context.h"
33 #include "wegl_imports.h"
34 #include "wegl_platform.h"
35 #include "wegl_util.h"
36
37 // Pre EGL 1.5 headers lack the definition.
38 #ifndef EGL_CONTEXT_OPENGL_ROBUST_ACCESS
39 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
40 #endif
41
42 static bool
bind_api(struct wegl_platform * plat,int32_t waffle_context_api)43 bind_api(struct wegl_platform *plat, int32_t waffle_context_api)
44 {
45 bool ok = true;
46
47 switch (waffle_context_api) {
48 case WAFFLE_CONTEXT_OPENGL:
49 ok &= plat->eglBindAPI(EGL_OPENGL_API);
50 break;
51 case WAFFLE_CONTEXT_OPENGL_ES1:
52 case WAFFLE_CONTEXT_OPENGL_ES2:
53 case WAFFLE_CONTEXT_OPENGL_ES3:
54 ok &= plat->eglBindAPI(EGL_OPENGL_ES_API);
55 break;
56 default:
57 assert(false);
58 return false;
59 }
60
61 if (!ok)
62 wegl_emit_error(plat, "eglBindAPI");
63
64 return ok;
65 }
66
67 static EGLContext
create_real_context(struct wegl_config * config,EGLContext share_ctx)68 create_real_context(struct wegl_config *config,
69 EGLContext share_ctx)
70
71 {
72 struct wegl_display *dpy = wegl_display(config->wcore.display);
73 struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
74 struct wcore_config_attrs *attrs = &config->wcore.attrs;
75 int32_t waffle_context_api = attrs->context_api;
76 EGLint attrib_list[64];
77 EGLint context_flags = 0;
78 int i = 0;
79
80 if (attrs->context_debug) {
81 context_flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
82 }
83
84 switch (waffle_context_api) {
85 case WAFFLE_CONTEXT_OPENGL:
86 if (dpy->KHR_create_context) {
87 attrib_list[i++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
88 attrib_list[i++] = attrs->context_major_version;
89 attrib_list[i++] = EGL_CONTEXT_MINOR_VERSION_KHR;
90 attrib_list[i++] = attrs->context_minor_version;
91 }
92 else {
93 assert(attrs->context_major_version == 1);
94 assert(attrs->context_minor_version == 0);
95 }
96
97 if (attrs->context_forward_compatible) {
98 assert(dpy->KHR_create_context);
99 context_flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
100 }
101
102 if (attrs->context_robust) {
103 if (dpy->major_version > 1 || dpy->minor_version >= 5) {
104 // Use the token from EGL 1.5, not
105 // EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT. Their values
106 // differ.
107 attrib_list[i++] = EGL_CONTEXT_OPENGL_ROBUST_ACCESS;
108 attrib_list[i++] = EGL_TRUE;
109 } else {
110 assert(dpy->KHR_create_context);
111 context_flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
112 }
113 }
114
115 if (wcore_config_attrs_version_ge(attrs, 32)) {
116 assert(dpy->KHR_create_context);
117 switch (attrs->context_profile) {
118 case WAFFLE_CONTEXT_CORE_PROFILE:
119 attrib_list[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
120 attrib_list[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
121 break;
122 case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
123 attrib_list[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
124 attrib_list[i++] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
125 break;
126 default:
127 wcore_error_internal("attrs->context_profile has bad value %#x",
128 attrs->context_profile);
129 return EGL_NO_CONTEXT;
130 }
131 }
132 break;
133
134 case WAFFLE_CONTEXT_OPENGL_ES1:
135 case WAFFLE_CONTEXT_OPENGL_ES2:
136 case WAFFLE_CONTEXT_OPENGL_ES3:
137 attrib_list[i++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
138 attrib_list[i++] = attrs->context_major_version;
139
140 if (dpy->KHR_create_context) {
141 attrib_list[i++] = EGL_CONTEXT_MINOR_VERSION_KHR;
142 attrib_list[i++] = attrs->context_minor_version;
143 }
144 else {
145 assert(attrs->context_minor_version == 0);
146 }
147
148 if (attrs->context_robust) {
149 // The EGL 1.5 token and the EXT token have different values.
150 if (dpy->major_version > 1 || dpy->minor_version >= 5) {
151 attrib_list[i++] = EGL_CONTEXT_OPENGL_ROBUST_ACCESS;
152 attrib_list[i++] = EGL_TRUE;
153 } else {
154 attrib_list[i++] = EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT;
155 attrib_list[i++] = EGL_TRUE;
156 }
157 }
158 break;
159
160 default:
161 assert(false);
162 return EGL_NO_CONTEXT;
163 }
164
165 if (context_flags != 0) {
166 attrib_list[i++] = EGL_CONTEXT_FLAGS_KHR;
167 attrib_list[i++] = context_flags;
168 }
169
170 attrib_list[i++] = EGL_NONE;
171
172 if (!bind_api(plat, waffle_context_api))
173 return EGL_NO_CONTEXT;
174
175 EGLContext ctx = plat->eglCreateContext(dpy->egl, config->egl,
176 share_ctx, attrib_list);
177 if (!ctx)
178 wegl_emit_error(plat, "eglCreateContext");
179
180 return ctx;
181 }
182
183 bool
wegl_context_init(struct wegl_context * ctx,struct wcore_config * wc_config,struct wcore_context * wc_share_ctx)184 wegl_context_init(struct wegl_context *ctx,
185 struct wcore_config *wc_config,
186 struct wcore_context *wc_share_ctx)
187 {
188 struct wegl_config *config = wegl_config(wc_config);
189 struct wegl_context *share_ctx = wegl_context(wc_share_ctx);
190 bool ok;
191
192 ok = wcore_context_init(&ctx->wcore, &config->wcore);
193 if (!ok)
194 goto fail;
195
196 ctx->egl = create_real_context(config,
197 share_ctx
198 ? share_ctx->egl
199 : EGL_NO_CONTEXT);
200 if (ctx->egl == EGL_NO_CONTEXT)
201 goto fail;
202
203 return true;
204
205 fail:
206 wegl_context_teardown(ctx);
207 return false;
208 }
209
210 struct wcore_context*
wegl_context_create(struct wcore_platform * wc_plat,struct wcore_config * wc_config,struct wcore_context * wc_share_ctx)211 wegl_context_create(struct wcore_platform *wc_plat,
212 struct wcore_config *wc_config,
213 struct wcore_context *wc_share_ctx)
214 {
215 struct wegl_context *ctx;
216
217 (void) wc_plat;
218
219 ctx = wcore_calloc(sizeof(*ctx));
220 if (!ctx)
221 return NULL;
222
223 if (!wegl_context_init(ctx, wc_config, wc_share_ctx)) {
224 wegl_context_destroy(&ctx->wcore);
225 return NULL;
226 }
227
228 return &ctx->wcore;
229 }
230
231 bool
wegl_context_teardown(struct wegl_context * ctx)232 wegl_context_teardown(struct wegl_context *ctx)
233 {
234 bool result = true;
235
236 if (!ctx)
237 return result;
238
239 if (ctx->egl != EGL_NO_CONTEXT) {
240 struct wegl_display *dpy = wegl_display(ctx->wcore.display);
241 struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
242
243 if (!plat->eglDestroyContext(dpy->egl, ctx->egl)) {
244 wegl_emit_error(plat, "eglDestroyContext");
245 result = false;
246 }
247 }
248
249 result &= wcore_context_teardown(&ctx->wcore);
250 return result;
251 }
252
253 bool
wegl_context_destroy(struct wcore_context * wc_ctx)254 wegl_context_destroy(struct wcore_context *wc_ctx)
255 {
256 bool result = true;
257
258 if (wc_ctx) {
259 struct wegl_context *ctx = wegl_context(wc_ctx);
260 result = wegl_context_teardown(ctx);
261 free(ctx);
262 }
263 return result;
264 }
265