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 45glXCreateContextAttribsARB(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 /* Some application may request an indirect context but we may want to force a direct 96 * one because Xorg only allows indirect contexts if they were enabled. 97 */ 98 if (!direct && 99 psc->force_direct_context) { 100 direct = true; 101 } 102 103 104 if (direct && psc->vtable->create_context_attribs) { 105 /* GLX drops the error returned by the driver. The expectation is that 106 * an error will also be returned by the server. The server's error 107 * will be delivered to the application. 108 */ 109 gc = psc->vtable->create_context_attribs(psc, cfg, share, num_attribs, 110 (const uint32_t *) attrib_list, 111 &dummy_err); 112 } 113 114 if (gc == NULL) { 115#ifdef GLX_USE_APPLEGL 116 gc = applegl_create_context(psc, cfg, share, 0); 117#else 118 gc = indirect_create_context_attribs(psc, cfg, share, num_attribs, 119 (const uint32_t *) attrib_list, 120 &dummy_err); 121#endif 122 } 123 124 xid = xcb_generate_id(c); 125 share_xid = (share != NULL) ? share->xid : 0; 126 127 /* The manual pages for glXCreateContext and glXCreateNewContext say: 128 * 129 * "NULL is returned if execution fails on the client side." 130 * 131 * If the server generates an error, the application is supposed to catch 132 * the protocol error and handle it. Part of handling the error is freeing 133 * the possibly non-NULL value returned by this function. 134 */ 135 cookie = 136 xcb_glx_create_context_attribs_arb_checked(c, 137 xid, 138 cfg ? cfg->fbconfigID : 0, 139 screen, 140 share_xid, 141 gc ? gc->isDirect : direct, 142 num_attribs, 143 (const uint32_t *) 144 attrib_list); 145 err = xcb_request_check(c, cookie); 146 if (err != NULL) { 147 if (gc) 148 gc->vtable->destroy(gc); 149 gc = NULL; 150 151 __glXSendErrorForXcb(dpy, err); 152 free(err); 153 } else if (!gc) { 154 /* the server thought the context description was okay, but we failed 155 * somehow on the client side. clean up the server resource and panic. 156 */ 157 xcb_glx_destroy_context(c, xid); 158 /* increment dpy->request in order to give a unique serial number to the 159 * error */ 160 XNoOp(dpy); 161 __glXSendError(dpy, GLXBadFBConfig, xid, 0, False); 162 } else { 163 gc->xid = xid; 164 gc->share_xid = share_xid; 165 } 166 167 return (GLXContext) gc; 168} 169