eglcontext.c revision af69d88d
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 */
45static 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 */
83static 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 */
360EGLBoolean
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
402static 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
418EGLBoolean
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 */
456static _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 */
482static 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 */
575EGLBoolean
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}
630