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