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 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 50indirect_destroy_context(struct glx_context *gc) 51{ 52 __glXFreeVertexArrayState(gc); 53 54 free((char *) gc->vendor); 55 free((char *) gc->renderer); 56 free((char *) gc->version); 57 free((char *) gc->extensions); 58 __glFreeAttributeState(gc); 59 free((char *) gc->buf); 60 free((char *) gc->client_state_private); 61 free((char *) gc); 62} 63 64static Bool 65SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id, 66 GLXContextTag gc_tag, GLXDrawable draw, 67 GLXDrawable read, GLXContextTag *out_tag) 68{ 69 xGLXMakeCurrentReply reply; 70 Bool ret; 71 int opcode = __glXSetupForCommand(dpy); 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 if (out_tag) 125 *out_tag = reply.contextTag; 126 127 UnlockDisplay(dpy); 128 SyncHandle(); 129 130 return ret; 131} 132 133static int 134indirect_bind_context(struct glx_context *gc, struct glx_context *old, 135 GLXDrawable draw, GLXDrawable read) 136{ 137 GLXContextTag tag; 138 Display *dpy = gc->psc->dpy; 139 Bool sent; 140 141 if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) { 142 tag = old->currentContextTag; 143 old->currentContextTag = 0; 144 } else { 145 tag = 0; 146 } 147 148 sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read, 149 &gc->currentContextTag); 150 151 if (!IndirectAPI) 152 IndirectAPI = __glXNewIndirectAPI(); 153 _glapi_set_dispatch(IndirectAPI); 154 155 return !sent; 156} 157 158static void 159indirect_unbind_context(struct glx_context *gc, struct glx_context *new) 160{ 161 Display *dpy = gc->psc->dpy; 162 163 if (gc == new) 164 return; 165 166 /* We are either switching to no context, away from an indirect 167 * context to a direct context or from one dpy to another and have 168 * to send a request to the dpy to unbind the previous context. 169 */ 170 if (!new || new->isDirect || new->psc->dpy != dpy) { 171 SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None, 172 NULL); 173 gc->currentContextTag = 0; 174 } 175} 176 177static void 178indirect_wait_gl(struct glx_context *gc) 179{ 180 xGLXWaitGLReq *req; 181 Display *dpy = gc->currentDpy; 182 183 /* Flush any pending commands out */ 184 __glXFlushRenderBuffer(gc, gc->pc); 185 186 /* Send the glXWaitGL request */ 187 LockDisplay(dpy); 188 GetReq(GLXWaitGL, req); 189 req->reqType = gc->majorOpcode; 190 req->glxCode = X_GLXWaitGL; 191 req->contextTag = gc->currentContextTag; 192 UnlockDisplay(dpy); 193 SyncHandle(); 194} 195 196static void 197indirect_wait_x(struct glx_context *gc) 198{ 199 xGLXWaitXReq *req; 200 Display *dpy = gc->currentDpy; 201 202 /* Flush any pending commands out */ 203 __glXFlushRenderBuffer(gc, gc->pc); 204 205 LockDisplay(dpy); 206 GetReq(GLXWaitX, req); 207 req->reqType = gc->majorOpcode; 208 req->glxCode = X_GLXWaitX; 209 req->contextTag = gc->currentContextTag; 210 UnlockDisplay(dpy); 211 SyncHandle(); 212} 213 214static void 215indirect_use_x_font(struct glx_context *gc, 216 Font font, int first, int count, int listBase) 217{ 218 xGLXUseXFontReq *req; 219 Display *dpy = gc->currentDpy; 220 221 /* Flush any pending commands out */ 222 __glXFlushRenderBuffer(gc, gc->pc); 223 224 /* Send the glXUseFont request */ 225 LockDisplay(dpy); 226 GetReq(GLXUseXFont, req); 227 req->reqType = gc->majorOpcode; 228 req->glxCode = X_GLXUseXFont; 229 req->contextTag = gc->currentContextTag; 230 req->font = font; 231 req->first = first; 232 req->count = count; 233 req->listBase = listBase; 234 UnlockDisplay(dpy); 235 SyncHandle(); 236} 237 238static void 239indirect_bind_tex_image(Display * dpy, 240 GLXDrawable drawable, 241 int buffer, const int *attrib_list) 242{ 243 xGLXVendorPrivateReq *req; 244 struct glx_context *gc = __glXGetCurrentContext(); 245 CARD32 *drawable_ptr; 246 INT32 *buffer_ptr; 247 CARD32 *num_attrib_ptr; 248 CARD32 *attrib_ptr; 249 CARD8 opcode; 250 unsigned int i; 251 252 i = 0; 253 if (attrib_list) { 254 while (attrib_list[i * 2] != None) 255 i++; 256 } 257 258 opcode = __glXSetupForCommand(dpy); 259 if (!opcode) 260 return; 261 262 LockDisplay(dpy); 263 GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req); 264 req->reqType = opcode; 265 req->glxCode = X_GLXVendorPrivate; 266 req->vendorCode = X_GLXvop_BindTexImageEXT; 267 req->contextTag = gc->currentContextTag; 268 269 drawable_ptr = (CARD32 *) (req + 1); 270 buffer_ptr = (INT32 *) (drawable_ptr + 1); 271 num_attrib_ptr = (CARD32 *) (buffer_ptr + 1); 272 attrib_ptr = (CARD32 *) (num_attrib_ptr + 1); 273 274 *drawable_ptr = drawable; 275 *buffer_ptr = buffer; 276 *num_attrib_ptr = (CARD32) i; 277 278 i = 0; 279 if (attrib_list) { 280 while (attrib_list[i * 2] != None) { 281 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0]; 282 *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1]; 283 i++; 284 } 285 } 286 287 UnlockDisplay(dpy); 288 SyncHandle(); 289} 290 291static void 292indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 293{ 294 xGLXVendorPrivateReq *req; 295 struct glx_context *gc = __glXGetCurrentContext(); 296 CARD32 *drawable_ptr; 297 INT32 *buffer_ptr; 298 CARD8 opcode; 299 300 opcode = __glXSetupForCommand(dpy); 301 if (!opcode) 302 return; 303 304 LockDisplay(dpy); 305 GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req); 306 req->reqType = opcode; 307 req->glxCode = X_GLXVendorPrivate; 308 req->vendorCode = X_GLXvop_ReleaseTexImageEXT; 309 req->contextTag = gc->currentContextTag; 310 311 drawable_ptr = (CARD32 *) (req + 1); 312 buffer_ptr = (INT32 *) (drawable_ptr + 1); 313 314 *drawable_ptr = drawable; 315 *buffer_ptr = buffer; 316 317 UnlockDisplay(dpy); 318 SyncHandle(); 319} 320 321static const struct glx_context_vtable indirect_context_vtable = { 322 .destroy = indirect_destroy_context, 323 .bind = indirect_bind_context, 324 .unbind = indirect_unbind_context, 325 .wait_gl = indirect_wait_gl, 326 .wait_x = indirect_wait_x, 327 .use_x_font = indirect_use_x_font, 328 .bind_tex_image = indirect_bind_tex_image, 329 .release_tex_image = indirect_release_tex_image, 330 .get_proc_address = NULL, 331}; 332 333/** 334 * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new 335 * function called \c __glXAllocateClientState that allocates the memory and 336 * does all the initialization (including the pixel pack / unpack). 337 * 338 * \note 339 * This function is \b not the place to validate the context creation 340 * parameters. It is just the allocator for the \c glx_context. 341 */ 342_X_HIDDEN struct glx_context * 343indirect_create_context(struct glx_screen *psc, 344 struct glx_config *mode, 345 struct glx_context *shareList, int renderType) 346{ 347 struct glx_context *gc; 348 int bufSize; 349 CARD8 opcode; 350 __GLXattribute *state; 351 352 opcode = __glXSetupForCommand(psc->dpy); 353 if (!opcode) { 354 return NULL; 355 } 356 357 /* Allocate our context record */ 358 gc = calloc(1, sizeof *gc); 359 if (!gc) { 360 /* Out of memory */ 361 return NULL; 362 } 363 364 glx_context_init(gc, psc, mode); 365 gc->isDirect = GL_FALSE; 366 gc->vtable = &indirect_context_vtable; 367 state = calloc(1, sizeof(struct __GLXattributeRec)); 368 gc->renderType = renderType; 369 370 if (state == NULL) { 371 /* Out of memory */ 372 free(gc); 373 return NULL; 374 } 375 gc->client_state_private = state; 376 state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false); 377 378 /* 379 ** Create a temporary buffer to hold GLX rendering commands. The size 380 ** of the buffer is selected so that the maximum number of GLX rendering 381 ** commands can fit in a single X packet and still have room in the X 382 ** packet for the GLXRenderReq header. 383 */ 384 385 bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq; 386 gc->buf = malloc(bufSize); 387 if (!gc->buf) { 388 free(gc->client_state_private); 389 free(gc); 390 return NULL; 391 } 392 gc->bufSize = bufSize; 393 394 /* Fill in the new context */ 395 gc->renderMode = GL_RENDER; 396 397 state->storePack.alignment = 4; 398 state->storeUnpack.alignment = 4; 399 400 gc->attributes.stackPointer = &gc->attributes.stack[0]; 401 402 /* 403 ** PERFORMANCE NOTE: A mode dependent fill image can speed things up. 404 */ 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 438_X_HIDDEN struct glx_context * 439indirect_create_context_attribs(struct glx_screen *base, 440 struct glx_config *config_base, 441 struct glx_context *shareList, 442 unsigned num_attribs, 443 const uint32_t *attribs, 444 unsigned *error) 445{ 446 int renderType = GLX_RGBA_TYPE; 447 unsigned i; 448 449 /* The error parameter is only used on the server so that correct GLX 450 * protocol errors can be generated. On the client, it can be ignored. 451 */ 452 (void) error; 453 454 /* All of the attribute validation for indirect contexts is handled on the 455 * server, so there's not much to do here. Still, we need to parse the 456 * attributes to correctly set renderType. 457 */ 458 for (i = 0; i < num_attribs; i++) { 459 if (attribs[i * 2] == GLX_RENDER_TYPE) 460 renderType = attribs[i * 2 + 1]; 461 } 462 463 return indirect_create_context(base, config_base, shareList, renderType); 464} 465 466static const struct glx_screen_vtable indirect_screen_vtable = { 467 .create_context = indirect_create_context, 468 .create_context_attribs = indirect_create_context_attribs, 469 .query_renderer_integer = NULL, 470 .query_renderer_string = NULL, 471}; 472 473_X_HIDDEN struct glx_screen * 474indirect_create_screen(int screen, struct glx_display * priv) 475{ 476 struct glx_screen *psc; 477 478 psc = calloc(1, sizeof *psc); 479 if (psc == NULL) 480 return NULL; 481 482 glx_screen_init(psc, screen, priv); 483 psc->vtable = &indirect_screen_vtable; 484 485 return psc; 486} 487 488#endif 489