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