Merge branch 'wip/nir-vtn' into vulkan
[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 if (val == EGL_TRUE)
198 ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
199 break;
200
201 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
202 if (dpy->Version < 15) {
203 err = EGL_BAD_ATTRIBUTE;
204 break;
205 }
206
207 if (val == EGL_TRUE)
208 ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
209 break;
210
211 case EGL_CONTEXT_OPENGL_DEBUG:
212 if (dpy->Version < 15) {
213 err = EGL_BAD_ATTRIBUTE;
214 break;
215 }
216
217 if (val == EGL_TRUE)
218 ctx->Flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
219 break;
220
221 case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE:
222 if (dpy->Version < 15) {
223 err = EGL_BAD_ATTRIBUTE;
224 break;
225 }
226
227 if (val == EGL_TRUE)
228 ctx->Flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
229 break;
230
231 default:
232 err = EGL_BAD_ATTRIBUTE;
233 break;
234 }
235
236 if (err != EGL_SUCCESS) {
237 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
238 break;
239 }
240 }
241
242 if (api == EGL_OPENGL_API) {
243 /* The EGL_KHR_create_context spec says:
244 *
245 * "If the requested OpenGL version is less than 3.2,
246 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
247 * functionality of the context is determined solely by the
248 * requested version."
249 *
250 * Since the value is ignored, only validate the setting if the version
251 * is >= 3.2.
252 */
253 if (ctx->ClientMajorVersion >= 4
254 || (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
255 switch (ctx->Profile) {
256 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
257 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
258 break;
259
260 default:
261 /* The EGL_KHR_create_context spec says:
262 *
263 * "* If an OpenGL context is requested, the requested version
264 * is greater than 3.2, and the value for attribute
265 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
266 * any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
267 * and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
268 * more than one of these bits set; or if the implementation does
269 * not support the requested profile, then an EGL_BAD_MATCH error
270 * is generated."
271 */
272 err = EGL_BAD_MATCH;
273 break;
274 }
275 }
276
277 /* The EGL_KHR_create_context spec says:
278 *
279 * "* If an OpenGL context is requested and the values for
280 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
281 * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
282 * the value for attribute
283 * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
284 * version and feature set that are not defined, than an
285 * EGL_BAD_MATCH error is generated.
286 *
287 * ... Thus, examples of invalid combinations of attributes
288 * include:
289 *
290 * - Major version < 1 or > 4
291 * - Major version == 1 and minor version < 0 or > 5
292 * - Major version == 2 and minor version < 0 or > 1
293 * - Major version == 3 and minor version < 0 or > 2
294 * - Major version == 4 and minor version < 0 or > 2
295 * - Forward-compatible flag set and major version < 3"
296 */
297 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
298 err = EGL_BAD_MATCH;
299
300 switch (ctx->ClientMajorVersion) {
301 case 1:
302 if (ctx->ClientMinorVersion > 5
303 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
304 err = EGL_BAD_MATCH;
305 break;
306
307 case 2:
308 if (ctx->ClientMinorVersion > 1
309 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
310 err = EGL_BAD_MATCH;
311 break;
312
313 case 3:
314 /* Note: The text above is incorrect. There *is* an OpenGL 3.3!
315 */
316 if (ctx->ClientMinorVersion > 3)
317 err = EGL_BAD_MATCH;
318 break;
319
320 case 4:
321 default:
322 /* Don't put additional version checks here. We don't know that
323 * there won't be versions > 4.2.
324 */
325 break;
326 }
327 } else if (api == EGL_OPENGL_ES_API) {
328 /* The EGL_KHR_create_context spec says:
329 *
330 * "* If an OpenGL ES context is requested and the values for
331 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
332 * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
333 * is not defined, than an EGL_BAD_MATCH error is generated.
334 *
335 * ... Examples of invalid combinations of attributes include:
336 *
337 * - Major version < 1 or > 2
338 * - Major version == 1 and minor version < 0 or > 1
339 * - Major version == 2 and minor version != 0
340 */
341 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
342 err = EGL_BAD_MATCH;
343
344 switch (ctx->ClientMajorVersion) {
345 case 1:
346 if (ctx->ClientMinorVersion > 1)
347 err = EGL_BAD_MATCH;
348 break;
349
350 case 2:
351 if (ctx->ClientMinorVersion > 0)
352 err = EGL_BAD_MATCH;
353 break;
354
355 case 3:
356 /* Don't put additional version checks here. We don't know that
357 * there won't be versions > 3.0.
358 */
359 break;
360
361 default:
362 err = EGL_BAD_MATCH;
363 break;
364 }
365 }
366
367 switch (ctx->ResetNotificationStrategy) {
368 case EGL_NO_RESET_NOTIFICATION_KHR:
369 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
370 break;
371
372 default:
373 err = EGL_BAD_ATTRIBUTE;
374 break;
375 }
376
377 if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
378 | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
379 | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
380 err = EGL_BAD_ATTRIBUTE;
381 }
382
383 return err;
384 }
385
386
387 /**
388 * Initialize the given _EGLContext object to defaults and/or the values
389 * in the attrib_list.
390 */
391 EGLBoolean
392 _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
393 const EGLint *attrib_list)
394 {
395 const EGLenum api = eglQueryAPI();
396 EGLint err;
397
398 if (api == EGL_NONE) {
399 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
400 return EGL_FALSE;
401 }
402
403 _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
404 ctx->ClientAPI = api;
405 ctx->Config = conf;
406 ctx->WindowRenderBuffer = EGL_NONE;
407 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
408
409 ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
410 ctx->ClientMinorVersion = 0;
411 ctx->Flags = 0;
412 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
413 ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
414
415 err = _eglParseContextAttribList(ctx, dpy, attrib_list);
416 if (err == EGL_SUCCESS && ctx->Config) {
417 EGLint api_bit;
418
419 api_bit = _eglGetContextAPIBit(ctx);
420 if (!(ctx->Config->RenderableType & api_bit)) {
421 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
422 api_bit, ctx->Config->RenderableType);
423 err = EGL_BAD_CONFIG;
424 }
425 }
426 if (err != EGL_SUCCESS)
427 return _eglError(err, "eglCreateContext");
428
429 return EGL_TRUE;
430 }
431
432
433 static EGLint
434 _eglQueryContextRenderBuffer(_EGLContext *ctx)
435 {
436 _EGLSurface *surf = ctx->DrawSurface;
437 EGLint rb;
438
439 if (!surf)
440 return EGL_NONE;
441 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
442 rb = ctx->WindowRenderBuffer;
443 else
444 rb = surf->RenderBuffer;
445 return rb;
446 }
447
448
449 EGLBoolean
450 _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
451 EGLint attribute, EGLint *value)
452 {
453 (void) drv;
454 (void) dpy;
455
456 if (!value)
457 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
458
459 switch (attribute) {
460 case EGL_CONFIG_ID:
461 if (!c->Config)
462 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
463 *value = c->Config->ConfigID;
464 break;
465 case EGL_CONTEXT_CLIENT_VERSION:
466 *value = c->ClientMajorVersion;
467 break;
468 case EGL_CONTEXT_CLIENT_TYPE:
469 *value = c->ClientAPI;
470 break;
471 case EGL_RENDER_BUFFER:
472 *value = _eglQueryContextRenderBuffer(c);
473 break;
474 default:
475 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
476 }
477
478 return EGL_TRUE;
479 }
480
481
482 /**
483 * Bind the context to the thread and return the previous context.
484 *
485 * Note that the context may be NULL.
486 */
487 static _EGLContext *
488 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
489 {
490 EGLint apiIndex;
491 _EGLContext *oldCtx;
492
493 apiIndex = (ctx) ?
494 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
495
496 oldCtx = t->CurrentContexts[apiIndex];
497 if (ctx != oldCtx) {
498 if (oldCtx)
499 oldCtx->Binding = NULL;
500 if (ctx)
501 ctx->Binding = t;
502
503 t->CurrentContexts[apiIndex] = ctx;
504 }
505
506 return oldCtx;
507 }
508
509
510 /**
511 * Return true if the given context and surfaces can be made current.
512 */
513 static EGLBoolean
514 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
515 {
516 _EGLThreadInfo *t = _eglGetCurrentThread();
517 _EGLDisplay *dpy;
518 EGLint conflict_api;
519
520 if (_eglIsCurrentThreadDummy())
521 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
522
523 /* this is easy */
524 if (!ctx) {
525 if (draw || read)
526 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
527 return EGL_TRUE;
528 }
529
530 dpy = ctx->Resource.Display;
531 if (!dpy->Extensions.KHR_surfaceless_context
532 && (draw == NULL || read == NULL))
533 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
534
535 /*
536 * The spec says
537 *
538 * "If ctx is current to some other thread, or if either draw or read are
539 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
540 * generated."
541 *
542 * and
543 *
544 * "at most one context may be bound to a particular surface at a given
545 * time"
546 */
547 if (ctx->Binding && ctx->Binding != t)
548 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
549 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
550 if (draw->CurrentContext->Binding != t ||
551 draw->CurrentContext->ClientAPI != ctx->ClientAPI)
552 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
553 }
554 if (read && read->CurrentContext && read->CurrentContext != ctx) {
555 if (read->CurrentContext->Binding != t ||
556 read->CurrentContext->ClientAPI != ctx->ClientAPI)
557 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
558 }
559
560 /* If the context has a config then it must match that of the two
561 * surfaces */
562 if (ctx->Config) {
563 if ((draw && draw->Config != ctx->Config) ||
564 (read && read->Config != ctx->Config))
565 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
566 } else {
567 /* Otherwise we must be using the EGL_MESA_configless_context
568 * extension */
569 assert(dpy->Extensions.MESA_configless_context);
570
571 /* The extension doesn't permit binding draw and read buffers with
572 * differing contexts */
573 if (draw && read && draw->Config != read->Config)
574 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
575 }
576
577 switch (ctx->ClientAPI) {
578 /* OpenGL and OpenGL ES are conflicting */
579 case EGL_OPENGL_ES_API:
580 conflict_api = EGL_OPENGL_API;
581 break;
582 case EGL_OPENGL_API:
583 conflict_api = EGL_OPENGL_ES_API;
584 break;
585 default:
586 conflict_api = -1;
587 break;
588 }
589
590 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
591 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
592
593 return EGL_TRUE;
594 }
595
596
597 /**
598 * Bind the context to the current thread and given surfaces. Return the
599 * previous bound context and surfaces. The caller should unreference the
600 * returned context and surfaces.
601 *
602 * Making a second call with the resources returned by the first call
603 * unsurprisingly undoes the first call, except for the resouce reference
604 * counts.
605 */
606 EGLBoolean
607 _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
608 _EGLContext **old_ctx,
609 _EGLSurface **old_draw, _EGLSurface **old_read)
610 {
611 _EGLThreadInfo *t = _eglGetCurrentThread();
612 _EGLContext *prev_ctx;
613 _EGLSurface *prev_draw, *prev_read;
614
615 if (!_eglCheckMakeCurrent(ctx, draw, read))
616 return EGL_FALSE;
617
618 /* increment refcounts before binding */
619 _eglGetContext(ctx);
620 _eglGetSurface(draw);
621 _eglGetSurface(read);
622
623 /* bind the new context */
624 prev_ctx = _eglBindContextToThread(ctx, t);
625
626 /* break previous bindings */
627 if (prev_ctx) {
628 prev_draw = prev_ctx->DrawSurface;
629 prev_read = prev_ctx->ReadSurface;
630
631 if (prev_draw)
632 prev_draw->CurrentContext = NULL;
633 if (prev_read)
634 prev_read->CurrentContext = NULL;
635
636 prev_ctx->DrawSurface = NULL;
637 prev_ctx->ReadSurface = NULL;
638 }
639 else {
640 prev_draw = prev_read = NULL;
641 }
642
643 /* establish new bindings */
644 if (ctx) {
645 if (draw)
646 draw->CurrentContext = ctx;
647 if (read)
648 read->CurrentContext = ctx;
649
650 ctx->DrawSurface = draw;
651 ctx->ReadSurface = read;
652 }
653
654 assert(old_ctx && old_draw && old_read);
655 *old_ctx = prev_ctx;
656 *old_draw = prev_draw;
657 *old_read = prev_read;
658
659 return EGL_TRUE;
660 }