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 Hgsberg (krh (at) bitplanet.net) 31 */ 32 33 #include "glapi.h" 34 #include "glxclient.h" 35 36 #ifndef GLX_USE_APPLEGL 37 38 extern struct _glapi_table *__glXNewIndirectAPI(void); 39 40 /* 41 ** All indirect rendering contexts will share the same indirect dispatch table. 42 */ 43 static struct _glapi_table *IndirectAPI = NULL; 44 45 static void 46 indirect_destroy_context(struct glx_context *gc) 47 { 48 __glXFreeVertexArrayState(gc); 49 50 free((char *) gc->vendor); 51 free((char *) gc->renderer); 52 free((char *) gc->version); 53 free((char *) gc->extensions); 54 __glFreeAttributeState(gc); 55 free((char *) gc->buf); 56 free((char *) gc->client_state_private); 57 free((char *) gc); 58 } 59 60 static Bool 61 SendMakeCurrentRequest(Display * dpy, CARD8 opcode, 62 GLXContextID gc_id, GLXContextTag gc_tag, 63 GLXDrawable draw, GLXDrawable read, 64 GLXContextTag *out_tag) 65 { 66 xGLXMakeCurrentReply reply; 67 Bool ret; 68 69 LockDisplay(dpy); 70 71 if (draw == read) { 72 xGLXMakeCurrentReq *req; 73 74 GetReq(GLXMakeCurrent, req); 75 req->reqType = opcode; 76 req->glxCode = X_GLXMakeCurrent; 77 req->drawable = draw; 78 req->context = gc_id; 79 req->oldContextTag = gc_tag; 80 } 81 else { 82 struct glx_display *priv = __glXInitialize(dpy); 83 84 /* If the server can support the GLX 1.3 version, we should 85 * perfer that. Not only that, some servers support GLX 1.3 but 86 * not the SGI extension. 87 */ 88 89 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 90 xGLXMakeContextCurrentReq *req; 91 92 GetReq(GLXMakeContextCurrent, req); 93 req->reqType = opcode; 94 req->glxCode = X_GLXMakeContextCurrent; 95 req->drawable = draw; 96 req->readdrawable = read; 97 req->context = gc_id; 98 req->oldContextTag = gc_tag; 99 } 100 else { 101 xGLXVendorPrivateWithReplyReq *vpreq; 102 xGLXMakeCurrentReadSGIReq *req; 103 104 GetReqExtra(GLXVendorPrivateWithReply, 105 sz_xGLXMakeCurrentReadSGIReq - 106 sz_xGLXVendorPrivateWithReplyReq, vpreq); 107 req = (xGLXMakeCurrentReadSGIReq *) vpreq; 108 req->reqType = opcode; 109 req->glxCode = X_GLXVendorPrivateWithReply; 110 req->vendorCode = X_GLXvop_MakeCurrentReadSGI; 111 req->drawable = draw; 112 req->readable = read; 113 req->context = gc_id; 114 req->oldContextTag = gc_tag; 115 } 116 } 117 118 ret = _XReply(dpy, (xReply *) &reply, 0, False); 119 120 if (out_tag) 121 *out_tag = reply.contextTag; 122 123 UnlockDisplay(dpy); 124 SyncHandle(); 125 126 return ret; 127 } 128 129 static int 130 indirect_bind_context(struct glx_context *gc, struct glx_context *old, 131 GLXDrawable draw, GLXDrawable read) 132 { 133 GLXContextTag tag; 134 Display *dpy = gc->psc->dpy; 135 int opcode = __glXSetupForCommand(dpy); 136 Bool sent; 137 138 if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) { 139 tag = old->currentContextTag; 140 old->currentContextTag = 0; 141 } else { 142 tag = 0; 143 } 144 145 sent = SendMakeCurrentRequest(dpy, opcode, gc->xid, tag, draw, read, 146 &gc->currentContextTag); 147 148 if (!IndirectAPI) 149 IndirectAPI = __glXNewIndirectAPI(); 150 _glapi_set_dispatch(IndirectAPI); 151 152 return !sent; 153 } 154 155 static void 156 indirect_unbind_context(struct glx_context *gc, struct glx_context *new) 157 { 158 Display *dpy = gc->psc->dpy; 159 int opcode = __glXSetupForCommand(dpy); 160 161 if (gc == new) 162 return; 163 164 /* We are either switching to no context, away from an indirect 165 * context to a direct context or from one dpy to another and have 166 * to send a request to the dpy to unbind the previous context. 167 */ 168 if (!new || new->isDirect || new->psc->dpy != dpy) { 169 SendMakeCurrentRequest(dpy, opcode, None, 170 gc->currentContextTag, None, None, NULL); 171 gc->currentContextTag = 0; 172 } 173 } 174 175 static void 176 indirect_wait_gl(struct glx_context *gc) 177 { 178 xGLXWaitGLReq *req; 179 Display *dpy = gc->currentDpy; 180 181 /* Flush any pending commands out */ 182 __glXFlushRenderBuffer(gc, gc->pc); 183 184 /* Send the glXWaitGL request */ 185 LockDisplay(dpy); 186 GetReq(GLXWaitGL, req); 187 req->reqType = gc->majorOpcode; 188 req->glxCode = X_GLXWaitGL; 189 req->contextTag = gc->currentContextTag; 190 UnlockDisplay(dpy); 191 SyncHandle(); 192 } 193 194 static void 195 indirect_wait_x(struct glx_context *gc) 196 { 197 xGLXWaitXReq *req; 198 Display *dpy = gc->currentDpy; 199 200 /* Flush any pending commands out */ 201 __glXFlushRenderBuffer(gc, gc->pc); 202 203 LockDisplay(dpy); 204 GetReq(GLXWaitX, req); 205 req->reqType = gc->majorOpcode; 206 req->glxCode = X_GLXWaitX; 207 req->contextTag = gc->currentContextTag; 208 UnlockDisplay(dpy); 209 SyncHandle(); 210 } 211 212 static void 213 indirect_use_x_font(struct glx_context *gc, 214 Font font, int first, int count, int listBase) 215 { 216 xGLXUseXFontReq *req; 217 Display *dpy = gc->currentDpy; 218 219 /* Flush any pending commands out */ 220 __glXFlushRenderBuffer(gc, gc->pc); 221 222 /* Send the glXUseFont request */ 223 LockDisplay(dpy); 224 GetReq(GLXUseXFont, req); 225 req->reqType = gc->majorOpcode; 226 req->glxCode = X_GLXUseXFont; 227 req->contextTag = gc->currentContextTag; 228 req->font = font; 229 req->first = first; 230 req->count = count; 231 req->listBase = listBase; 232 UnlockDisplay(dpy); 233 SyncHandle(); 234 } 235 236 static void 237 indirect_bind_tex_image(Display * dpy, 238 GLXDrawable drawable, 239 int buffer, const int *attrib_list) 240 { 241 xGLXVendorPrivateReq *req; 242 struct glx_context *gc = __glXGetCurrentContext(); 243 CARD32 *drawable_ptr; 244 INT32 *buffer_ptr; 245 CARD32 *num_attrib_ptr; 246 CARD32 *attrib_ptr; 247 CARD8 opcode; 248 unsigned int i; 249 250 i = 0; 251 if (attrib_list) { 252 while (attrib_list[i * 2] != None) 253 i++; 254 } 255 256 opcode = __glXSetupForCommand(dpy); 257 if (!opcode) 258 return; 259 260 LockDisplay(dpy); 261 GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req); 262 req->reqType = opcode; 263 req->glxCode = X_GLXVendorPrivate; 264 req->vendorCode = X_GLXvop_BindTexImageEXT; 265 req->contextTag = gc->currentContextTag; 266 267 drawable_ptr = (CARD32 *) (req + 1); 268 buffer_ptr = (INT32 *) (drawable_ptr + 1); 269 num_attrib_ptr = (CARD32 *) (buffer_ptr + 1); 270 attrib_ptr = (CARD32 *) (num_attrib_ptr + 1); 271 272 *drawable_ptr = drawable; 273 *buffer_ptr = buffer; 274 *num_attrib_ptr = (CARD32) i; 275 276 i = 0; 277 if (attrib_list) { 278 while (attrib_list[i * 2] != None) { 279 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0]; 280 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1]; 281 i++; 282 } 283 } 284 285 UnlockDisplay(dpy); 286 SyncHandle(); 287 } 288 289 static void 290 indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 291 { 292 xGLXVendorPrivateReq *req; 293 struct glx_context *gc = __glXGetCurrentContext(); 294 CARD32 *drawable_ptr; 295 INT32 *buffer_ptr; 296 CARD8 opcode; 297 298 opcode = __glXSetupForCommand(dpy); 299 if (!opcode) 300 return; 301 302 LockDisplay(dpy); 303 GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req); 304 req->reqType = opcode; 305 req->glxCode = X_GLXVendorPrivate; 306 req->vendorCode = X_GLXvop_ReleaseTexImageEXT; 307 req->contextTag = gc->currentContextTag; 308 309 drawable_ptr = (CARD32 *) (req + 1); 310 buffer_ptr = (INT32 *) (drawable_ptr + 1); 311 312 *drawable_ptr = drawable; 313 *buffer_ptr = buffer; 314 315 UnlockDisplay(dpy); 316 SyncHandle(); 317 } 318 319 static const struct glx_context_vtable indirect_context_vtable = { 320 .destroy = indirect_destroy_context, 321 .bind = indirect_bind_context, 322 .unbind = indirect_unbind_context, 323 .wait_gl = indirect_wait_gl, 324 .wait_x = indirect_wait_x, 325 .use_x_font = indirect_use_x_font, 326 .bind_tex_image = indirect_bind_tex_image, 327 .release_tex_image = indirect_release_tex_image, 328 .get_proc_address = NULL, 329 }; 330 331 /** 332 * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new 333 * function called \c __glXAllocateClientState that allocates the memory and 334 * does all the initialization (including the pixel pack / unpack). 335 * 336 * \note 337 * This function is \b not the place to validate the context creation 338 * parameters. It is just the allocator for the \c glx_context. 339 */ 340 _X_HIDDEN struct glx_context * 341 indirect_create_context(struct glx_screen *psc, 342 struct glx_config *mode, 343 struct glx_context *shareList, int renderType) 344 { 345 struct glx_context *gc; 346 int bufSize; 347 CARD8 opcode; 348 __GLXattribute *state; 349 350 opcode = __glXSetupForCommand(psc->dpy); 351 if (!opcode) { 352 return NULL; 353 } 354 355 /* Allocate our context record */ 356 gc = calloc(1, sizeof *gc); 357 if (!gc) { 358 /* Out of memory */ 359 return NULL; 360 } 361 362 glx_context_init(gc, psc, mode); 363 gc->isDirect = GL_FALSE; 364 gc->vtable = &indirect_context_vtable; 365 state = calloc(1, sizeof(struct __GLXattributeRec)); 366 gc->renderType = renderType; 367 368 if (state == NULL) { 369 /* Out of memory */ 370 free(gc); 371 return NULL; 372 } 373 gc->client_state_private = state; 374 state->NoDrawArraysProtocol = (getenv("LIBGL_NO_DRAWARRAYS") != NULL); 375 376 /* 377 ** Create a temporary buffer to hold GLX rendering commands. The size 378 ** of the buffer is selected so that the maximum number of GLX rendering 379 ** commands can fit in a single X packet and still have room in the X 380 ** packet for the GLXRenderReq header. 381 */ 382 383 bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq; 384 gc->buf = malloc(bufSize); 385 if (!gc->buf) { 386 free(gc->client_state_private); 387 free(gc); 388 return NULL; 389 } 390 gc->bufSize = bufSize; 391 392 /* Fill in the new context */ 393 gc->renderMode = GL_RENDER; 394 395 state->storePack.alignment = 4; 396 state->storeUnpack.alignment = 4; 397 398 gc->attributes.stackPointer = &gc->attributes.stack[0]; 399 400 /* 401 ** PERFORMANCE NOTE: A mode dependent fill image can speed things up. 402 */ 403 gc->fillImage = __glFillImage; 404 gc->pc = gc->buf; 405 gc->bufEnd = gc->buf + bufSize; 406 gc->isDirect = GL_FALSE; 407 if (__glXDebug) { 408 /* 409 ** Set limit register so that there will be one command per packet 410 */ 411 gc->limit = gc->buf; 412 } 413 else { 414 gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE; 415 } 416 gc->majorOpcode = opcode; 417 418 /* 419 ** Constrain the maximum drawing command size allowed to be 420 ** transfered using the X_GLXRender protocol request. First 421 ** constrain by a software limit, then constrain by the protocl 422 ** limit. 423 */ 424 if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) { 425 bufSize = __GLX_RENDER_CMD_SIZE_LIMIT; 426 } 427 if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) { 428 bufSize = __GLX_MAX_RENDER_CMD_SIZE; 429 } 430 gc->maxSmallRenderCommandSize = bufSize; 431 432 433 return gc; 434 } 435 436 _X_HIDDEN struct glx_context * 437 indirect_create_context_attribs(struct glx_screen *base, 438 struct glx_config *config_base, 439 struct glx_context *shareList, 440 unsigned num_attribs, 441 const uint32_t *attribs, 442 unsigned *error) 443 { 444 int renderType = GLX_RGBA_TYPE; 445 unsigned i; 446 447 /* The error parameter is only used on the server so that correct GLX 448 * protocol errors can be generated. On the client, it can be ignored. 449 */ 450 (void) error; 451 452 /* All of the attribute validation for indirect contexts is handled on the 453 * server, so there's not much to do here. Still, we need to parse the 454 * attributes to correctly set renderType. 455 */ 456 for (i = 0; i < num_attribs; i++) { 457 if (attribs[i * 2] == GLX_RENDER_TYPE) 458 renderType = attribs[i * 2 + 1]; 459 } 460 461 return indirect_create_context(base, config_base, shareList, renderType); 462 } 463 464 static const struct glx_screen_vtable indirect_screen_vtable = { 465 .create_context = indirect_create_context, 466 .create_context_attribs = indirect_create_context_attribs, 467 .query_renderer_integer = NULL, 468 .query_renderer_string = NULL, 469 }; 470 471 _X_HIDDEN struct glx_screen * 472 indirect_create_screen(int screen, struct glx_display * priv) 473 { 474 struct glx_screen *psc; 475 476 psc = calloc(1, sizeof *psc); 477 if (psc == NULL) 478 return NULL; 479 480 glx_screen_init(psc, screen, priv); 481 psc->vtable = &indirect_screen_vtable; 482 483 return psc; 484 } 485 486 #endif 487