OSDN Git Service

egl: fix setting context flags
[android-x86/external-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       default:
202          err = EGL_BAD_ATTRIBUTE;
203          break;
204       }
205
206       if (err != EGL_SUCCESS) {
207          _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
208          break;
209       }
210    }
211
212    if (api == EGL_OPENGL_API) {
213       /* The EGL_KHR_create_context spec says:
214        *
215        *     "If the requested OpenGL version is less than 3.2,
216        *     EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
217        *     functionality of the context is determined solely by the
218        *     requested version."
219        *
220        * Since the value is ignored, only validate the setting if the version
221        * is >= 3.2.
222        */
223       if (ctx->ClientMajorVersion >= 4
224           || (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
225          switch (ctx->Profile) {
226          case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
227          case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
228             break;
229
230          default:
231             /* The EGL_KHR_create_context spec says:
232              *
233              *     "* If an OpenGL context is requested, the requested version
234              *        is greater than 3.2, and the value for attribute
235              *        EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
236              *        any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
237              *        and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
238              *        more than one of these bits set; or if the implementation does
239              *        not support the requested profile, then an EGL_BAD_MATCH error
240              *        is generated."
241              */
242             err = EGL_BAD_MATCH;
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          /* Don't put additional version checks here.  We don't know that
327           * there won't be versions > 3.0.
328           */
329          break;
330
331       default:
332          err = EGL_BAD_MATCH;
333          break;
334       }
335    }
336
337    switch (ctx->ResetNotificationStrategy) {
338    case EGL_NO_RESET_NOTIFICATION_KHR:
339    case EGL_LOSE_CONTEXT_ON_RESET_KHR:
340       break;
341
342    default:
343       err = EGL_BAD_ATTRIBUTE;
344       break;
345    }
346
347    if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
348                       | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
349                       | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
350       err = EGL_BAD_ATTRIBUTE;
351    }
352
353    return err;
354 }
355
356
357 /**
358  * Initialize the given _EGLContext object to defaults and/or the values
359  * in the attrib_list.
360  */
361 EGLBoolean
362 _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
363                 const EGLint *attrib_list)
364 {
365    const EGLenum api = eglQueryAPI();
366    EGLint err;
367
368    if (api == EGL_NONE) {
369       _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
370       return EGL_FALSE;
371    }
372
373    _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
374    ctx->ClientAPI = api;
375    ctx->Config = conf;
376    ctx->WindowRenderBuffer = EGL_NONE;
377    ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
378
379    ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
380    ctx->ClientMinorVersion = 0;
381    ctx->Flags = 0;
382    ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
383    ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
384
385    err = _eglParseContextAttribList(ctx, dpy, attrib_list);
386    if (err == EGL_SUCCESS && ctx->Config) {
387       EGLint api_bit;
388
389       api_bit = _eglGetContextAPIBit(ctx);
390       if (!(ctx->Config->RenderableType & api_bit)) {
391          _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
392                api_bit, ctx->Config->RenderableType);
393          err = EGL_BAD_CONFIG;
394       }
395    }
396    if (err != EGL_SUCCESS)
397       return _eglError(err, "eglCreateContext");
398
399    return EGL_TRUE;
400 }
401
402
403 static EGLint
404 _eglQueryContextRenderBuffer(_EGLContext *ctx)
405 {
406    _EGLSurface *surf = ctx->DrawSurface;
407    EGLint rb;
408
409    if (!surf)
410       return EGL_NONE;
411    if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
412       rb = ctx->WindowRenderBuffer;
413    else
414       rb = surf->RenderBuffer;
415    return rb;
416 }
417
418
419 EGLBoolean
420 _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
421                  EGLint attribute, EGLint *value)
422 {
423    (void) drv;
424    (void) dpy;
425
426    if (!value)
427       return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
428
429    switch (attribute) {
430    case EGL_CONFIG_ID:
431       if (!c->Config)
432          return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
433       *value = c->Config->ConfigID;
434       break;
435    case EGL_CONTEXT_CLIENT_VERSION:
436       *value = c->ClientMajorVersion;
437       break;
438    case EGL_CONTEXT_CLIENT_TYPE:
439       *value = c->ClientAPI;
440       break;
441    case EGL_RENDER_BUFFER:
442       *value = _eglQueryContextRenderBuffer(c);
443       break;
444    default:
445       return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
446    }
447
448    return EGL_TRUE;
449 }
450
451
452 /**
453  * Bind the context to the thread and return the previous context.
454  *
455  * Note that the context may be NULL.
456  */
457 static _EGLContext *
458 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
459 {
460    EGLint apiIndex;
461    _EGLContext *oldCtx;
462
463    apiIndex = (ctx) ?
464       _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
465
466    oldCtx = t->CurrentContexts[apiIndex];
467    if (ctx != oldCtx) {
468       if (oldCtx)
469          oldCtx->Binding = NULL;
470       if (ctx)
471          ctx->Binding = t;
472
473       t->CurrentContexts[apiIndex] = ctx;
474    }
475
476    return oldCtx;
477 }
478
479
480 /**
481  * Return true if the given context and surfaces can be made current.
482  */
483 static EGLBoolean
484 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
485 {
486    _EGLThreadInfo *t = _eglGetCurrentThread();
487    _EGLDisplay *dpy;
488    EGLint conflict_api;
489
490    if (_eglIsCurrentThreadDummy())
491       return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
492
493    /* this is easy */
494    if (!ctx) {
495       if (draw || read)
496          return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
497       return EGL_TRUE;
498    }
499
500    dpy = ctx->Resource.Display;
501    if (!dpy->Extensions.KHR_surfaceless_context
502        && (draw == NULL || read == NULL))
503       return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
504
505    /*
506     * The spec says
507     *
508     * "If ctx is current to some other thread, or if either draw or read are
509     * bound to contexts in another thread, an EGL_BAD_ACCESS error is
510     * generated."
511     *
512     * and
513     *
514     * "at most one context may be bound to a particular surface at a given
515     * time"
516     */
517    if (ctx->Binding && ctx->Binding != t)
518       return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
519    if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
520       if (draw->CurrentContext->Binding != t ||
521           draw->CurrentContext->ClientAPI != ctx->ClientAPI)
522          return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
523    }
524    if (read && read->CurrentContext && read->CurrentContext != ctx) {
525       if (read->CurrentContext->Binding != t ||
526           read->CurrentContext->ClientAPI != ctx->ClientAPI)
527          return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
528    }
529
530    /* If the context has a config then it must match that of the two
531     * surfaces */
532    if (ctx->Config) {
533       if ((draw && draw->Config != ctx->Config) ||
534           (read && read->Config != ctx->Config))
535          return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
536    } else {
537       /* Otherwise we must be using the EGL_MESA_configless_context
538        * extension */
539       assert(dpy->Extensions.MESA_configless_context);
540
541       /* The extension doesn't permit binding draw and read buffers with
542        * differing contexts */
543       if (draw && read && draw->Config != read->Config)
544          return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
545    }
546
547    switch (ctx->ClientAPI) {
548    /* OpenGL and OpenGL ES are conflicting */
549    case EGL_OPENGL_ES_API:
550       conflict_api = EGL_OPENGL_API;
551       break;
552    case EGL_OPENGL_API:
553       conflict_api = EGL_OPENGL_ES_API;
554       break;
555    default:
556       conflict_api = -1;
557       break;
558    }
559
560    if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
561       return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
562
563    return EGL_TRUE;
564 }
565
566
567 /**
568  * Bind the context to the current thread and given surfaces.  Return the
569  * previous bound context and surfaces.  The caller should unreference the
570  * returned context and surfaces.
571  *
572  * Making a second call with the resources returned by the first call
573  * unsurprisingly undoes the first call, except for the resouce reference
574  * counts.
575  */
576 EGLBoolean
577 _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
578                 _EGLContext **old_ctx,
579                 _EGLSurface **old_draw, _EGLSurface **old_read)
580 {
581    _EGLThreadInfo *t = _eglGetCurrentThread();
582    _EGLContext *prev_ctx;
583    _EGLSurface *prev_draw, *prev_read;
584
585    if (!_eglCheckMakeCurrent(ctx, draw, read))
586       return EGL_FALSE;
587
588    /* increment refcounts before binding */
589    _eglGetContext(ctx);
590    _eglGetSurface(draw);
591    _eglGetSurface(read);
592
593    /* bind the new context */
594    prev_ctx = _eglBindContextToThread(ctx, t);
595
596    /* break previous bindings */
597    if (prev_ctx) {
598       prev_draw = prev_ctx->DrawSurface;
599       prev_read = prev_ctx->ReadSurface;
600
601       if (prev_draw)
602          prev_draw->CurrentContext = NULL;
603       if (prev_read)
604          prev_read->CurrentContext = NULL;
605
606       prev_ctx->DrawSurface = NULL;
607       prev_ctx->ReadSurface = NULL;
608    }
609    else {
610       prev_draw = prev_read = NULL;
611    }
612
613    /* establish new bindings */
614    if (ctx) {
615       if (draw)
616          draw->CurrentContext = ctx;
617       if (read)
618          read->CurrentContext = ctx;
619
620       ctx->DrawSurface = draw;
621       ctx->ReadSurface = read;
622    }
623
624    assert(old_ctx && old_draw && old_read);
625    *old_ctx = prev_ctx;
626    *old_draw = prev_draw;
627    *old_read = prev_read;
628
629    return EGL_TRUE;
630 }