135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2011 Intel Corporation
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1235c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1335c4bbdfSmrg * Software.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1635c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1735c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1835c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1935c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2035c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2135c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2235c4bbdfSmrg */
2335c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H
2435c4bbdfSmrg#include <dix-config.h>
2535c4bbdfSmrg#endif
2635c4bbdfSmrg
2735c4bbdfSmrg#include <GL/glxtokens.h>
2835c4bbdfSmrg#include "glxserver.h"
2935c4bbdfSmrg#include "glxext.h"
3035c4bbdfSmrg#include "indirect_dispatch.h"
311b5d61b8Smrg#include "opaque.h"
3235c4bbdfSmrg
3335c4bbdfSmrg#define ALL_VALID_FLAGS \
3435c4bbdfSmrg    (GLX_CONTEXT_DEBUG_BIT_ARB | GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB \
3535c4bbdfSmrg     | GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB)
3635c4bbdfSmrg
3735c4bbdfSmrgstatic Bool
3835c4bbdfSmrgvalidate_GL_version(int major_version, int minor_version)
3935c4bbdfSmrg{
4035c4bbdfSmrg    if (major_version <= 0 || minor_version < 0)
411b5d61b8Smrg        return FALSE;
4235c4bbdfSmrg
4335c4bbdfSmrg    switch (major_version) {
4435c4bbdfSmrg    case 1:
4535c4bbdfSmrg        if (minor_version > 5)
461b5d61b8Smrg            return FALSE;
4735c4bbdfSmrg        break;
4835c4bbdfSmrg
4935c4bbdfSmrg    case 2:
5035c4bbdfSmrg        if (minor_version > 1)
511b5d61b8Smrg            return FALSE;
5235c4bbdfSmrg        break;
5335c4bbdfSmrg
5435c4bbdfSmrg    case 3:
5535c4bbdfSmrg        if (minor_version > 3)
561b5d61b8Smrg            return FALSE;
5735c4bbdfSmrg        break;
5835c4bbdfSmrg
5935c4bbdfSmrg    default:
6035c4bbdfSmrg        break;
6135c4bbdfSmrg    }
6235c4bbdfSmrg
631b5d61b8Smrg    return TRUE;
6435c4bbdfSmrg}
6535c4bbdfSmrg
6635c4bbdfSmrgstatic Bool
6735c4bbdfSmrgvalidate_render_type(uint32_t render_type)
6835c4bbdfSmrg{
6935c4bbdfSmrg    switch (render_type) {
7035c4bbdfSmrg    case GLX_RGBA_TYPE:
7135c4bbdfSmrg    case GLX_COLOR_INDEX_TYPE:
7235c4bbdfSmrg    case GLX_RGBA_FLOAT_TYPE_ARB:
7335c4bbdfSmrg    case GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT:
741b5d61b8Smrg        return TRUE;
7535c4bbdfSmrg    default:
761b5d61b8Smrg        return FALSE;
7735c4bbdfSmrg    }
7835c4bbdfSmrg}
7935c4bbdfSmrg
8035c4bbdfSmrgint
8135c4bbdfSmrg__glXDisp_CreateContextAttribsARB(__GLXclientState * cl, GLbyte * pc)
8235c4bbdfSmrg{
8335c4bbdfSmrg    ClientPtr client = cl->client;
8435c4bbdfSmrg    xGLXCreateContextAttribsARBReq *req = (xGLXCreateContextAttribsARBReq *) pc;
8535c4bbdfSmrg    int32_t *attribs = (req->numAttribs != 0) ? (int32_t *) (req + 1) : NULL;
8635c4bbdfSmrg    unsigned i;
8735c4bbdfSmrg    int major_version = 1;
8835c4bbdfSmrg    int minor_version = 0;
8935c4bbdfSmrg    uint32_t flags = 0;
9035c4bbdfSmrg    uint32_t render_type = GLX_RGBA_TYPE;
9135c4bbdfSmrg    uint32_t flush = GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB;
9235c4bbdfSmrg    __GLXcontext *ctx = NULL;
9335c4bbdfSmrg    __GLXcontext *shareCtx = NULL;
9435c4bbdfSmrg    __GLXscreen *glxScreen;
951b5d61b8Smrg    __GLXconfig *config = NULL;
9635c4bbdfSmrg    int err;
9735c4bbdfSmrg
9835c4bbdfSmrg    /* The GLX_ARB_create_context_robustness spec says:
9935c4bbdfSmrg     *
10035c4bbdfSmrg     *     "The default value for GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
10135c4bbdfSmrg     *     is GLX_NO_RESET_NOTIFICATION_ARB."
10235c4bbdfSmrg     */
10335c4bbdfSmrg    int reset = GLX_NO_RESET_NOTIFICATION_ARB;
10435c4bbdfSmrg
10535c4bbdfSmrg    /* The GLX_ARB_create_context_profile spec says:
10635c4bbdfSmrg     *
10735c4bbdfSmrg     *     "The default value for GLX_CONTEXT_PROFILE_MASK_ARB is
10835c4bbdfSmrg     *     GLX_CONTEXT_CORE_PROFILE_BIT_ARB."
10935c4bbdfSmrg     *
11035c4bbdfSmrg     * The core profile only makes sense for OpenGL versions 3.2 and later.
11135c4bbdfSmrg     * If the version ultimately specified is less than 3.2, the core profile
11235c4bbdfSmrg     * bit is cleared (see below).
11335c4bbdfSmrg     */
11435c4bbdfSmrg    int profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
11535c4bbdfSmrg
11635c4bbdfSmrg    /* Verify that the size of the packet matches the size inferred from the
11735c4bbdfSmrg     * sizes specified for the various fields.
11835c4bbdfSmrg     */
11935c4bbdfSmrg    const unsigned expected_size = (sz_xGLXCreateContextAttribsARBReq
12035c4bbdfSmrg                                    + (req->numAttribs * 8)) / 4;
12135c4bbdfSmrg
12235c4bbdfSmrg    if (req->length != expected_size)
12335c4bbdfSmrg        return BadLength;
12435c4bbdfSmrg
12535c4bbdfSmrg    /* The GLX_ARB_create_context spec says:
12635c4bbdfSmrg     *
12735c4bbdfSmrg     *     "* If <config> is not a valid GLXFBConfig, GLXBadFBConfig is
12835c4bbdfSmrg     *        generated."
12935c4bbdfSmrg     *
13035c4bbdfSmrg     * On the client, the screen comes from the FBConfig, so GLXBadFBConfig
13135c4bbdfSmrg     * should be issued if the screen is nonsense.
13235c4bbdfSmrg     */
133ed6184dfSmrg    if (!validGlxScreen(client, req->screen, &glxScreen, &err)) {
134ed6184dfSmrg        client->errorValue = req->fbconfig;
13535c4bbdfSmrg        return __glXError(GLXBadFBConfig);
136ed6184dfSmrg    }
13735c4bbdfSmrg
1381b5d61b8Smrg    if (req->fbconfig) {
139ed6184dfSmrg        if (!validGlxFBConfig(client, glxScreen, req->fbconfig, &config, &err)) {
140ed6184dfSmrg            client->errorValue = req->fbconfig;
1411b5d61b8Smrg            return __glXError(GLXBadFBConfig);
142ed6184dfSmrg        }
1431b5d61b8Smrg    }
14435c4bbdfSmrg
14535c4bbdfSmrg    /* Validate the context with which the new context should share resources.
14635c4bbdfSmrg     */
14735c4bbdfSmrg    if (req->shareList != None) {
14835c4bbdfSmrg        if (!validGlxContext(client, req->shareList, DixReadAccess,
14935c4bbdfSmrg                             &shareCtx, &err))
15035c4bbdfSmrg            return err;
15135c4bbdfSmrg
15235c4bbdfSmrg        /* The crazy condition is because C doesn't have a logical XOR
15335c4bbdfSmrg         * operator.  Comparing directly for equality may fail if one is 1 and
15435c4bbdfSmrg         * the other is 2 even though both are logically true.
15535c4bbdfSmrg         */
15635c4bbdfSmrg        if (!!req->isDirect != !!shareCtx->isDirect) {
15735c4bbdfSmrg            client->errorValue = req->shareList;
15835c4bbdfSmrg            return BadMatch;
15935c4bbdfSmrg        }
16035c4bbdfSmrg
16135c4bbdfSmrg        /* The GLX_ARB_create_context spec says:
16235c4bbdfSmrg         *
16335c4bbdfSmrg         *     "* If the server context state for <share_context>...was
16435c4bbdfSmrg         *        created on a different screen than the one referenced by
16535c4bbdfSmrg         *        <config>...BadMatch is generated."
16635c4bbdfSmrg         */
16735c4bbdfSmrg        if (glxScreen != shareCtx->pGlxScreen) {
16835c4bbdfSmrg            client->errorValue = shareCtx->pGlxScreen->pScreen->myNum;
16935c4bbdfSmrg            return BadMatch;
17035c4bbdfSmrg        }
17135c4bbdfSmrg    }
17235c4bbdfSmrg
17335c4bbdfSmrg    for (i = 0; i < req->numAttribs; i++) {
17435c4bbdfSmrg        switch (attribs[i * 2]) {
17535c4bbdfSmrg        case GLX_CONTEXT_MAJOR_VERSION_ARB:
17635c4bbdfSmrg            major_version = attribs[2 * i + 1];
17735c4bbdfSmrg            break;
17835c4bbdfSmrg
17935c4bbdfSmrg        case GLX_CONTEXT_MINOR_VERSION_ARB:
18035c4bbdfSmrg            minor_version = attribs[2 * i + 1];
18135c4bbdfSmrg            break;
18235c4bbdfSmrg
18335c4bbdfSmrg        case GLX_CONTEXT_FLAGS_ARB:
18435c4bbdfSmrg            flags = attribs[2 * i + 1];
18535c4bbdfSmrg            break;
18635c4bbdfSmrg
18735c4bbdfSmrg        case GLX_RENDER_TYPE:
1881b5d61b8Smrg            /* Not valid for GLX_EXT_no_config_context */
1891b5d61b8Smrg            if (!req->fbconfig)
1901b5d61b8Smrg                return BadValue;
19135c4bbdfSmrg            render_type = attribs[2 * i + 1];
19235c4bbdfSmrg            break;
19335c4bbdfSmrg
19435c4bbdfSmrg        case GLX_CONTEXT_PROFILE_MASK_ARB:
19535c4bbdfSmrg            profile = attribs[2 * i + 1];
19635c4bbdfSmrg            break;
19735c4bbdfSmrg
19835c4bbdfSmrg        case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
19935c4bbdfSmrg            reset = attribs[2 * i + 1];
20035c4bbdfSmrg            if (reset != GLX_NO_RESET_NOTIFICATION_ARB
20135c4bbdfSmrg                && reset != GLX_LOSE_CONTEXT_ON_RESET_ARB)
20235c4bbdfSmrg                return BadValue;
20335c4bbdfSmrg
20435c4bbdfSmrg            break;
20535c4bbdfSmrg
20635c4bbdfSmrg        case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB:
20735c4bbdfSmrg            flush = attribs[2 * i + 1];
20835c4bbdfSmrg            if (flush != GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB
20935c4bbdfSmrg                && flush != GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB)
21035c4bbdfSmrg                return BadValue;
21135c4bbdfSmrg            break;
21235c4bbdfSmrg
2131b5d61b8Smrg        case GLX_SCREEN:
2141b5d61b8Smrg            /* Only valid for GLX_EXT_no_config_context */
2151b5d61b8Smrg            if (req->fbconfig)
2161b5d61b8Smrg                return BadValue;
2171b5d61b8Smrg            /* Must match the value in the request header */
2181b5d61b8Smrg            if (attribs[2 * i + 1] != req->screen)
2191b5d61b8Smrg                return BadValue;
2201b5d61b8Smrg            break;
2211b5d61b8Smrg
2221b5d61b8Smrg        case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
2231b5d61b8Smrg            /* ignore */
2241b5d61b8Smrg            break;
2251b5d61b8Smrg
22635c4bbdfSmrg        default:
2271b5d61b8Smrg            if (!req->isDirect)
2281b5d61b8Smrg                return BadValue;
2291b5d61b8Smrg            break;
23035c4bbdfSmrg        }
23135c4bbdfSmrg    }
23235c4bbdfSmrg
23335c4bbdfSmrg    /* The GLX_ARB_create_context spec says:
23435c4bbdfSmrg     *
23535c4bbdfSmrg     *     "If attributes GLX_CONTEXT_MAJOR_VERSION_ARB and
23635c4bbdfSmrg     *     GLX_CONTEXT_MINOR_VERSION_ARB, when considered together
23735c4bbdfSmrg     *     with attributes GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB and
23835c4bbdfSmrg     *     GLX_RENDER_TYPE, specify an OpenGL version and feature set
23935c4bbdfSmrg     *     that are not defined, BadMatch is generated.
24035c4bbdfSmrg     *
24135c4bbdfSmrg     *     ...Feature deprecation was introduced with OpenGL 3.0, so
24235c4bbdfSmrg     *     forward-compatible contexts may only be requested for
24335c4bbdfSmrg     *     OpenGL 3.0 and above. Thus, examples of invalid
24435c4bbdfSmrg     *     combinations of attributes include:
24535c4bbdfSmrg     *
24635c4bbdfSmrg     *       - Major version < 1 or > 3
24735c4bbdfSmrg     *       - Major version == 1 and minor version < 0 or > 5
24835c4bbdfSmrg     *       - Major version == 2 and minor version < 0 or > 1
24935c4bbdfSmrg     *       - Major version == 3 and minor version > 2
25035c4bbdfSmrg     *       - Forward-compatible flag set and major version < 3
25135c4bbdfSmrg     *       - Color index rendering and major version >= 3"
25235c4bbdfSmrg     */
25335c4bbdfSmrg    if (!validate_GL_version(major_version, minor_version))
25435c4bbdfSmrg        return BadMatch;
25535c4bbdfSmrg
25635c4bbdfSmrg    if (major_version < 3
25735c4bbdfSmrg        && ((flags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) != 0))
25835c4bbdfSmrg        return BadMatch;
25935c4bbdfSmrg
26035c4bbdfSmrg    if (major_version >= 3 && render_type == GLX_COLOR_INDEX_TYPE)
26135c4bbdfSmrg        return BadMatch;
26235c4bbdfSmrg
26335c4bbdfSmrg    if (!validate_render_type(render_type))
26435c4bbdfSmrg        return BadValue;
26535c4bbdfSmrg
26635c4bbdfSmrg    if ((flags & ~ALL_VALID_FLAGS) != 0)
26735c4bbdfSmrg        return BadValue;
26835c4bbdfSmrg
26935c4bbdfSmrg    /* The GLX_ARB_create_context_profile spec says:
27035c4bbdfSmrg     *
27135c4bbdfSmrg     *     "* If attribute GLX_CONTEXT_PROFILE_MASK_ARB has no bits set; has
27235c4bbdfSmrg     *        any bits set other than GLX_CONTEXT_CORE_PROFILE_BIT_ARB and
27335c4bbdfSmrg     *        GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; has more than one of
27435c4bbdfSmrg     *        these bits set; or if the implementation does not support the
27535c4bbdfSmrg     *        requested profile, then GLXBadProfileARB is generated."
27635c4bbdfSmrg     *
27735c4bbdfSmrg     * The GLX_EXT_create_context_es2_profile spec doesn't exactly say what
27835c4bbdfSmrg     * is supposed to happen if an invalid version is set, but it doesn't
27935c4bbdfSmrg     * much matter as support for GLES contexts is only defined for direct
28035c4bbdfSmrg     * contexts (at the moment anyway) so we can leave it up to the driver
28135c4bbdfSmrg     * to validate.
28235c4bbdfSmrg     */
28335c4bbdfSmrg    switch (profile) {
28435c4bbdfSmrg    case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
28535c4bbdfSmrg    case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
28635c4bbdfSmrg    case GLX_CONTEXT_ES2_PROFILE_BIT_EXT:
28735c4bbdfSmrg        break;
28835c4bbdfSmrg    default:
28935c4bbdfSmrg        return __glXError(GLXBadProfileARB);
29035c4bbdfSmrg    }
29135c4bbdfSmrg
29235c4bbdfSmrg    /* The GLX_ARB_create_context_robustness spec says:
29335c4bbdfSmrg     *
29435c4bbdfSmrg     *     "* If the reset notification behavior of <share_context> and the
29535c4bbdfSmrg     *        newly created context are different, BadMatch is generated."
29635c4bbdfSmrg     */
29735c4bbdfSmrg    if (shareCtx != NULL && shareCtx->resetNotificationStrategy != reset)
29835c4bbdfSmrg        return BadMatch;
29935c4bbdfSmrg
30035c4bbdfSmrg    /* There is no GLX protocol for desktop OpenGL versions after 1.4.  There
30135c4bbdfSmrg     * is no GLX protocol for any version of OpenGL ES.  If the application is
30235c4bbdfSmrg     * requested an indirect rendering context for a version that cannot be
30335c4bbdfSmrg     * satisfied, reject it.
30435c4bbdfSmrg     *
30535c4bbdfSmrg     * The GLX_ARB_create_context spec says:
30635c4bbdfSmrg     *
30735c4bbdfSmrg     *     "* If <config> does not support compatible OpenGL contexts
30835c4bbdfSmrg     *        providing the requested API major and minor version,
30935c4bbdfSmrg     *        forward-compatible flag, and debug context flag, GLXBadFBConfig
31035c4bbdfSmrg     *        is generated."
31135c4bbdfSmrg     */
31235c4bbdfSmrg    if (!req->isDirect && (major_version > 1 || minor_version > 4
31335c4bbdfSmrg                           || profile == GLX_CONTEXT_ES2_PROFILE_BIT_EXT)) {
314ed6184dfSmrg        client->errorValue = req->fbconfig;
31535c4bbdfSmrg        return __glXError(GLXBadFBConfig);
31635c4bbdfSmrg    }
31735c4bbdfSmrg
31835c4bbdfSmrg    /* Allocate memory for the new context
31935c4bbdfSmrg     */
32035c4bbdfSmrg    if (req->isDirect) {
32135c4bbdfSmrg        ctx = __glXdirectContextCreate(glxScreen, config, shareCtx);
32235c4bbdfSmrg        err = BadAlloc;
32335c4bbdfSmrg    }
32435c4bbdfSmrg    else {
3251b5d61b8Smrg        /* Only allow creating indirect GLX contexts if allowed by
3261b5d61b8Smrg         * server command line.  Indirect GLX is of limited use (since
3271b5d61b8Smrg         * it's only GL 1.4), it's slower than direct contexts, and
3281b5d61b8Smrg         * it's a massive attack surface for buffer overflow type
3291b5d61b8Smrg         * errors.
3301b5d61b8Smrg         */
3311b5d61b8Smrg        if (!enableIndirectGLX) {
3321b5d61b8Smrg            client->errorValue = req->isDirect;
3331b5d61b8Smrg            return BadValue;
3341b5d61b8Smrg        }
3351b5d61b8Smrg
33635c4bbdfSmrg        ctx = glxScreen->createContext(glxScreen, config, shareCtx,
33735c4bbdfSmrg                                       req->numAttribs, (uint32_t *) attribs,
33835c4bbdfSmrg                                       &err);
33935c4bbdfSmrg    }
34035c4bbdfSmrg
34135c4bbdfSmrg    if (ctx == NULL)
34235c4bbdfSmrg        return err;
34335c4bbdfSmrg
34435c4bbdfSmrg    ctx->pGlxScreen = glxScreen;
34535c4bbdfSmrg    ctx->config = config;
34635c4bbdfSmrg    ctx->id = req->context;
34735c4bbdfSmrg    ctx->share_id = req->shareList;
3481b5d61b8Smrg    ctx->idExists = TRUE;
34935c4bbdfSmrg    ctx->isDirect = req->isDirect;
35035c4bbdfSmrg    ctx->renderMode = GL_RENDER;
35135c4bbdfSmrg    ctx->resetNotificationStrategy = reset;
35235c4bbdfSmrg    ctx->releaseBehavior = flush;
353ed6184dfSmrg    ctx->renderType = render_type;
35435c4bbdfSmrg
35535c4bbdfSmrg    /* Add the new context to the various global tables of GLX contexts.
35635c4bbdfSmrg     */
35735c4bbdfSmrg    if (!__glXAddContext(ctx)) {
35835c4bbdfSmrg        (*ctx->destroy) (ctx);
35935c4bbdfSmrg        client->errorValue = req->context;
36035c4bbdfSmrg        return BadAlloc;
36135c4bbdfSmrg    }
36235c4bbdfSmrg
36335c4bbdfSmrg    return Success;
36435c4bbdfSmrg}
36535c4bbdfSmrg
36635c4bbdfSmrgint
36735c4bbdfSmrg__glXDispSwap_CreateContextAttribsARB(__GLXclientState * cl, GLbyte * pc)
36835c4bbdfSmrg{
36935c4bbdfSmrg    return BadRequest;
37035c4bbdfSmrg}
371