1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <limits.h>
25 #include "glxclient.h"
26 #include "glx_error.h"
27 #include <xcb/glx.h>
28 #include <X11/Xlib-xcb.h>
29 
30 #include <assert.h>
31 
32 #if INT_MAX != 2147483647
33 #error This code requires sizeof(uint32_t) == sizeof(int).
34 #endif
35 
36 /* An "Atrribs/Attribs" typo was fixed in glxproto.h in Nov 2014.
37  * This is in case we don't have the updated header.
38  */
39 #if !defined(X_GLXCreateContextAttribsARB) && \
40      defined(X_GLXCreateContextAtrribsARB)
41 #define X_GLXCreateContextAttribsARB X_GLXCreateContextAtrribsARB
42 #endif
43 
44 _X_HIDDEN GLXContext
glXCreateContextAttribsARB(Display * dpy,GLXFBConfig config,GLXContext share_context,Bool direct,const int * attrib_list)45 glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config,
46 			   GLXContext share_context, Bool direct,
47 			   const int *attrib_list)
48 {
49    xcb_connection_t *const c = XGetXCBConnection(dpy);
50    struct glx_config *const cfg = (struct glx_config *) config;
51    struct glx_context *const share = (struct glx_context *) share_context;
52    struct glx_context *gc = NULL;
53    unsigned num_attribs = 0;
54    struct glx_screen *psc;
55    xcb_generic_error_t *err;
56    xcb_void_cookie_t cookie;
57    unsigned dummy_err = 0;
58    uint32_t xid, share_xid;
59    int screen = -1;
60 
61    if (dpy == NULL)
62       return NULL;
63 
64    /* Count the number of attributes specified by the application.  All
65     * attributes appear in pairs, except the terminating None.
66     */
67    if (attrib_list != NULL) {
68       for (/* empty */; attrib_list[num_attribs * 2] != 0; num_attribs++)
69 	 /* empty */ ;
70    }
71 
72    if (cfg) {
73       screen = cfg->screen;
74    } else {
75       for (unsigned int i = 0; i < num_attribs; i++) {
76          if (attrib_list[i * 2] == GLX_SCREEN)
77             screen = attrib_list[i * 2 + 1];
78       }
79       if (screen == -1) {
80          __glXSendError(dpy, BadValue, 0, X_GLXCreateContextAttribsARB, True);
81          return NULL;
82       }
83    }
84 
85    /* This means that either the caller passed the wrong display pointer or
86     * one of the internal GLX data structures (probably the fbconfig) has an
87     * error.  There is nothing sensible to do, so return an error.
88     */
89    psc = GetGLXScreenConfigs(dpy, screen);
90    if (psc == NULL)
91       return NULL;
92 
93    assert(screen == psc->scr);
94 
95    if (direct && psc->vtable->create_context_attribs) {
96       /* GLX drops the error returned by the driver.  The expectation is that
97        * an error will also be returned by the server.  The server's error
98        * will be delivered to the application.
99        */
100       gc = psc->vtable->create_context_attribs(psc, cfg, share, num_attribs,
101 					       (const uint32_t *) attrib_list,
102 					       &dummy_err);
103    }
104 
105    if (gc == NULL) {
106 #ifdef GLX_USE_APPLEGL
107       gc = applegl_create_context(psc, cfg, share, 0);
108 #else
109       gc = indirect_create_context_attribs(psc, cfg, share, num_attribs,
110               (const uint32_t *) attrib_list,
111               &dummy_err);
112 #endif
113    }
114 
115    xid = xcb_generate_id(c);
116    share_xid = (share != NULL) ? share->xid : 0;
117 
118    /* The manual pages for glXCreateContext and glXCreateNewContext say:
119     *
120     *     "NULL is returned if execution fails on the client side."
121     *
122     * If the server generates an error, the application is supposed to catch
123     * the protocol error and handle it.  Part of handling the error is freeing
124     * the possibly non-NULL value returned by this function.
125     */
126    cookie =
127       xcb_glx_create_context_attribs_arb_checked(c,
128 						 xid,
129 						 cfg ? cfg->fbconfigID : 0,
130 						 screen,
131 						 share_xid,
132 						 gc ? gc->isDirect : direct,
133 						 num_attribs,
134 						 (const uint32_t *)
135 						 attrib_list);
136    err = xcb_request_check(c, cookie);
137    if (err != NULL) {
138       if (gc)
139          gc->vtable->destroy(gc);
140       gc = NULL;
141 
142       __glXSendErrorForXcb(dpy, err);
143       free(err);
144    } else if (!gc) {
145       /* the server thought the context description was okay, but we failed
146        * somehow on the client side. clean up the server resource and panic.
147        */
148       xcb_glx_destroy_context(c, xid);
149       /* increment dpy->request in order to give a unique serial number to the
150        * error */
151       XNoOp(dpy);
152       __glXSendError(dpy, GLXBadFBConfig, xid, 0, False);
153    } else {
154       gc->xid = xid;
155       gc->share_xid = share_xid;
156    }
157 
158    return (GLXContext) gc;
159 }
160