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