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