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