1/* 2 * Copyright © 2010 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 "Soft- 6 * ware"), to deal in the Software without restriction, including without 7 * limitation the rights to use, copy, modify, merge, publish, distribute, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, provided that the above copyright 10 * notice(s) and this permission notice appear in all copies of the Soft- 11 * ware and that both the above copyright notice(s) and this permission 12 * notice appear in supporting documentation. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22 * MANCE OF THIS SOFTWARE. 23 * 24 * Except as contained in this notice, the name of a copyright holder shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization of 27 * the copyright holder. 28 * 29 * Authors: 30 * Kristian Høgsberg (krh@bitplanet.net) 31 */ 32 33#include <stdbool.h> 34 35#include "glapi.h" 36#include "glxclient.h" 37#include "indirect.h" 38#include "util/debug.h" 39 40#ifndef GLX_USE_APPLEGL 41 42extern struct _glapi_table *__glXNewIndirectAPI(void); 43 44/* 45** All indirect rendering contexts will share the same indirect dispatch table. 46*/ 47static struct _glapi_table *IndirectAPI = NULL; 48 49static void 50__glFreeAttributeState(struct glx_context * gc) 51{ 52 __GLXattribute *sp, **spp; 53 54 for (spp = &gc->attributes.stack[0]; 55 spp < &gc->attributes.stack[__GL_CLIENT_ATTRIB_STACK_DEPTH]; spp++) { 56 sp = *spp; 57 if (sp) { 58 free((char *) sp); 59 } 60 else { 61 break; 62 } 63 } 64} 65 66static void 67indirect_destroy_context(struct glx_context *gc) 68{ 69 __glXFreeVertexArrayState(gc); 70 71 free((char *) gc->vendor); 72 free((char *) gc->renderer); 73 free((char *) gc->version); 74 free((char *) gc->extensions); 75 __glFreeAttributeState(gc); 76 free((char *) gc->buf); 77 free((char *) gc->client_state_private); 78 free((char *) gc); 79} 80 81static Bool 82SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id, 83 GLXContextTag gc_tag, GLXDrawable draw, 84 GLXDrawable read, GLXContextTag *out_tag) 85{ 86 xGLXMakeCurrentReply reply; 87 Bool ret; 88 int opcode = __glXSetupForCommand(dpy); 89 90 LockDisplay(dpy); 91 92 if (draw == read) { 93 xGLXMakeCurrentReq *req; 94 95 GetReq(GLXMakeCurrent, req); 96 req->reqType = opcode; 97 req->glxCode = X_GLXMakeCurrent; 98 req->drawable = draw; 99 req->context = gc_id; 100 req->oldContextTag = gc_tag; 101 } 102 else { 103 struct glx_display *priv = __glXInitialize(dpy); 104 105 /* If the server can support the GLX 1.3 version, we should 106 * perfer that. Not only that, some servers support GLX 1.3 but 107 * not the SGI extension. 108 */ 109 110 if (priv->minorVersion >= 3) { 111 xGLXMakeContextCurrentReq *req; 112 113 GetReq(GLXMakeContextCurrent, req); 114 req->reqType = opcode; 115 req->glxCode = X_GLXMakeContextCurrent; 116 req->drawable = draw; 117 req->readdrawable = read; 118 req->context = gc_id; 119 req->oldContextTag = gc_tag; 120 } 121 else { 122 xGLXVendorPrivateWithReplyReq *vpreq; 123 xGLXMakeCurrentReadSGIReq *req; 124 125 GetReqExtra(GLXVendorPrivateWithReply, 126 sz_xGLXMakeCurrentReadSGIReq - 127 sz_xGLXVendorPrivateWithReplyReq, vpreq); 128 req = (xGLXMakeCurrentReadSGIReq *) vpreq; 129 req->reqType = opcode; 130 req->glxCode = X_GLXVendorPrivateWithReply; 131 req->vendorCode = X_GLXvop_MakeCurrentReadSGI; 132 req->drawable = draw; 133 req->readable = read; 134 req->context = gc_id; 135 req->oldContextTag = gc_tag; 136 } 137 } 138 139 ret = _XReply(dpy, (xReply *) &reply, 0, False); 140 141 if (out_tag) 142 *out_tag = reply.contextTag; 143 144 UnlockDisplay(dpy); 145 SyncHandle(); 146 147 return ret; 148} 149 150static int 151indirect_bind_context(struct glx_context *gc, struct glx_context *old, 152 GLXDrawable draw, GLXDrawable read) 153{ 154 GLXContextTag tag; 155 Display *dpy = gc->psc->dpy; 156 Bool sent; 157 158 if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) { 159 tag = old->currentContextTag; 160 old->currentContextTag = 0; 161 } else { 162 tag = 0; 163 } 164 165 sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read, 166 &gc->currentContextTag); 167 168 if (sent) { 169 if (!IndirectAPI) 170 IndirectAPI = __glXNewIndirectAPI(); 171 _glapi_set_dispatch(IndirectAPI); 172 173 /* The indirect vertex array state must to be initialised after we 174 * have setup the context, as it needs to query server attributes. 175 * 176 * At the point this is called gc->currentDpy is not initialized 177 * nor is the thread's current context actually set. Hence the 178 * cleverness before the GetString calls. 179 */ 180 __GLXattribute *state = gc->client_state_private; 181 if (state && state->array_state == NULL) { 182 gc->currentDpy = gc->psc->dpy; 183 __glXSetCurrentContext(gc); 184 __indirect_glGetString(GL_EXTENSIONS); 185 __indirect_glGetString(GL_VERSION); 186 __glXInitVertexArrayState(gc); 187 } 188 } 189 190 return !sent; 191} 192 193static void 194indirect_unbind_context(struct glx_context *gc, struct glx_context *new) 195{ 196 Display *dpy = gc->psc->dpy; 197 198 if (gc == new) 199 return; 200 201 /* We are either switching to no context, away from an indirect 202 * context to a direct context or from one dpy to another and have 203 * to send a request to the dpy to unbind the previous context. 204 */ 205 if (!new || new->isDirect || new->psc->dpy != dpy) { 206 SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None, 207 NULL); 208 gc->currentContextTag = 0; 209 } 210} 211 212static void 213indirect_wait_gl(struct glx_context *gc) 214{ 215 xGLXWaitGLReq *req; 216 Display *dpy = gc->currentDpy; 217 218 /* Flush any pending commands out */ 219 __glXFlushRenderBuffer(gc, gc->pc); 220 221 /* Send the glXWaitGL request */ 222 LockDisplay(dpy); 223 GetReq(GLXWaitGL, req); 224 req->reqType = gc->majorOpcode; 225 req->glxCode = X_GLXWaitGL; 226 req->contextTag = gc->currentContextTag; 227 UnlockDisplay(dpy); 228 SyncHandle(); 229} 230 231static void 232indirect_wait_x(struct glx_context *gc) 233{ 234 xGLXWaitXReq *req; 235 Display *dpy = gc->currentDpy; 236 237 /* Flush any pending commands out */ 238 __glXFlushRenderBuffer(gc, gc->pc); 239 240 LockDisplay(dpy); 241 GetReq(GLXWaitX, req); 242 req->reqType = gc->majorOpcode; 243 req->glxCode = X_GLXWaitX; 244 req->contextTag = gc->currentContextTag; 245 UnlockDisplay(dpy); 246 SyncHandle(); 247} 248 249static const struct glx_context_vtable indirect_context_vtable = { 250 .destroy = indirect_destroy_context, 251 .bind = indirect_bind_context, 252 .unbind = indirect_unbind_context, 253 .wait_gl = indirect_wait_gl, 254 .wait_x = indirect_wait_x, 255}; 256 257_X_HIDDEN struct glx_context * 258indirect_create_context(struct glx_screen *psc, 259 struct glx_config *mode, 260 struct glx_context *shareList, int renderType) 261{ 262 unsigned error = 0; 263 const uint32_t attribs[] = { GLX_RENDER_TYPE, renderType }; 264 265 return indirect_create_context_attribs(psc, mode, shareList, 266 1, attribs, &error); 267} 268 269/** 270 * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new 271 * function called \c __glXAllocateClientState that allocates the memory and 272 * does all the initialization (including the pixel pack / unpack). 273 */ 274_X_HIDDEN struct glx_context * 275indirect_create_context_attribs(struct glx_screen *psc, 276 struct glx_config *mode, 277 struct glx_context *shareList, 278 unsigned num_attribs, 279 const uint32_t *attribs, 280 unsigned *error) 281{ 282 struct glx_context *gc; 283 int bufSize; 284 CARD8 opcode; 285 __GLXattribute *state; 286 int i, renderType = GLX_RGBA_TYPE; 287 uint32_t mask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; 288 uint32_t major = 1; 289 uint32_t minor = 0; 290 291 opcode = __glXSetupForCommand(psc->dpy); 292 if (!opcode) { 293 return NULL; 294 } 295 296 for (i = 0; i < num_attribs; i++) { 297 uint32_t attr = attribs[i*2], val = attribs[i*2 + 1]; 298 299 if (attr == GLX_RENDER_TYPE) 300 renderType = val; 301 if (attr == GLX_CONTEXT_PROFILE_MASK_ARB) 302 mask = val; 303 if (attr == GLX_CONTEXT_MAJOR_VERSION_ARB) 304 major = val; 305 if (attr == GLX_CONTEXT_MINOR_VERSION_ARB) 306 minor = val; 307 } 308 309 /* We have no indirect support for core or ES contexts, and our compat 310 * context support is limited to GL 1.4. 311 */ 312 if (mask != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB || 313 major != 1 || 314 minor > 4) { 315 return NULL; 316 } 317 318 /* We can't share with a direct context */ 319 if (shareList && shareList->isDirect) 320 return NULL; 321 322 /* Allocate our context record */ 323 gc = calloc(1, sizeof *gc); 324 if (!gc) { 325 /* Out of memory */ 326 return NULL; 327 } 328 329 glx_context_init(gc, psc, mode); 330 gc->isDirect = GL_FALSE; 331 gc->vtable = &indirect_context_vtable; 332 state = calloc(1, sizeof(struct __GLXattributeRec)); 333 gc->renderType = renderType; 334 335 if (state == NULL) { 336 /* Out of memory */ 337 free(gc); 338 return NULL; 339 } 340 gc->client_state_private = state; 341 state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false); 342 343 /* 344 ** Create a temporary buffer to hold GLX rendering commands. The size 345 ** of the buffer is selected so that the maximum number of GLX rendering 346 ** commands can fit in a single X packet and still have room in the X 347 ** packet for the GLXRenderReq header. 348 */ 349 350 bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq; 351 gc->buf = malloc(bufSize); 352 if (!gc->buf) { 353 free(gc->client_state_private); 354 free(gc); 355 return NULL; 356 } 357 gc->bufSize = bufSize; 358 359 /* Fill in the new context */ 360 gc->renderMode = GL_RENDER; 361 362 state->storePack.alignment = 4; 363 state->storeUnpack.alignment = 4; 364 365 gc->attributes.stackPointer = &gc->attributes.stack[0]; 366 367 gc->pc = gc->buf; 368 gc->bufEnd = gc->buf + bufSize; 369 gc->isDirect = GL_FALSE; 370 if (__glXDebug) { 371 /* 372 ** Set limit register so that there will be one command per packet 373 */ 374 gc->limit = gc->buf; 375 } 376 else { 377 gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE; 378 } 379 gc->majorOpcode = opcode; 380 381 /* 382 ** Constrain the maximum drawing command size allowed to be 383 ** transferred using the X_GLXRender protocol request. First 384 ** constrain by a software limit, then constrain by the protocol 385 ** limit. 386 */ 387 gc->maxSmallRenderCommandSize = MIN3(bufSize, __GLX_RENDER_CMD_SIZE_LIMIT, 388 __GLX_MAX_RENDER_CMD_SIZE); 389 390 391 return gc; 392} 393 394static const struct glx_screen_vtable indirect_screen_vtable = { 395 .create_context = indirect_create_context, 396 .create_context_attribs = indirect_create_context_attribs, 397 .query_renderer_integer = NULL, 398 .query_renderer_string = NULL, 399}; 400 401_X_HIDDEN struct glx_screen * 402indirect_create_screen(int screen, struct glx_display * priv) 403{ 404 struct glx_screen *psc; 405 406 psc = calloc(1, sizeof *psc); 407 if (psc == NULL) 408 return NULL; 409 410 glx_screen_init(psc, screen, priv); 411 psc->vtable = &indirect_screen_vtable; 412 413 return psc; 414} 415 416#endif 417