egl: Fix OpenGL ES version checks in _eglParseContextAttribList()
[mesa.git] / src / egl / main / eglcontext.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "eglconfig.h"
35 #include "eglcontext.h"
36 #include "egldisplay.h"
37 #include "eglcurrent.h"
38 #include "eglsurface.h"
39 #include "egllog.h"
40
41
42 /**
43 * Return the API bit (one of EGL_xxx_BIT) of the context.
44 */
45 static EGLint
46 _eglGetContextAPIBit(_EGLContext *ctx)
47 {
48 EGLint bit = 0;
49
50 switch (ctx->ClientAPI) {
51 case EGL_OPENGL_ES_API:
52 switch (ctx->ClientMajorVersion) {
53 case 1:
54 bit = EGL_OPENGL_ES_BIT;
55 break;
56 case 2:
57 bit = EGL_OPENGL_ES2_BIT;
58 break;
59 case 3:
60 bit = EGL_OPENGL_ES3_BIT_KHR;
61 break;
62 default:
63 break;
64 }
65 break;
66 case EGL_OPENVG_API:
67 bit = EGL_OPENVG_BIT;
68 break;
69 case EGL_OPENGL_API:
70 bit = EGL_OPENGL_BIT;
71 break;
72 default:
73 break;
74 }
75
76 return bit;
77 }
78
79
80 /**
81 * Parse the list of context attributes and return the proper error code.
82 */
83 static EGLint
84 _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
85 const EGLint *attrib_list)
86 {
87 EGLenum api = ctx->ClientAPI;
88 EGLint i, err = EGL_SUCCESS;
89
90 if (!attrib_list)
91 return EGL_SUCCESS;
92
93 if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) {
94 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]);
95 return EGL_BAD_ATTRIBUTE;
96 }
97
98 for (i = 0; attrib_list[i] != EGL_NONE; i++) {
99 EGLint attr = attrib_list[i++];
100 EGLint val = attrib_list[i];
101
102 switch (attr) {
103 case EGL_CONTEXT_CLIENT_VERSION:
104 ctx->ClientMajorVersion = val;
105 break;
106
107 case EGL_CONTEXT_MINOR_VERSION_KHR:
108 if (!dpy->Extensions.KHR_create_context) {
109 err = EGL_BAD_ATTRIBUTE;
110 break;
111 }
112
113 ctx->ClientMinorVersion = val;
114 break;
115
116 case EGL_CONTEXT_FLAGS_KHR:
117 if (!dpy->Extensions.KHR_create_context) {
118 err = EGL_BAD_ATTRIBUTE;
119 break;
120 }
121
122 /* The EGL_KHR_create_context spec says:
123 *
124 * "Flags are only defined for OpenGL context creation, and
125 * specifying a flags value other than zero for other types of
126 * contexts, including OpenGL ES contexts, will generate an
127 * error."
128 */
129 if (api != EGL_OPENGL_API && val != 0) {
130 err = EGL_BAD_ATTRIBUTE;
131 break;
132 }
133
134 ctx->Flags = val;
135 break;
136
137 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
138 if (!dpy->Extensions.KHR_create_context) {
139 err = EGL_BAD_ATTRIBUTE;
140 break;
141 }
142
143 /* The EGL_KHR_create_context spec says:
144 *
145 * "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
146 * OpenGL contexts, and specifying it for other types of
147 * contexts, including OpenGL ES contexts, will generate an
148 * error."
149 */
150 if (api != EGL_OPENGL_API) {
151 err = EGL_BAD_ATTRIBUTE;
152 break;
153 }
154
155 ctx->Profile = val;
156 break;
157
158 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
159 /* The EGL_KHR_create_context spec says:
160 *
161 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
162 * meaningful for OpenGL contexts, and specifying it for other
163 * types of contexts, including OpenGL ES contexts, will generate
164 * an error."
165 */
166 if (!dpy->Extensions.KHR_create_context
167 || api != EGL_OPENGL_API) {
168 err = EGL_BAD_ATTRIBUTE;
169 break;
170 }
171
172 ctx->ResetNotificationStrategy = val;
173 break;
174
175 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
176 /* The EGL_EXT_create_context_robustness spec says:
177 *
178 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
179 * meaningful for OpenGL ES contexts, and specifying it for other
180 * types of contexts will generate an EGL_BAD_ATTRIBUTE error."
181 */
182 if (!dpy->Extensions.EXT_create_context_robustness
183 || api != EGL_OPENGL_ES_API) {
184 err = EGL_BAD_ATTRIBUTE;
185 break;
186 }
187
188 ctx->ResetNotificationStrategy = val;
189 break;
190
191 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
192 if (!dpy->Extensions.EXT_create_context_robustness) {
193 err = EGL_BAD_ATTRIBUTE;
194 break;
195 }
196
197 ctx->Flags = EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
198 break;
199
200 default:
201 err = EGL_BAD_ATTRIBUTE;
202 break;
203 }
204
205 if (err != EGL_SUCCESS) {
206 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
207 break;
208 }
209 }
210
211 if (api == EGL_OPENGL_API) {
212 /* The EGL_KHR_create_context spec says:
213 *
214 * "If the requested OpenGL version is less than 3.2,
215 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
216 * functionality of the context is determined solely by the
217 * requested version."
218 *
219 * Since the value is ignored, only validate the setting if the version
220 * is >= 3.2.
221 */
222 if (ctx->ClientMajorVersion >= 4
223 || (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
224 switch (ctx->Profile) {
225 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
226 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
227 break;
228
229 default:
230 /* The EGL_KHR_create_context spec says:
231 *
232 * "* If an OpenGL context is requested, the requested version
233 * is greater than 3.2, and the value for attribute
234 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
235 * any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
236 * and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
237 * more than one of these bits set; or if the implementation does
238 * not support the requested profile, then an EGL_BAD_MATCH error
239 * is generated."
240 */
241 err = EGL_BAD_MATCH;
242 break;
243 }
244 }
245
246 /* The EGL_KHR_create_context spec says:
247 *
248 * "* If an OpenGL context is requested and the values for
249 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
250 * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
251 * the value for attribute
252 * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
253 * version and feature set that are not defined, than an
254 * EGL_BAD_MATCH error is generated.
255 *
256 * ... Thus, examples of invalid combinations of attributes
257 * include:
258 *
259 * - Major version < 1 or > 4
260 * - Major version == 1 and minor version < 0 or > 5
261 * - Major version == 2 and minor version < 0 or > 1
262 * - Major version == 3 and minor version < 0 or > 2
263 * - Major version == 4 and minor version < 0 or > 2
264 * - Forward-compatible flag set and major version < 3"
265 */
266 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
267 err = EGL_BAD_MATCH;
268
269 switch (ctx->ClientMajorVersion) {
270 case 1:
271 if (ctx->ClientMinorVersion > 5
272 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
273 err = EGL_BAD_MATCH;
274 break;
275
276 case 2:
277 if (ctx->ClientMinorVersion > 1
278 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
279 err = EGL_BAD_MATCH;
280 break;
281
282 case 3:
283 /* Note: The text above is incorrect. There *is* an OpenGL 3.3!
284 */
285 if (ctx->ClientMinorVersion > 3)
286 err = EGL_BAD_MATCH;
287 break;
288
289 case 4:
290 default:
291 /* Don't put additional version checks here. We don't know that
292 * there won't be versions > 4.2.
293 */
294 break;
295 }
296 } else if (api == EGL_OPENGL_ES_API) {
297 /* The EGL_KHR_create_context spec says:
298 *
299 * "* If an OpenGL ES context is requested and the values for
300 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
301 * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
302 * is not defined, than an EGL_BAD_MATCH error is generated.
303 *
304 * ... Examples of invalid combinations of attributes include:
305 *
306 * - Major version < 1 or > 2
307 * - Major version == 1 and minor version < 0 or > 1
308 * - Major version == 2 and minor version != 0
309 */
310 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
311 err = EGL_BAD_MATCH;
312
313 switch (ctx->ClientMajorVersion) {
314 case 1:
315 if (ctx->ClientMinorVersion > 1)
316 err = EGL_BAD_MATCH;
317 break;
318
319 case 2:
320 if (ctx->ClientMinorVersion > 0)
321 err = EGL_BAD_MATCH;
322 break;
323
324 case 3:
325 /* Don't put additional version checks here. We don't know that
326 * there won't be versions > 3.0.
327 */
328 break;
329
330 default:
331 err = EGL_BAD_MATCH;
332 break;
333 }
334 }
335
336 switch (ctx->ResetNotificationStrategy) {
337 case EGL_NO_RESET_NOTIFICATION_KHR:
338 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
339 break;
340
341 default:
342 err = EGL_BAD_ATTRIBUTE;
343 break;
344 }
345
346 if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
347 | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
348 | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
349 err = EGL_BAD_ATTRIBUTE;
350 }
351
352 return err;
353 }
354
355
356 /**
357 * Initialize the given _EGLContext object to defaults and/or the values
358 * in the attrib_list.
359 */
360 EGLBoolean
361 _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
362 const EGLint *attrib_list)
363 {
364 const EGLenum api = eglQueryAPI();
365 EGLint err;
366
367 if (api == EGL_NONE) {
368 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
369 return EGL_FALSE;
370 }
371
372 _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
373 ctx->ClientAPI = api;
374 ctx->Config = conf;
375 ctx->WindowRenderBuffer = EGL_NONE;
376 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
377
378 ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
379 ctx->ClientMinorVersion = 0;
380 ctx->Flags = 0;
381 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
382 ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
383
384 err = _eglParseContextAttribList(ctx, dpy, attrib_list);
385 if (err == EGL_SUCCESS && ctx->Config) {
386 EGLint api_bit;
387
388 api_bit = _eglGetContextAPIBit(ctx);
389 if (!(ctx->Config->RenderableType & api_bit)) {
390 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
391 api_bit, ctx->Config->RenderableType);
392 err = EGL_BAD_CONFIG;
393 }
394 }
395 if (err != EGL_SUCCESS)
396 return _eglError(err, "eglCreateContext");
397
398 return EGL_TRUE;
399 }
400
401
402 static EGLint
403 _eglQueryContextRenderBuffer(_EGLContext *ctx)
404 {
405 _EGLSurface *surf = ctx->DrawSurface;
406 EGLint rb;
407
408 if (!surf)
409 return EGL_NONE;
410 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
411 rb = ctx->WindowRenderBuffer;
412 else
413 rb = surf->RenderBuffer;
414 return rb;
415 }
416
417
418 EGLBoolean
419 _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
420 EGLint attribute, EGLint *value)
421 {
422 (void) drv;
423 (void) dpy;
424
425 if (!value)
426 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
427
428 switch (attribute) {
429 case EGL_CONFIG_ID:
430 if (!c->Config)
431 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
432 *value = c->Config->ConfigID;
433 break;
434 case EGL_CONTEXT_CLIENT_VERSION:
435 *value = c->ClientMajorVersion;
436 break;
437 case EGL_CONTEXT_CLIENT_TYPE:
438 *value = c->ClientAPI;
439 break;
440 case EGL_RENDER_BUFFER:
441 *value = _eglQueryContextRenderBuffer(c);
442 break;
443 default:
444 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
445 }
446
447 return EGL_TRUE;
448 }
449
450
451 /**
452 * Bind the context to the thread and return the previous context.
453 *
454 * Note that the context may be NULL.
455 */
456 static _EGLContext *
457 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
458 {
459 EGLint apiIndex;
460 _EGLContext *oldCtx;
461
462 apiIndex = (ctx) ?
463 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
464
465 oldCtx = t->CurrentContexts[apiIndex];
466 if (ctx != oldCtx) {
467 if (oldCtx)
468 oldCtx->Binding = NULL;
469 if (ctx)
470 ctx->Binding = t;
471
472 t->CurrentContexts[apiIndex] = ctx;
473 }
474
475 return oldCtx;
476 }
477
478
479 /**
480 * Return true if the given context and surfaces can be made current.
481 */
482 static EGLBoolean
483 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
484 {
485 _EGLThreadInfo *t = _eglGetCurrentThread();
486 _EGLDisplay *dpy;
487 EGLint conflict_api;
488
489 if (_eglIsCurrentThreadDummy())
490 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
491
492 /* this is easy */
493 if (!ctx) {
494 if (draw || read)
495 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
496 return EGL_TRUE;
497 }
498
499 dpy = ctx->Resource.Display;
500 if (!dpy->Extensions.KHR_surfaceless_context
501 && (draw == NULL || read == NULL))
502 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
503
504 /*
505 * The spec says
506 *
507 * "If ctx is current to some other thread, or if either draw or read are
508 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
509 * generated."
510 *
511 * and
512 *
513 * "at most one context may be bound to a particular surface at a given
514 * time"
515 */
516 if (ctx->Binding && ctx->Binding != t)
517 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
518 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
519 if (draw->CurrentContext->Binding != t ||
520 draw->CurrentContext->ClientAPI != ctx->ClientAPI)
521 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
522 }
523 if (read && read->CurrentContext && read->CurrentContext != ctx) {
524 if (read->CurrentContext->Binding != t ||
525 read->CurrentContext->ClientAPI != ctx->ClientAPI)
526 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
527 }
528
529 /* If the context has a config then it must match that of the two
530 * surfaces */
531 if (ctx->Config) {
532 if ((draw && draw->Config != ctx->Config) ||
533 (read && read->Config != ctx->Config))
534 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
535 } else {
536 /* Otherwise we must be using the EGL_MESA_configless_context
537 * extension */
538 assert(dpy->Extensions.MESA_configless_context);
539
540 /* The extension doesn't permit binding draw and read buffers with
541 * differing contexts */
542 if (draw && read && draw->Config != read->Config)
543 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
544 }
545
546 switch (ctx->ClientAPI) {
547 /* OpenGL and OpenGL ES are conflicting */
548 case EGL_OPENGL_ES_API:
549 conflict_api = EGL_OPENGL_API;
550 break;
551 case EGL_OPENGL_API:
552 conflict_api = EGL_OPENGL_ES_API;
553 break;
554 default:
555 conflict_api = -1;
556 break;
557 }
558
559 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
560 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
561
562 return EGL_TRUE;
563 }
564
565
566 /**
567 * Bind the context to the current thread and given surfaces. Return the
568 * previous bound context and surfaces. The caller should unreference the
569 * returned context and surfaces.
570 *
571 * Making a second call with the resources returned by the first call
572 * unsurprisingly undoes the first call, except for the resouce reference
573 * counts.
574 */
575 EGLBoolean
576 _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
577 _EGLContext **old_ctx,
578 _EGLSurface **old_draw, _EGLSurface **old_read)
579 {
580 _EGLThreadInfo *t = _eglGetCurrentThread();
581 _EGLContext *prev_ctx;
582 _EGLSurface *prev_draw, *prev_read;
583
584 if (!_eglCheckMakeCurrent(ctx, draw, read))
585 return EGL_FALSE;
586
587 /* increment refcounts before binding */
588 _eglGetContext(ctx);
589 _eglGetSurface(draw);
590 _eglGetSurface(read);
591
592 /* bind the new context */
593 prev_ctx = _eglBindContextToThread(ctx, t);
594
595 /* break previous bindings */
596 if (prev_ctx) {
597 prev_draw = prev_ctx->DrawSurface;
598 prev_read = prev_ctx->ReadSurface;
599
600 if (prev_draw)
601 prev_draw->CurrentContext = NULL;
602 if (prev_read)
603 prev_read->CurrentContext = NULL;
604
605 prev_ctx->DrawSurface = NULL;
606 prev_ctx->ReadSurface = NULL;
607 }
608 else {
609 prev_draw = prev_read = NULL;
610 }
611
612 /* establish new bindings */
613 if (ctx) {
614 if (draw)
615 draw->CurrentContext = ctx;
616 if (read)
617 read->CurrentContext = ctx;
618
619 ctx->DrawSurface = draw;
620 ctx->ReadSurface = read;
621 }
622
623 assert(old_ctx && old_draw && old_read);
624 *old_ctx = prev_ctx;
625 *old_draw = prev_draw;
626 *old_read = prev_read;
627
628 return EGL_TRUE;
629 }