glxcmds.c 75 KB
Newer Older
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
1
/*
Adam Jackson's avatar
Adam Jackson committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice including the dates of first publication and
 * either this permission notice or a reference to
 * http://oss.sgi.com/projects/FreeB/
 * shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Except as contained in this notice, the name of Silicon Graphics, Inc.
 * shall not be used in advertising or otherwise to promote the sale, use or
 * other dealings in this Software without prior written authorization from
 * Silicon Graphics, Inc.
 */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
30

31 32 33 34
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

35
#include <string.h>
36
#include <assert.h>
37

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
38 39
#include "glxserver.h"
#include <GL/glxtokens.h>
Adam Jackson's avatar
Adam Jackson committed
40
#include <X11/extensions/presenttokens.h>
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
41 42 43 44 45
#include <unpack.h>
#include <pixmapstr.h>
#include <windowstr.h>
#include "glxutil.h"
#include "glxext.h"
46
#include "indirect_dispatch.h"
47 48
#include "indirect_table.h"
#include "indirect_util.h"
49
#include "protocol-versions.h"
50
#include "glxvndabi.h"
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
51

52 53
static char GLXServerVendorName[] = "SGI";

54
_X_HIDDEN int
55 56
validGlxScreen(ClientPtr client, int screen, __GLXscreen ** pGlxScreen,
               int *err)
57 58
{
    /*
59 60
     ** Check if screen exists.
     */
61
    if (screen < 0 || screen >= screenInfo.numScreens) {
62 63 64
        client->errorValue = screen;
        *err = BadValue;
        return FALSE;
65 66
    }
    *pGlxScreen = glxGetScreen(screenInfo.screens[screen]);
67

68 69 70
    return TRUE;
}

71
_X_HIDDEN int
72 73
validGlxFBConfig(ClientPtr client, __GLXscreen * pGlxScreen, XID id,
                 __GLXconfig ** config, int *err)
74
{
75
    __GLXconfig *m;
76 77

    for (m = pGlxScreen->fbconfigs; m != NULL; m = m->next)
78 79 80 81
        if (m->fbconfigID == id) {
            *config = m;
            return TRUE;
        }
82 83 84 85 86 87 88 89

    client->errorValue = id;
    *err = __glXError(GLXBadFBConfig);

    return FALSE;
}

static int
90 91
validGlxVisual(ClientPtr client, __GLXscreen * pGlxScreen, XID id,
               __GLXconfig ** config, int *err)
92 93 94 95
{
    int i;

    for (i = 0; i < pGlxScreen->numVisuals; i++)
96 97 98 99
        if (pGlxScreen->visuals[i]->visualID == id) {
            *config = pGlxScreen->visuals[i];
            return TRUE;
        }
100 101 102 103 104 105 106 107

    client->errorValue = id;
    *err = BadValue;

    return FALSE;
}

static int
108 109
validGlxFBConfigForWindow(ClientPtr client, __GLXconfig * config,
                          DrawablePtr pDraw, int *err)
110 111 112 113 114 115
{
    ScreenPtr pScreen = pDraw->pScreen;
    VisualPtr pVisual = NULL;
    XID vid;
    int i;

116
    vid = wVisual((WindowPtr) pDraw);
117
    for (i = 0; i < pScreen->numVisuals; i++) {
118 119 120 121
        if (pScreen->visuals[i].vid == vid) {
            pVisual = &pScreen->visuals[i];
            break;
        }
122 123 124
    }

    /* FIXME: What exactly should we check here... */
125
    if (pVisual->class != glxConvertToXVisualType(config->visualType) ||
126 127 128 129
        !(config->drawableType & GLX_WINDOW_BIT)) {
        client->errorValue = pDraw->id;
        *err = BadMatch;
        return FALSE;
130 131 132 133
    }

    return TRUE;
}
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
134

135
_X_HIDDEN int
136
validGlxContext(ClientPtr client, XID id, int access_mode,
137
                __GLXcontext ** context, int *err)
138
{
139
    /* no ghost contexts */
140 141
    if (id & SERVER_BIT) {
        *err = __glXError(GLXBadContext);
142
        return FALSE;
143
    }
144

145
    *err = dixLookupResourceByType((void **) context, id,
146
                                   __glXContextRes, client, access_mode);
Adam Jackson's avatar
Adam Jackson committed
147
    if (*err != Success || (*context)->idExists == GL_FALSE) {
148 149 150 151
        client->errorValue = id;
        if (*err == BadValue || *err == Success)
            *err = __glXError(GLXBadContext);
        return FALSE;
152 153 154 155 156
    }

    return TRUE;
}

Jon Turney's avatar
Jon Turney committed
157
int
158
validGlxDrawable(ClientPtr client, XID id, int type, int access_mode,
159
                 __GLXdrawable ** drawable, int *err)
160 161 162
{
    int rc;

163
    rc = dixLookupResourceByType((void **) drawable, id,
164
                                 __glXDrawableRes, client, access_mode);
165
    if (rc != Success && rc != BadValue) {
166 167 168
        *err = rc;
        client->errorValue = id;
        return FALSE;
169 170
    }

171 172 173
    /* If the ID of the glx drawable we looked up doesn't match the id
     * we looked for, it's because we looked it up under the X
     * drawable ID (see DoCreateGLXDrawable). */
174
    if (rc == BadValue ||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        (*drawable)->drawId != id ||
        (type != GLX_DRAWABLE_ANY && type != (*drawable)->type)) {
        client->errorValue = id;
        switch (type) {
        case GLX_DRAWABLE_WINDOW:
            *err = __glXError(GLXBadWindow);
            return FALSE;
        case GLX_DRAWABLE_PIXMAP:
            *err = __glXError(GLXBadPixmap);
            return FALSE;
        case GLX_DRAWABLE_PBUFFER:
            *err = __glXError(GLXBadPbuffer);
            return FALSE;
        case GLX_DRAWABLE_ANY:
            *err = __glXError(GLXBadDrawable);
            return FALSE;
        }
192 193 194 195 196
    }

    return TRUE;
}

197
void
198
__glXContextDestroy(__GLXcontext * context)
199
{
200
    lastGLContext = NULL;
201 202
}

203 204
static void
__glXdirectContextDestroy(__GLXcontext * context)
205
{
206
    __glXContextDestroy(context);
207
    free(context);
208 209
}

210 211 212 213 214 215
static int
__glXdirectContextLoseCurrent(__GLXcontext * context)
{
    return GL_TRUE;
}

216
_X_HIDDEN __GLXcontext *
217 218
__glXdirectContextCreate(__GLXscreen * screen,
                         __GLXconfig * modes, __GLXcontext * shareContext)
219 220 221
{
    __GLXcontext *context;

222
    context = calloc(1, sizeof(__GLXcontext));
223
    if (context == NULL)
224
        return NULL;
225

226
    context->config = modes;
227
    context->destroy = __glXdirectContextDestroy;
228
    context->loseCurrent = __glXdirectContextLoseCurrent;
229 230 231 232

    return context;
}

Eric Anholt's avatar
Eric Anholt committed
233 234 235
/**
 * Create a GL context with the given properties.  This routine is used
 * to implement \c glXCreateContext, \c glXCreateNewContext, and
236
 * \c glXCreateContextWithConfigSGIX.  This works because of the hack way
Eric Anholt's avatar
Eric Anholt committed
237 238 239 240
 * that GLXFBConfigs are implemented.  Basically, the FBConfigID is the
 * same as the VisualID.
 */

Kristian Høgsberg's avatar
Kristian Høgsberg committed
241
static int
242 243 244
DoCreateContext(__GLXclientState * cl, GLXContextID gcId,
                GLXContextID shareList, __GLXconfig * config,
                __GLXscreen * pGlxScreen, GLboolean isDirect)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
245 246 247
{
    ClientPtr client = cl->client;
    __GLXcontext *glxc, *shareglxc;
248
    int err;
249

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
250
    /*
Peter Hutterer's avatar
Peter Hutterer committed
251
     ** Find the display list space that we want to share.
252 253
     **
     ** NOTE: In a multithreaded X server, we would need to keep a reference
Peter Hutterer's avatar
Peter Hutterer committed
254 255 256 257
     ** count for each display list so that if one client detroyed a list that
     ** another client was using, the list would not really be freed until it
     ** was no longer in use.  Since this sample implementation has no support
     ** for multithreaded servers, we don't do this.
258
     */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
259
    if (shareList == None) {
260 261 262 263 264 265 266
        shareglxc = 0;
    }
    else {
        if (!validGlxContext(client, shareList, DixReadAccess,
                             &shareglxc, &err))
            return err;

267 268 269 270 271 272 273 274 275 276
        /* Page 26 (page 32 of the PDF) of the GLX 1.4 spec says:
         *
         *     "The server context state for all sharing contexts must exist
         *     in a single address space or a BadMatch error is generated."
         *
         * If the share context is indirect, force the new context to also be
         * indirect.  If the shard context is direct but the new context
         * cannot be direct, generate BadMatch.
         */
        if (shareglxc->isDirect && !isDirect) {
277 278 279
            client->errorValue = shareList;
            return BadMatch;
        }
280
        else if (!shareglxc->isDirect) {
281 282 283 284 285 286
            /*
             ** Create an indirect context regardless of what the client asked
             ** for; this way we can share display list space with shareList.
             */
            isDirect = GL_FALSE;
        }
287 288 289 290 291 292 293 294 295

        /* Core GLX doesn't explicitly require this, but GLX_ARB_create_context
         * does (see glx/createcontext.c), and it's assumed by our
         * implementation anyway, so let's be consistent about it.
         */
        if (shareglxc->pGlxScreen != pGlxScreen) {
            client->errorValue = shareglxc->pGlxScreen->pScreen->myNum;
            return BadMatch;
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
296 297 298
    }

    /*
299 300
     ** Allocate memory for the new context
     */
301
    if (!isDirect) {
302 303 304 305 306 307 308 309 310 311 312
        /* Only allow creating indirect GLX contexts if allowed by
         * server command line.  Indirect GLX is of limited use (since
         * it's only GL 1.4), it's slower than direct contexts, and
         * it's a massive attack surface for buffer overflow type
         * errors.
         */
        if (!enableIndirectGLX) {
            client->errorValue = isDirect;
            return BadValue;
        }

313 314 315 316 317 318 319
        /* Without any attributes, the only error that the driver should be
         * able to generate is BadAlloc.  As result, just drop the error
         * returned from the driver on the floor.
         */
        glxc = pGlxScreen->createContext(pGlxScreen, config, shareglxc,
                                         0, NULL, &err);
    }
320
    else
321
        glxc = __glXdirectContextCreate(pGlxScreen, config, shareglxc);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
322
    if (!glxc) {
323
        return BadAlloc;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
324 325
    }

326
    /* Initialize the GLXcontext structure.
327
     */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
328
    glxc->pGlxScreen = pGlxScreen;
329
    glxc->config = config;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
330 331 332 333 334 335
    glxc->id = gcId;
    glxc->share_id = shareList;
    glxc->idExists = GL_TRUE;
    glxc->isDirect = isDirect;
    glxc->renderMode = GL_RENDER;

336 337 338 339 340 341 342 343 344 345
    /* The GLX_ARB_create_context_robustness spec says:
     *
     *     "The default value for GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
     *     is GLX_NO_RESET_NOTIFICATION_ARB."
     *
     * Without using glXCreateContextAttribsARB, there is no way to specify a
     * non-default reset notification strategy.
     */
    glxc->resetNotificationStrategy = GLX_NO_RESET_NOTIFICATION_ARB;

346 347 348 349 350 351 352 353 354 355 356 357 358
#ifdef GLX_CONTEXT_RELEASE_BEHAVIOR_ARB
    /* The GLX_ARB_context_flush_control spec says:
     *
     *     "The default value [for GLX_CONTEXT_RELEASE_BEHAVIOR] is
     *     CONTEXT_RELEASE_BEHAVIOR_FLUSH, and may in some cases be changed
     *     using platform-specific context creation extensions."
     *
     * Without using glXCreateContextAttribsARB, there is no way to specify a
     * non-default release behavior.
     */
    glxc->releaseBehavior = GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB;
#endif

359
    /* Add the new context to the various global tables of GLX contexts.
360
     */
361
    if (!__glXAddContext(glxc)) {
362 363 364 365 366
        (*glxc->destroy) (glxc);
        client->errorValue = gcId;
        return BadAlloc;
    }

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
367 368 369
    return Success;
}

370 371
int
__glXDisp_CreateContext(__GLXclientState * cl, GLbyte * pc)
Eric Anholt's avatar
Eric Anholt committed
372 373
{
    xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;
374
    __GLXconfig *config;
375 376
    __GLXscreen *pGlxScreen;
    int err;
Eric Anholt's avatar
Eric Anholt committed
377

378
    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
379
        return err;
380
    if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err))
381
        return err;
382 383

    return DoCreateContext(cl, req->context, req->shareList,
384
                           config, pGlxScreen, req->isDirect);
385
}
Eric Anholt's avatar
Eric Anholt committed
386

387 388
int
__glXDisp_CreateNewContext(__GLXclientState * cl, GLbyte * pc)
Eric Anholt's avatar
Eric Anholt committed
389 390
{
    xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
391
    __GLXconfig *config;
392 393 394 395
    __GLXscreen *pGlxScreen;
    int err;

    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
396
        return err;
397
    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
398
        return err;
Eric Anholt's avatar
Eric Anholt committed
399

400
    return DoCreateContext(cl, req->context, req->shareList,
401
                           config, pGlxScreen, req->isDirect);
402
}
Eric Anholt's avatar
Eric Anholt committed
403

404 405
int
__glXDisp_CreateContextWithConfigSGIX(__GLXclientState * cl, GLbyte * pc)
Eric Anholt's avatar
Eric Anholt committed
406
{
Julien Cristau's avatar
Julien Cristau committed
407
    ClientPtr client = cl->client;
408 409
    xGLXCreateContextWithConfigSGIXReq *req =
        (xGLXCreateContextWithConfigSGIXReq *) pc;
410
    __GLXconfig *config;
411 412
    __GLXscreen *pGlxScreen;
    int err;
Eric Anholt's avatar
Eric Anholt committed
413

Julien Cristau's avatar
Julien Cristau committed
414 415
    REQUEST_SIZE_MATCH(xGLXCreateContextWithConfigSGIXReq);

416
    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
417
        return err;
418
    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
419
        return err;
420 421

    return DoCreateContext(cl, req->context, req->shareList,
422
                           config, pGlxScreen, req->isDirect);
423
}
Adam Jackson's avatar
Adam Jackson committed
424

425 426
int
__glXDisp_DestroyContext(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
427 428 429
{
    xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc;
    __GLXcontext *glxc;
430 431 432
    int err;

    if (!validGlxContext(cl->client, req->context, DixDestroyAccess,
433 434
                         &glxc, &err))
        return err;
435

436
    glxc->idExists = GL_FALSE;
437 438 439 440 441 442 443 444 445 446
    if (glxc->currentClient) {
        XID ghost = FakeClientID(glxc->currentClient->index);

        if (!AddResource(ghost, __glXContextRes, glxc))
            return BadAlloc;
        ChangeResourceValue(glxc->id, __glXContextRes, NULL);
        glxc->id = ghost;
    }

    FreeResourceByType(req->context, __glXContextRes, FALSE);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
447

Adam Jackson's avatar
Adam Jackson committed
448
    return Success;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
449 450
}

451 452
__GLXcontext *
__glXLookupContextByTag(__GLXclientState * cl, GLXContextTag tag)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
453
{
454
    return glxServer.getContextTagPrivate(cl->client, tag);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
455 456
}

457 458 459 460 461 462 463 464 465 466 467 468
static __GLXconfig *
inferConfigForWindow(__GLXscreen *pGlxScreen, WindowPtr pWin)
{
    int i, vid = wVisual(pWin);

    for (i = 0; i < pGlxScreen->numVisuals; i++)
        if (pGlxScreen->visuals[i]->visualID == vid)
            return pGlxScreen->visuals[i];

    return NULL;
}

469
/**
470 471 472 473
 * This is a helper function to handle the legacy (pre GLX 1.3) cases
 * where passing an X window to glXMakeCurrent is valid.  Given a
 * resource ID, look up the GLX drawable if available, otherwise, make
 * sure it's an X window and create a GLX drawable one the fly.
474
 */
Kristian Høgsberg's avatar
Kristian Høgsberg committed
475
static __GLXdrawable *
476 477
__glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client,
                 int *error)
478 479
{
    DrawablePtr pDraw;
480
    __GLXdrawable *pGlxDraw;
481 482
    __GLXconfig *config;
    __GLXscreen *pGlxScreen;
483
    int rc;
484

485
    if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY,
486
                         DixWriteAccess, &pGlxDraw, &rc)) {
487 488 489
        if (glxc != NULL &&
            glxc->config != NULL &&
            glxc->config != pGlxDraw->config) {
490 491 492 493
            client->errorValue = drawId;
            *error = BadMatch;
            return NULL;
        }
494

495
        return pGlxDraw;
496 497
    }

498 499
    /* No active context and an unknown drawable, bail. */
    if (glxc == NULL) {
500 501 502
        client->errorValue = drawId;
        *error = BadMatch;
        return NULL;
503 504
    }

505 506 507 508
    /* The drawId wasn't a GLX drawable.  Make sure it's a window and
     * create a GLXWindow for it.  Check that the drawable screen
     * matches the context screen and that the context fbconfig is
     * compatible with the window visual. */
509

510
    rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
511
    if (rc != Success || pDraw->type != DRAWABLE_WINDOW) {
512 513 514
        client->errorValue = drawId;
        *error = __glXError(GLXBadDrawable);
        return NULL;
515 516
    }

517 518
    pGlxScreen = glxc->pGlxScreen;
    if (pDraw->pScreen != pGlxScreen->pScreen) {
519 520 521
        client->errorValue = pDraw->pScreen->myNum;
        *error = BadMatch;
        return NULL;
522 523
    }

524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
    config = glxc->config;
    if (!config)
        config = inferConfigForWindow(pGlxScreen, (WindowPtr)pDraw);
    if (!config) {
        /*
         * If we get here, we've tried to bind a no-config context to a
         * window without a corresponding fbconfig, presumably because
         * we don't support GL on it (PseudoColor perhaps). From GLX Section
         * 3.3.7 "Rendering Contexts":
         *
         * "If draw or read are not compatible with ctx a BadMatch error
         * is generated."
         */
        *error = BadMatch;
        return NULL;
    }

    if (!validGlxFBConfigForWindow(client, config, pDraw, error))
542
        return NULL;
543

544 545
    pGlxDraw = pGlxScreen->createDrawable(client, pGlxScreen, pDraw, drawId,
                                          GLX_DRAWABLE_WINDOW, drawId, config);
546 547 548 549
    if (!pGlxDraw) {
	*error = BadAlloc;
	return NULL;
    }
550 551 552

    /* since we are creating the drawablePrivate, drawId should be new */
    if (!AddResource(drawId, __glXDrawableRes, pGlxDraw)) {
553 554
        *error = BadAlloc;
        return NULL;
555 556
    }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
557
    return pGlxDraw;
558 559
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
560 561 562 563
/*****************************************************************************/
/*
** Make an OpenGL context and drawable current.
*/
564

565 566 567
int
xorgGlxMakeCurrent(ClientPtr client, GLXContextTag tag, XID drawId, XID readId,
                   XID contextId, GLXContextTag newContextTag)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
568
{
569 570
    __GLXclientState *cl = glxGetClient(client);
    __GLXcontext *glxc = NULL, *prevglxc = NULL;
571 572
    __GLXdrawable *drawPriv = NULL;
    __GLXdrawable *readPriv = NULL;
573
    int error;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
574

575 576 577
    /* Drawables but no context makes no sense */
    if (!contextId && (drawId || readId))
        return BadMatch;
578

579 580
    /* If either drawable is null, the other must be too */
    if ((drawId == None) != (readId == None))
581 582
        return BadMatch;

583
    /* Look up old context. If we have one, it must be in a usable state. */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
584
    if (tag != 0) {
585 586
        prevglxc = glxServer.getContextTagPrivate(client, tag);

587
        if (prevglxc && prevglxc->renderMode != GL_RENDER) {
588 589 590 591 592
            /* Oops.  Not in render mode render. */
            client->errorValue = prevglxc->id;
            return __glXError(GLXBadContextState);
        }
    }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
593

594
    /* Look up new context. It must not be current for someone else. */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
595
    if (contextId != None) {
596
        int status;
597

598 599
        if (!validGlxContext(client, contextId, DixUseAccess, &glxc, &error))
            return error;
600 601

        if ((glxc != prevglxc) && glxc->currentClient)
602
            return BadAccess;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
603

604 605 606 607 608
        if (drawId) {
            drawPriv = __glXGetDrawable(glxc, drawId, client, &status);
            if (drawPriv == NULL)
                return status;
        }
609

610 611 612 613 614
        if (readId) {
            readPriv = __glXGetDrawable(glxc, readId, client, &status);
            if (readPriv == NULL)
                return status;
        }
615
    }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
616 617

    if (prevglxc) {
618
        /* Flush the previous context if needed. */
619
        Bool need_flush = !prevglxc->isDirect;
620 621 622 623
#ifdef GLX_CONTEXT_RELEASE_BEHAVIOR_ARB
        if (prevglxc->releaseBehavior == GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB)
            need_flush = GL_FALSE;
#endif
624
        if (need_flush) {
625
            if (!__glXForceCurrent(cl, tag, (int *) &error))
626
                return error;
627
            glFlush();
628 629
        }

630 631
        /* Make the previous context not current. */
        if (!(*prevglxc->loseCurrent) (prevglxc))
632
            return __glXError(GLXBadContext);
633

634
        lastGLContext = NULL;
635 636 637 638 639
        if (!prevglxc->isDirect) {
            prevglxc->drawPriv = NULL;
            prevglxc->readPriv = NULL;
        }
    }
640

641
    if (glxc && !glxc->isDirect) {
642 643
        glxc->drawPriv = drawPriv;
        glxc->readPriv = readPriv;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
644

645
        /* make the context current */
646
        lastGLContext = glxc;
647
        if (!(*glxc->makeCurrent) (glxc)) {
648
            lastGLContext = NULL;
649 650 651 652
            glxc->drawPriv = NULL;
            glxc->readPriv = NULL;
            return __glXError(GLXBadContext);
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
653

654
        glxc->currentClient = client;
655
        glxServer.setContextTagPrivate(client, newContextTag, glxc);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
656 657
    }

658 659 660 661 662
    if (prevglxc) {
        prevglxc->currentClient = NULL;
        if (!prevglxc->idExists) {
            FreeResourceByType(prevglxc->id, __glXContextRes, FALSE);
        }
663
    }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
664 665 666 667

    return Success;
}

668 669
int
__glXDisp_MakeCurrent(__GLXclientState * cl, GLbyte * pc)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
670
{
671
    return BadImplementation;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
672 673
}

674 675
int
__glXDisp_MakeContextCurrent(__GLXclientState * cl, GLbyte * pc)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
676
{
677
    return BadImplementation;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
678 679
}

680 681
int
__glXDisp_MakeCurrentReadSGI(__GLXclientState * cl, GLbyte * pc)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
682
{
683
    return BadImplementation;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
684 685
}

686 687
int
__glXDisp_IsDirect(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
688 689 690 691 692
{
    ClientPtr client = cl->client;
    xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc;
    xGLXIsDirectReply reply;
    __GLXcontext *glxc;
693
    int err;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
694

695
    if (!validGlxContext(cl->client, req->context, DixReadAccess, &glxc, &err))
696
        return err;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
697

698 699 700 701 702 703
    reply = (xGLXIsDirectReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = 0,
        .isDirect = glxc->isDirect
    };
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
704 705

    if (client->swapped) {
706 707 708
        __GLX_DECLARE_SWAP_VARIABLES;
        __GLX_SWAP_SHORT(&reply.sequenceNumber);
        __GLX_SWAP_INT(&reply.length);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
709
    }
710
    WriteToClient(client, sz_xGLXIsDirectReply, &reply);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
711 712 713 714

    return Success;
}

715 716
int
__glXDisp_QueryVersion(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
717 718 719 720 721 722
{
    ClientPtr client = cl->client;
    xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc;
    xGLXQueryVersionReply reply;
    GLuint major, minor;

Julien Cristau's avatar
Julien Cristau committed
723 724
    REQUEST_SIZE_MATCH(xGLXQueryVersionReq);

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
725 726
    major = req->majorVersion;
    minor = req->minorVersion;
727 728
    (void) major;
    (void) minor;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
729 730

    /*
731 732 733 734
     ** Server should take into consideration the version numbers sent by the
     ** client if it wants to work with older clients; however, in this
     ** implementation the server just returns its version number.
     */
735 736 737 738
    reply = (xGLXQueryVersionReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = 0,
739 740
        .majorVersion = SERVER_GLX_MAJOR_VERSION,
        .minorVersion = SERVER_GLX_MINOR_VERSION
741
    };
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
742 743

    if (client->swapped) {
744 745 746 747 748
        __GLX_DECLARE_SWAP_VARIABLES;
        __GLX_SWAP_SHORT(&reply.sequenceNumber);
        __GLX_SWAP_INT(&reply.length);
        __GLX_SWAP_INT(&reply.majorVersion);
        __GLX_SWAP_INT(&reply.minorVersion);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
749
    }
750 751

    WriteToClient(client, sz_xGLXQueryVersionReply, &reply);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
752 753 754
    return Success;
}

755 756
int
__glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
757
{
758
    xGLXWaitGLReq *req = (xGLXWaitGLReq *) pc;
Julien Cristau's avatar
Julien Cristau committed
759
    GLXContextTag tag;
760
    __GLXcontext *glxc = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
761
    int error;
762

Julien Cristau's avatar
Julien Cristau committed
763
    tag = req->contextTag;
764
    if (tag) {
765 766 767 768 769 770
        glxc = __glXLookupContextByTag(cl, tag);
        if (!glxc)
            return __glXError(GLXBadContextTag);

        if (!__glXForceCurrent(cl, req->contextTag, &error))
            return error;
771

772
        glFinish();
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
773
    }
774

775
    if (glxc && glxc->drawPriv && glxc->drawPriv->waitGL)
776
        (*glxc->drawPriv->waitGL) (glxc->drawPriv);
777

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
778 779 780
    return Success;
}

781 782
int
__glXDisp_WaitX(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
783
{
784
    xGLXWaitXReq *req = (xGLXWaitXReq *) pc;
Julien Cristau's avatar
Julien Cristau committed
785
    GLXContextTag tag;
786
    __GLXcontext *glxc = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
787
    int error;
788

Julien Cristau's avatar
Julien Cristau committed
789
    tag = req->contextTag;
790
    if (tag) {
791 792 793 794 795 796
        glxc = __glXLookupContextByTag(cl, tag);
        if (!glxc)
            return __glXError(GLXBadContextTag);

        if (!__glXForceCurrent(cl, req->contextTag, &error))
            return error;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
797
    }
798

799
    if (glxc && glxc->drawPriv && glxc->drawPriv->waitX)
800
        (*glxc->drawPriv->waitX) (glxc->drawPriv);
801

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
802 803 804
    return Success;
}

805 806
int
__glXDisp_CopyContext(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
807 808 809
{
    ClientPtr client = cl->client;
    xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc;
Julien Cristau's avatar
Julien Cristau committed
810 811 812 813
    GLXContextID source;
    GLXContextID dest;
    GLXContextTag tag;
    unsigned long mask;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
814 815 816
    __GLXcontext *src, *dst;
    int error;

Julien Cristau's avatar
Julien Cristau committed
817 818 819 820
    source = req->source;
    dest = req->dest;
    tag = req->contextTag;
    mask = req->mask;
821
    if (!validGlxContext(cl->client, source, DixReadAccess, &src, &error))
822
        return error;
823
    if (!validGlxContext(cl->client, dest, DixWriteAccess, &dst, &error))
824
        return error;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
825 826

    /*
827 828 829 830 831 832
     ** They must be in the same address space, and same screen.
     ** NOTE: no support for direct rendering contexts here.
     */
    if (src->isDirect || dst->isDirect || (src->pGlxScreen != dst->pGlxScreen)) {
        client->errorValue = source;
        return BadMatch;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
833 834 835
    }

    /*
836 837
     ** The destination context must not be current for any client.
     */
838
    if (dst->currentClient) {
839 840
        client->errorValue = dest;
        return BadAccess;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
841 842 843
    }

    if (tag) {
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
        __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag);

        if (!tagcx) {
            return __glXError(GLXBadContextTag);
        }
        if (tagcx != src) {
            /*
             ** This would be caused by a faulty implementation of the client
             ** library.
             */
            return BadMatch;
        }
        /*
         ** In this case, glXCopyContext is in both GL and X streams, in terms
         ** of sequentiality.
         */
        if (__glXForceCurrent(cl, tag, &error)) {
            /*
             ** Do whatever is needed to make sure that all preceding requests
             ** in both streams are completed before the copy is executed.
             */
865
            glFinish();
866 867 868 869
        }
        else {
            return error;
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
870 871
    }
    /*
872 873 874 875 876
     ** Issue copy.  The only reason for failure is a bad mask.
     */
    if (!(*dst->copy) (dst, src, mask)) {
        client->errorValue = mask;
        return BadValue;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
877 878 879 880
    }
    return Success;
}

881 882
enum {
    GLX_VIS_CONFIG_UNPAIRED = 18,
883
    GLX_VIS_CONFIG_PAIRED = 22
884 885 886 887 888
};

enum {
    GLX_VIS_CONFIG_TOTAL = GLX_VIS_CONFIG_UNPAIRED + GLX_VIS_CONFIG_PAIRED
};
Eric Anholt's avatar
Eric Anholt committed
889

890 891
int
__glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
892
{
893
    xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
894 895
    ClientPtr client = cl->client;
    xGLXGetVisualConfigsReply reply;
896
    __GLXscreen *pGlxScreen;
897
    __GLXconfig *modes;
898
    CARD32 buf[GLX_VIS_CONFIG_TOTAL];
899
    int p, i, err;
900

Eric Anholt's avatar
Eric Anholt committed
901 902
    __GLX_DECLARE_SWAP_VARIABLES;
    __GLX_DECLARE_SWAP_ARRAY_VARIABLES;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
903

904
    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
905
        return err;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
906

907 908 909 910 911 912 913 914
    reply = (xGLXGetVisualConfigsReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = (pGlxScreen->numVisuals *
                   __GLX_SIZE_CARD32 * GLX_VIS_CONFIG_TOTAL) >> 2,
        .numVisuals = pGlxScreen->numVisuals,
        .numProps = GLX_VIS_CONFIG_TOTAL
    };
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
915

Kristian Høgsberg's avatar
Kristian Høgsberg committed
916
    if (client->swapped) {
917 918 919 920
        __GLX_SWAP_SHORT(&reply.sequenceNumber);
        __GLX_SWAP_INT(&reply.length);