mesa/src/glx/create_context.c

169 lines
5.4 KiB
C

/*
* Copyright © 2011 Intel Corporation
*
* 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 and this permission notice (including the next
* paragraph) 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <limits.h>
#include "glxclient.h"
#include "glx_error.h"
#include <xcb/glx.h>
#include <X11/Xlib-xcb.h>
#include <assert.h>
#if INT_MAX != 2147483647
#error This code requires sizeof(uint32_t) == sizeof(int).
#endif
/* An "Atrribs/Attribs" typo was fixed in glxproto.h in Nov 2014.
* This is in case we don't have the updated header.
*/
#if !defined(X_GLXCreateContextAttribsARB) && \
defined(X_GLXCreateContextAtrribsARB)
#define X_GLXCreateContextAttribsARB X_GLXCreateContextAtrribsARB
#endif
_X_HIDDEN GLXContext
glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config,
GLXContext share_context, Bool direct,
const int *attrib_list)
{
xcb_connection_t *const c = XGetXCBConnection(dpy);
struct glx_config *const cfg = (struct glx_config *) config;
struct glx_context *const share = (struct glx_context *) share_context;
struct glx_context *gc = NULL;
unsigned num_attribs = 0;
struct glx_screen *psc;
xcb_generic_error_t *err;
xcb_void_cookie_t cookie;
unsigned dummy_err = 0;
uint32_t xid, share_xid;
int screen = -1;
if (dpy == NULL)
return NULL;
/* Count the number of attributes specified by the application. All
* attributes appear in pairs, except the terminating None.
*/
if (attrib_list != NULL) {
for (/* empty */; attrib_list[num_attribs * 2] != 0; num_attribs++)
/* empty */ ;
}
if (cfg) {
screen = cfg->screen;
} else {
for (unsigned int i = 0; i < num_attribs; i++) {
if (attrib_list[i * 2] == GLX_SCREEN)
screen = attrib_list[i * 2 + 1];
}
if (screen == -1) {
__glXSendError(dpy, BadValue, 0, X_GLXCreateContextAttribsARB, True);
return NULL;
}
}
/* This means that either the caller passed the wrong display pointer or
* one of the internal GLX data structures (probably the fbconfig) has an
* error. There is nothing sensible to do, so return an error.
*/
psc = GetGLXScreenConfigs(dpy, screen);
if (psc == NULL)
return NULL;
assert(screen == psc->scr);
/* Some application may request an indirect context but we may want to force a direct
* one because Xorg only allows indirect contexts if they were enabled.
*/
if (!direct &&
psc->force_direct_context) {
direct = true;
}
if (direct && psc->vtable->create_context_attribs) {
/* GLX drops the error returned by the driver. The expectation is that
* an error will also be returned by the server. The server's error
* will be delivered to the application.
*/
gc = psc->vtable->create_context_attribs(psc, cfg, share, num_attribs,
(const uint32_t *) attrib_list,
&dummy_err);
}
if (gc == NULL) {
#ifdef GLX_USE_APPLEGL
gc = applegl_create_context(psc, cfg, share, 0);
#else
gc = indirect_create_context_attribs(psc, cfg, share, num_attribs,
(const uint32_t *) attrib_list,
&dummy_err);
#endif
}
xid = xcb_generate_id(c);
share_xid = (share != NULL) ? share->xid : 0;
/* The manual pages for glXCreateContext and glXCreateNewContext say:
*
* "NULL is returned if execution fails on the client side."
*
* If the server generates an error, the application is supposed to catch
* the protocol error and handle it. Part of handling the error is freeing
* the possibly non-NULL value returned by this function.
*/
cookie =
xcb_glx_create_context_attribs_arb_checked(c,
xid,
cfg ? cfg->fbconfigID : 0,
screen,
share_xid,
gc ? gc->isDirect : direct,
num_attribs,
(const uint32_t *)
attrib_list);
err = xcb_request_check(c, cookie);
if (err != NULL) {
if (gc)
gc->vtable->destroy(gc);
gc = NULL;
__glXSendErrorForXcb(dpy, err);
free(err);
} else if (!gc) {
/* the server thought the context description was okay, but we failed
* somehow on the client side. clean up the server resource and panic.
*/
xcb_glx_destroy_context(c, xid);
/* increment dpy->request in order to give a unique serial number to the
* error */
XNoOp(dpy);
__glXSendError(dpy, GLXBadFBConfig, xid, 0, False);
} else {
gc->xid = xid;
gc->share_xid = share_xid;
}
return (GLXContext) gc;
}