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