glxcmds.c 75.7 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 40 41 42 43 44
#include "glxserver.h"
#include <GL/glxtokens.h>
#include <unpack.h>
#include <pixmapstr.h>
#include <windowstr.h>
#include "glxutil.h"
#include "glxext.h"
45
#include "indirect_dispatch.h"
46 47
#include "indirect_table.h"
#include "indirect_util.h"
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
48

49 50
static char GLXServerVendorName[] = "SGI";

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

65 66 67
    return TRUE;
}

68
_X_HIDDEN int
69 70
validGlxFBConfig(ClientPtr client, __GLXscreen * pGlxScreen, XID id,
                 __GLXconfig ** config, int *err)
71
{
72
    __GLXconfig *m;
73 74

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

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

    return FALSE;
}

static int
87 88
validGlxVisual(ClientPtr client, __GLXscreen * pGlxScreen, XID id,
               __GLXconfig ** config, int *err)
89 90 91 92
{
    int i;

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

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

    return FALSE;
}

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

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

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

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

132
_X_HIDDEN int
133
validGlxContext(ClientPtr client, XID id, int access_mode,
134
                __GLXcontext ** context, int *err)
135
{
136
    *err = dixLookupResourceByType((void **) context, id,
137
                                   __glXContextRes, client, access_mode);
Adam Jackson's avatar
Adam Jackson committed
138
    if (*err != Success || (*context)->idExists == GL_FALSE) {
139 140 141 142
        client->errorValue = id;
        if (*err == BadValue || *err == Success)
            *err = __glXError(GLXBadContext);
        return FALSE;
143 144 145 146 147
    }

    return TRUE;
}

148 149
static int
validGlxDrawable(ClientPtr client, XID id, int type, int access_mode,
150
                 __GLXdrawable ** drawable, int *err)
151 152 153
{
    int rc;

154
    rc = dixLookupResourceByType((void **) drawable, id,
155
                                 __glXDrawableRes, client, access_mode);
156
    if (rc != Success && rc != BadValue) {
157 158 159
        *err = rc;
        client->errorValue = id;
        return FALSE;
160 161
    }

162 163 164
    /* 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). */
165
    if (rc == BadValue ||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
        (*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;
        }
183 184 185 186 187
    }

    return TRUE;
}

188
void
189
__glXContextDestroy(__GLXcontext * context)
190
{
191
    lastGLContext = NULL;
192 193
}

194 195
static void
__glXdirectContextDestroy(__GLXcontext * context)
196
{
197
    __glXContextDestroy(context);
198
    free(context);
199 200
}

201 202 203 204 205 206
static int
__glXdirectContextLoseCurrent(__GLXcontext * context)
{
    return GL_TRUE;
}

207
_X_HIDDEN __GLXcontext *
208 209
__glXdirectContextCreate(__GLXscreen * screen,
                         __GLXconfig * modes, __GLXcontext * shareContext)
210 211 212
{
    __GLXcontext *context;

213
    context = calloc(1, sizeof(__GLXcontext));
214
    if (context == NULL)
215
        return NULL;
216 217

    context->destroy = __glXdirectContextDestroy;
218
    context->loseCurrent = __glXdirectContextLoseCurrent;
219 220 221 222

    return context;
}

Eric Anholt's avatar
Eric Anholt committed
223 224 225 226 227 228 229 230
/**
 * Create a GL context with the given properties.  This routine is used
 * to implement \c glXCreateContext, \c glXCreateNewContext, and
 * \c glXCreateContextWithConfigSGIX.  This works becuase of the hack way
 * that GLXFBConfigs are implemented.  Basically, the FBConfigID is the
 * same as the VisualID.
 */

Kristian Høgsberg's avatar
Kristian Høgsberg committed
231
static int
232 233 234
DoCreateContext(__GLXclientState * cl, GLXContextID gcId,
                GLXContextID shareList, __GLXconfig * config,
                __GLXscreen * pGlxScreen, GLboolean isDirect)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
235 236 237
{
    ClientPtr client = cl->client;
    __GLXcontext *glxc, *shareglxc;
238
    int err;
239

240
    LEGAL_NEW_RESOURCE(gcId, client);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
241 242

    /*
Peter Hutterer's avatar
Peter Hutterer committed
243
     ** Find the display list space that we want to share.
244 245
     **
     ** NOTE: In a multithreaded X server, we would need to keep a reference
Peter Hutterer's avatar
Peter Hutterer committed
246 247 248 249
     ** 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.
250
     */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
251
    if (shareList == None) {
252 253 254 255 256 257 258
        shareglxc = 0;
    }
    else {
        if (!validGlxContext(client, shareList, DixReadAccess,
                             &shareglxc, &err))
            return err;

259 260 261 262 263 264 265 266 267 268
        /* 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) {
269 270 271
            client->errorValue = shareList;
            return BadMatch;
        }
272
        else if (!shareglxc->isDirect) {
273 274 275 276 277 278
            /*
             ** Create an indirect context regardless of what the client asked
             ** for; this way we can share display list space with shareList.
             */
            isDirect = GL_FALSE;
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
279 280 281
    }

    /*
282 283
     ** Allocate memory for the new context
     */
284
    if (!isDirect) {
285 286 287 288 289 290 291 292 293 294 295
        /* 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;
        }

296 297 298 299 300 301 302
        /* 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);
    }
303
    else
304
        glxc = __glXdirectContextCreate(pGlxScreen, config, shareglxc);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
305
    if (!glxc) {
306
        return BadAlloc;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
307 308
    }

309
    /* Initialize the GLXcontext structure.
310
     */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
311
    glxc->pGlxScreen = pGlxScreen;
312
    glxc->config = config;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
313 314 315
    glxc->id = gcId;
    glxc->share_id = shareList;
    glxc->idExists = GL_TRUE;
316
    glxc->currentClient = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
317
    glxc->isDirect = isDirect;
318
    glxc->hasUnflushedCommands = GL_FALSE;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
319
    glxc->renderMode = GL_RENDER;
320 321 322 323 324 325
    glxc->feedbackBuf = NULL;
    glxc->feedbackBufSize = 0;
    glxc->selectBuf = NULL;
    glxc->selectBufSize = 0;
    glxc->drawPriv = NULL;
    glxc->readPriv = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
326

327 328 329 330 331 332 333 334 335 336
    /* 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;

337 338 339 340 341 342 343 344 345 346 347 348 349
#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

350
    /* Add the new context to the various global tables of GLX contexts.
351
     */
352
    if (!__glXAddContext(glxc)) {
353 354 355 356 357
        (*glxc->destroy) (glxc);
        client->errorValue = gcId;
        return BadAlloc;
    }

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
358 359 360
    return Success;
}

361 362
int
__glXDisp_CreateContext(__GLXclientState * cl, GLbyte * pc)
Eric Anholt's avatar
Eric Anholt committed
363
{
Julien Cristau's avatar
Julien Cristau committed
364
    ClientPtr client = cl->client;
Eric Anholt's avatar
Eric Anholt committed
365
    xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;
366
    __GLXconfig *config;
367 368
    __GLXscreen *pGlxScreen;
    int err;
Eric Anholt's avatar
Eric Anholt committed
369

Julien Cristau's avatar
Julien Cristau committed
370 371
    REQUEST_SIZE_MATCH(xGLXCreateContextReq);

372
    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
373
        return err;
374
    if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err))
375
        return err;
376 377

    return DoCreateContext(cl, req->context, req->shareList,
378
                           config, pGlxScreen, req->isDirect);
379
}
Eric Anholt's avatar
Eric Anholt committed
380

381 382
int
__glXDisp_CreateNewContext(__GLXclientState * cl, GLbyte * pc)
Eric Anholt's avatar
Eric Anholt committed
383
{
Julien Cristau's avatar
Julien Cristau committed
384
    ClientPtr client = cl->client;
Eric Anholt's avatar
Eric Anholt committed
385
    xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
386
    __GLXconfig *config;
387 388 389
    __GLXscreen *pGlxScreen;
    int err;

Julien Cristau's avatar
Julien Cristau committed
390 391
    REQUEST_SIZE_MATCH(xGLXCreateNewContextReq);

392
    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
393
        return err;
394
    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
395
        return err;
Eric Anholt's avatar
Eric Anholt committed
396

397
    return DoCreateContext(cl, req->context, req->shareList,
398
                           config, pGlxScreen, req->isDirect);
399
}
Eric Anholt's avatar
Eric Anholt committed
400

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

Julien Cristau's avatar
Julien Cristau committed
411 412
    REQUEST_SIZE_MATCH(xGLXCreateContextWithConfigSGIXReq);

413
    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
414
        return err;
415
    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
416
        return err;
417 418

    return DoCreateContext(cl, req->context, req->shareList,
419
                           config, pGlxScreen, req->isDirect);
420
}
Adam Jackson's avatar
Adam Jackson committed
421

422 423
int
__glXDisp_DestroyContext(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
424
{
Julien Cristau's avatar
Julien Cristau committed
425
    ClientPtr client = cl->client;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
426 427
    xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc;
    __GLXcontext *glxc;
428 429
    int err;

Julien Cristau's avatar
Julien Cristau committed
430 431
    REQUEST_SIZE_MATCH(xGLXDestroyContextReq);

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

436 437 438
    glxc->idExists = GL_FALSE;
    if (!glxc->currentClient)
        FreeResourceByType(req->context, __glXContextRes, FALSE);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
439

Adam Jackson's avatar
Adam Jackson committed
440
    return Success;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
441 442 443
}

/*
Adam Jackson's avatar
Adam Jackson committed
444 445 446 447 448 449 450 451
 * This will return "deleted" contexts, ie, where idExists is GL_FALSE.
 * Contrast validGlxContext, which will not.  We're cheating here and
 * using the XID as the context tag, which is fine as long as we defer
 * actually destroying the context until it's no longer referenced, and
 * block clients from trying to MakeCurrent on contexts that are on the
 * way to destruction.  Notice that DoMakeCurrent calls validGlxContext
 * for new contexts but __glXLookupContextByTag for previous contexts.
 */
452 453
__GLXcontext *
__glXLookupContextByTag(__GLXclientState * cl, GLXContextTag tag)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
454
{
Adam Jackson's avatar
Adam Jackson committed
455
    __GLXcontext *ret;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
456

457
    if (dixLookupResourceByType((void **) &ret, tag, __glXContextRes,
Adam Jackson's avatar
Adam Jackson committed
458 459 460 461
                                cl->client, DixUseAccess) == Success)
        return ret;

    return NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
462 463 464 465
}

/*****************************************************************************/

466 467
static void
StopUsingContext(__GLXcontext * glxc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
468 469
{
    if (glxc) {
470
        glxc->currentClient = NULL;
471
        if (!glxc->idExists) {
Adam Jackson's avatar
Adam Jackson committed
472
            FreeResourceByType(glxc->id, __glXContextRes, FALSE);
473
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
474 475 476
    }
}

477 478
static void
StartUsingContext(__GLXclientState * cl, __GLXcontext * glxc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
479
{
480
    glxc->currentClient = cl->client;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
481 482
}

483
/**
484 485 486 487
 * 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.
488
 */
Kristian Høgsberg's avatar
Kristian Høgsberg committed
489
static __GLXdrawable *
490 491
__glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client,
                 int *error)
492 493
{
    DrawablePtr pDraw;
494
    __GLXdrawable *pGlxDraw;
495
    int rc;
496

497
    if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY,
498 499 500 501 502 503
                         DixWriteAccess, &pGlxDraw, &rc)) {
        if (glxc != NULL && pGlxDraw->config != glxc->config) {
            client->errorValue = drawId;
            *error = BadMatch;
            return NULL;
        }
504

505
        return pGlxDraw;
506 507
    }

508 509
    /* No active context and an unknown drawable, bail. */
    if (glxc == NULL) {
510 511 512
        client->errorValue = drawId;
        *error = BadMatch;
        return NULL;
513 514
    }

515 516 517 518
    /* 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. */
519

520
    rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
521
    if (rc != Success || pDraw->type != DRAWABLE_WINDOW) {
522 523 524
        client->errorValue = drawId;
        *error = __glXError(GLXBadDrawable);
        return NULL;
525 526
    }

527
    if (pDraw->pScreen != glxc->pGlxScreen->pScreen) {
528 529 530
        client->errorValue = pDraw->pScreen->myNum;
        *error = BadMatch;
        return NULL;
531 532
    }

533
    if (!validGlxFBConfigForWindow(client, glxc->config, pDraw, error))
534
        return NULL;
535

536
    pGlxDraw = glxc->pGlxScreen->createDrawable(client, glxc->pGlxScreen,
537 538 539
                                                pDraw, drawId,
                                                GLX_DRAWABLE_WINDOW,
                                                drawId, glxc->config);
540 541 542 543
    if (!pGlxDraw) {
	*error = BadAlloc;
	return NULL;
    }
544 545 546

    /* since we are creating the drawablePrivate, drawId should be new */
    if (!AddResource(drawId, __glXDrawableRes, pGlxDraw)) {
547 548 549
        pGlxDraw->destroy(pGlxDraw);
        *error = BadAlloc;
        return NULL;
550 551
    }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
552
    return pGlxDraw;
553 554
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
555 556 557 558
/*****************************************************************************/
/*
** Make an OpenGL context and drawable current.
*/
559

Kristian Høgsberg's avatar
Kristian Høgsberg committed
560
static int
561 562 563
DoMakeCurrent(__GLXclientState * cl,
              GLXDrawable drawId, GLXDrawable readId,
              GLXContextID contextId, GLXContextTag tag)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
564 565 566 567
{
    ClientPtr client = cl->client;
    xGLXMakeCurrentReply reply;
    __GLXcontext *glxc, *prevglxc;
568 569
    __GLXdrawable *drawPriv = NULL;
    __GLXdrawable *readPriv = NULL;
570
    int error;
571
    GLuint mask;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
572 573

    /*
574 575
     ** If one is None and the other isn't, it's a bad match.
     */
576

577 578
    mask = (drawId == None) ? (1 << 0) : 0;
    mask |= (readId == None) ? (1 << 1) : 0;
579 580
    mask |= (contextId == None) ? (1 << 2) : 0;

581 582
    if ((mask != 0x00) && (mask != 0x07)) {
        return BadMatch;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
583
    }
584

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
585
    /*
586 587
     ** Lookup old context.  If we have one, it must be in a usable state.
     */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
588
    if (tag != 0) {
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
        prevglxc = __glXLookupContextByTag(cl, tag);
        if (!prevglxc) {
            /*
             ** Tag for previous context is invalid.
             */
            return __glXError(GLXBadContextTag);
        }
        if (prevglxc->renderMode != GL_RENDER) {
            /* Oops.  Not in render mode render. */
            client->errorValue = prevglxc->id;
            return __glXError(GLXBadContextState);
        }
    }
    else {
        prevglxc = 0;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
604 605 606
    }

    /*
607 608
     ** Lookup new context.  It must not be current for someone else.
     */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
609
    if (contextId != None) {
610
        int status;
611

612 613
        if (!validGlxContext(client, contextId, DixUseAccess, &glxc, &error))
            return error;
614
        if ((glxc != prevglxc) && glxc->currentClient) {
615 616 617
            /* Context is current to somebody else */
            return BadAccess;
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
618

619 620
        assert(drawId != None);
        assert(readId != None);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
621

622 623 624
        drawPriv = __glXGetDrawable(glxc, drawId, client, &status);
        if (drawPriv == NULL)
            return status;
625

626 627 628
        readPriv = __glXGetDrawable(glxc, readId, client, &status);
        if (readPriv == NULL)
            return status;
629

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
630
    }
631 632 633 634 635 636
    else {
        /* Switching to no context.  Ignore new drawable. */
        glxc = 0;
        drawPriv = 0;
        readPriv = 0;
    }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
637 638

    if (prevglxc) {
639 640 641
        /*
         ** Flush the previous context if needed.
         */
642 643 644 645 646 647
        Bool need_flush = GL_TRUE;
#ifdef GLX_CONTEXT_RELEASE_BEHAVIOR_ARB
        if (prevglxc->releaseBehavior == GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB)
            need_flush = GL_FALSE;
#endif
        if (prevglxc->hasUnflushedCommands && need_flush) {
648
            if (__glXForceCurrent(cl, tag, (int *) &error)) {
649
                glFlush();
650 651 652 653 654 655 656 657 658 659 660 661 662
                prevglxc->hasUnflushedCommands = GL_FALSE;
            }
            else {
                return error;
            }
        }

        /*
         ** Make the previous context not current.
         */
        if (!(*prevglxc->loseCurrent) (prevglxc)) {
            return __glXError(GLXBadContext);
        }
663
        lastGLContext = NULL;
664 665 666 667 668
        if (!prevglxc->isDirect) {
            prevglxc->drawPriv = NULL;
            prevglxc->readPriv = NULL;
        }
    }
669

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
670 671
    if ((glxc != 0) && !glxc->isDirect) {

672 673
        glxc->drawPriv = drawPriv;
        glxc->readPriv = readPriv;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
674

675
        /* make the context current */
676
        lastGLContext = glxc;
677
        if (!(*glxc->makeCurrent) (glxc)) {
678
            lastGLContext = NULL;
679 680 681 682
            glxc->drawPriv = NULL;
            glxc->readPriv = NULL;
            return __glXError(GLXBadContext);
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
683

684
        glxc->currentClient = client;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
685 686
    }

Adam Jackson's avatar
Adam Jackson committed
687
    StopUsingContext(prevglxc);
688

689 690 691 692 693 694 695
    reply = (xGLXMakeCurrentReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = 0,
        .contextTag = 0
    };

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
696
    if (glxc) {
697 698 699
        StartUsingContext(cl, glxc);
        reply.contextTag = glxc->id;
    }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
700 701

    if (client->swapped) {
702 703 704
        __glXSwapMakeCurrentReply(client, &reply);
    }
    else {
705
        WriteToClient(client, sz_xGLXMakeCurrentReply, &reply);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
706 707 708 709
    }
    return Success;
}

710 711
int
__glXDisp_MakeCurrent(__GLXclientState * cl, GLbyte * pc)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
712
{
Julien Cristau's avatar
Julien Cristau committed
713
    ClientPtr client = cl->client;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
714 715
    xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc;

Julien Cristau's avatar
Julien Cristau committed
716 717
    REQUEST_SIZE_MATCH(xGLXMakeCurrentReq);

718 719
    return DoMakeCurrent(cl, req->drawable, req->drawable,
                         req->context, req->oldContextTag);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
720 721
}

722 723
int
__glXDisp_MakeContextCurrent(__GLXclientState * cl, GLbyte * pc)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
724
{
Julien Cristau's avatar
Julien Cristau committed
725
    ClientPtr client = cl->client;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
726 727
    xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc;

Julien Cristau's avatar
Julien Cristau committed
728 729
    REQUEST_SIZE_MATCH(xGLXMakeContextCurrentReq);

730 731
    return DoMakeCurrent(cl, req->drawable, req->readdrawable,
                         req->context, req->oldContextTag);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
732 733
}

734 735
int
__glXDisp_MakeCurrentReadSGI(__GLXclientState * cl, GLbyte * pc)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
736
{
Julien Cristau's avatar
Julien Cristau committed
737
    ClientPtr client = cl->client;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
738 739
    xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc;

Julien Cristau's avatar
Julien Cristau committed
740 741
    REQUEST_SIZE_MATCH(xGLXMakeCurrentReadSGIReq);

742 743
    return DoMakeCurrent(cl, req->drawable, req->readable,
                         req->context, req->oldContextTag);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
744 745
}

746 747
int
__glXDisp_IsDirect(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
748 749 750 751 752
{
    ClientPtr client = cl->client;
    xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc;
    xGLXIsDirectReply reply;
    __GLXcontext *glxc;
753
    int err;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
754

Julien Cristau's avatar
Julien Cristau committed
755 756
    REQUEST_SIZE_MATCH(xGLXIsDirectReq);

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

760 761 762 763 764 765
    reply = (xGLXIsDirectReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = 0,
        .isDirect = glxc->isDirect
    };
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
766 767

    if (client->swapped) {
768 769 770
        __glXSwapIsDirectReply(client, &reply);
    }
    else {
771
        WriteToClient(client, sz_xGLXIsDirectReply, &reply);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
772 773 774 775 776
    }

    return Success;
}

777 778
int
__glXDisp_QueryVersion(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
779 780 781 782 783 784
{
    ClientPtr client = cl->client;
    xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc;
    xGLXQueryVersionReply reply;
    GLuint major, minor;

Julien Cristau's avatar
Julien Cristau committed
785 786
    REQUEST_SIZE_MATCH(xGLXQueryVersionReq);

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
787 788
    major = req->majorVersion;
    minor = req->minorVersion;
789 790
    (void) major;
    (void) minor;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
791 792

    /*
793 794 795 796
     ** 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.
     */
797 798 799 800 801 802 803
    reply = (xGLXQueryVersionReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = 0,
        .majorVersion = glxMajorVersion,
        .minorVersion = glxMinorVersion
    };
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
804 805

    if (client->swapped) {
806 807 808
        __glXSwapQueryVersionReply(client, &reply);
    }
    else {
809
        WriteToClient(client, sz_xGLXQueryVersionReply, &reply);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
810 811 812 813
    }
    return Success;
}

814 815
int
__glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
816
{
Julien Cristau's avatar
Julien Cristau committed
817
    ClientPtr client = cl->client;
818
    xGLXWaitGLReq *req = (xGLXWaitGLReq *) pc;
Julien Cristau's avatar
Julien Cristau committed
819
    GLXContextTag tag;
820
    __GLXcontext *glxc = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
821
    int error;
822

Julien Cristau's avatar
Julien Cristau committed
823 824 825
    REQUEST_SIZE_MATCH(xGLXWaitGLReq);

    tag = req->contextTag;
826
    if (tag) {
827 828 829 830 831 832
        glxc = __glXLookupContextByTag(cl, tag);
        if (!glxc)
            return __glXError(GLXBadContextTag);

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

834
        glFinish();
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
835
    }
836 837

    if (glxc && glxc->drawPriv->waitGL)
838
        (*glxc->drawPriv->waitGL) (glxc->drawPriv);
839

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
840 841 842
    return Success;
}

843 844
int
__glXDisp_WaitX(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
845
{
Julien Cristau's avatar
Julien Cristau committed
846
    ClientPtr client = cl->client;
847
    xGLXWaitXReq *req = (xGLXWaitXReq *) pc;
Julien Cristau's avatar
Julien Cristau committed
848
    GLXContextTag tag;
849
    __GLXcontext *glxc = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
850
    int error;
851

Julien Cristau's avatar
Julien Cristau committed
852 853 854
    REQUEST_SIZE_MATCH(xGLXWaitXReq);

    tag = req->contextTag;
855
    if (tag) {
856 857 858 859 860 861
        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
862
    }
863

Pierre Willenbrock's avatar
Pierre Willenbrock committed
864
    if (glxc && glxc->drawPriv->waitX)
865
        (*glxc->drawPriv->waitX) (glxc->drawPriv);
866

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
867 868 869
    return Success;
}

870 871
int
__glXDisp_CopyContext(__GLXclientState * cl, GLbyte * pc)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
872 873 874
{
    ClientPtr client = cl->client;
    xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc;
Julien Cristau's avatar
Julien Cristau committed
875 876 877 878
    GLXContextID source;
    GLXContextID dest;
    GLXContextTag tag;
    unsigned long mask;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
879 880 881
    __GLXcontext *src, *dst;
    int error;

Julien Cristau's avatar