| /* |
| * Copyright © 2010 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Soft- |
| * ware"), to deal in the Software without restriction, including without |
| * limitation the rights to use, copy, modify, merge, publish, distribute, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, provided that the above copyright |
| * notice(s) and this permission notice appear in all copies of the Soft- |
| * ware and that both the above copyright notice(s) and this permission |
| * notice appear in supporting documentation. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY |
| * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN |
| * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- |
| * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- |
| * MANCE OF THIS SOFTWARE. |
| * |
| * Except as contained in this notice, the name of a copyright holder shall |
| * not be used in advertising or otherwise to promote the sale, use or |
| * other dealings in this Software without prior written authorization of |
| * the copyright holder. |
| * |
| * Authors: |
| * Kristian Høgsberg (krh@bitplanet.net) |
| */ |
| |
| #include "glapi.h" |
| #include "glxclient.h" |
| |
| extern struct _glapi_table *__glXNewIndirectAPI(void); |
| |
| /* |
| ** All indirect rendering contexts will share the same indirect dispatch table. |
| */ |
| static struct _glapi_table *IndirectAPI = NULL; |
| |
| static void |
| indirect_destroy_context(struct glx_context *gc) |
| { |
| if (!gc->imported && gc->xid) |
| glx_send_destroy_context(gc->psc->dpy, gc->xid); |
| |
| __glXFreeVertexArrayState(gc); |
| |
| if (gc->vendor) |
| XFree((char *) gc->vendor); |
| if (gc->renderer) |
| XFree((char *) gc->renderer); |
| if (gc->version) |
| XFree((char *) gc->version); |
| if (gc->extensions) |
| XFree((char *) gc->extensions); |
| __glFreeAttributeState(gc); |
| XFree((char *) gc->buf); |
| Xfree((char *) gc->client_state_private); |
| XFree((char *) gc); |
| } |
| |
| static Bool |
| SendMakeCurrentRequest(Display * dpy, CARD8 opcode, |
| GLXContextID gc_id, GLXContextTag gc_tag, |
| GLXDrawable draw, GLXDrawable read, |
| xGLXMakeCurrentReply * reply) |
| { |
| Bool ret; |
| |
| LockDisplay(dpy); |
| |
| if (draw == read) { |
| xGLXMakeCurrentReq *req; |
| |
| GetReq(GLXMakeCurrent, req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXMakeCurrent; |
| req->drawable = draw; |
| req->context = gc_id; |
| req->oldContextTag = gc_tag; |
| } |
| else { |
| struct glx_display *priv = __glXInitialize(dpy); |
| |
| /* If the server can support the GLX 1.3 version, we should |
| * perfer that. Not only that, some servers support GLX 1.3 but |
| * not the SGI extension. |
| */ |
| |
| if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { |
| xGLXMakeContextCurrentReq *req; |
| |
| GetReq(GLXMakeContextCurrent, req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXMakeContextCurrent; |
| req->drawable = draw; |
| req->readdrawable = read; |
| req->context = gc_id; |
| req->oldContextTag = gc_tag; |
| } |
| else { |
| xGLXVendorPrivateWithReplyReq *vpreq; |
| xGLXMakeCurrentReadSGIReq *req; |
| |
| GetReqExtra(GLXVendorPrivateWithReply, |
| sz_xGLXMakeCurrentReadSGIReq - |
| sz_xGLXVendorPrivateWithReplyReq, vpreq); |
| req = (xGLXMakeCurrentReadSGIReq *) vpreq; |
| req->reqType = opcode; |
| req->glxCode = X_GLXVendorPrivateWithReply; |
| req->vendorCode = X_GLXvop_MakeCurrentReadSGI; |
| req->drawable = draw; |
| req->readable = read; |
| req->context = gc_id; |
| req->oldContextTag = gc_tag; |
| } |
| } |
| |
| ret = _XReply(dpy, (xReply *) reply, 0, False); |
| |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| |
| return ret; |
| } |
| |
| static int |
| indirect_bind_context(struct glx_context *gc, struct glx_context *old, |
| GLXDrawable draw, GLXDrawable read) |
| { |
| xGLXMakeCurrentReply reply; |
| GLXContextTag tag; |
| __GLXattribute *state; |
| Display *dpy = gc->psc->dpy; |
| int opcode = __glXSetupForCommand(dpy); |
| |
| if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) { |
| tag = old->currentContextTag; |
| old->currentContextTag = 0; |
| } else { |
| tag = 0; |
| } |
| |
| SendMakeCurrentRequest(dpy, opcode, gc->xid, tag, draw, read, &reply); |
| |
| if (!IndirectAPI) |
| IndirectAPI = __glXNewIndirectAPI(); |
| _glapi_set_dispatch(IndirectAPI); |
| |
| gc->currentContextTag = reply.contextTag; |
| state = gc->client_state_private; |
| if (state->array_state == NULL) { |
| glGetString(GL_EXTENSIONS); |
| glGetString(GL_VERSION); |
| __glXInitVertexArrayState(gc); |
| } |
| |
| return Success; |
| } |
| |
| static void |
| indirect_unbind_context(struct glx_context *gc, struct glx_context *new) |
| { |
| Display *dpy = gc->psc->dpy; |
| int opcode = __glXSetupForCommand(dpy); |
| xGLXMakeCurrentReply reply; |
| |
| if (gc == new) |
| return; |
| |
| /* We are either switching to no context, away from a indirect |
| * context to a direct context or from one dpy to another and have |
| * to send a request to the dpy to unbind the previous context. |
| */ |
| if (!new || new->isDirect || new->psc->dpy != dpy) { |
| SendMakeCurrentRequest(dpy, opcode, None, |
| gc->currentContextTag, None, None, &reply); |
| gc->currentContextTag = 0; |
| } |
| } |
| |
| static void |
| indirect_wait_gl(struct glx_context *gc) |
| { |
| xGLXWaitGLReq *req; |
| Display *dpy = gc->currentDpy; |
| |
| /* Flush any pending commands out */ |
| __glXFlushRenderBuffer(gc, gc->pc); |
| |
| /* Send the glXWaitGL request */ |
| LockDisplay(dpy); |
| GetReq(GLXWaitGL, req); |
| req->reqType = gc->majorOpcode; |
| req->glxCode = X_GLXWaitGL; |
| req->contextTag = gc->currentContextTag; |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| } |
| |
| static void |
| indirect_wait_x(struct glx_context *gc) |
| { |
| xGLXWaitXReq *req; |
| Display *dpy = gc->currentDpy; |
| |
| /* Flush any pending commands out */ |
| __glXFlushRenderBuffer(gc, gc->pc); |
| |
| LockDisplay(dpy); |
| GetReq(GLXWaitX, req); |
| req->reqType = gc->majorOpcode; |
| req->glxCode = X_GLXWaitX; |
| req->contextTag = gc->currentContextTag; |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| } |
| |
| static void |
| indirect_use_x_font(struct glx_context *gc, |
| Font font, int first, int count, int listBase) |
| { |
| xGLXUseXFontReq *req; |
| Display *dpy = gc->currentDpy; |
| |
| /* Flush any pending commands out */ |
| __glXFlushRenderBuffer(gc, gc->pc); |
| |
| /* Send the glXUseFont request */ |
| LockDisplay(dpy); |
| GetReq(GLXUseXFont, req); |
| req->reqType = gc->majorOpcode; |
| req->glxCode = X_GLXUseXFont; |
| req->contextTag = gc->currentContextTag; |
| req->font = font; |
| req->first = first; |
| req->count = count; |
| req->listBase = listBase; |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| } |
| |
| static void |
| indirect_bind_tex_image(Display * dpy, |
| GLXDrawable drawable, |
| int buffer, const int *attrib_list) |
| { |
| xGLXVendorPrivateReq *req; |
| struct glx_context *gc = __glXGetCurrentContext(); |
| CARD32 *drawable_ptr; |
| INT32 *buffer_ptr; |
| CARD32 *num_attrib_ptr; |
| CARD32 *attrib_ptr; |
| CARD8 opcode; |
| unsigned int i; |
| |
| i = 0; |
| if (attrib_list) { |
| while (attrib_list[i * 2] != None) |
| i++; |
| } |
| |
| opcode = __glXSetupForCommand(dpy); |
| if (!opcode) |
| return; |
| |
| LockDisplay(dpy); |
| GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXVendorPrivate; |
| req->vendorCode = X_GLXvop_BindTexImageEXT; |
| req->contextTag = gc->currentContextTag; |
| |
| drawable_ptr = (CARD32 *) (req + 1); |
| buffer_ptr = (INT32 *) (drawable_ptr + 1); |
| num_attrib_ptr = (CARD32 *) (buffer_ptr + 1); |
| attrib_ptr = (CARD32 *) (num_attrib_ptr + 1); |
| |
| *drawable_ptr = drawable; |
| *buffer_ptr = buffer; |
| *num_attrib_ptr = (CARD32) i; |
| |
| i = 0; |
| if (attrib_list) { |
| while (attrib_list[i * 2] != None) { |
| *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0]; |
| *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1]; |
| i++; |
| } |
| } |
| |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| } |
| |
| static void |
| indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) |
| { |
| xGLXVendorPrivateReq *req; |
| struct glx_context *gc = __glXGetCurrentContext(); |
| CARD32 *drawable_ptr; |
| INT32 *buffer_ptr; |
| CARD8 opcode; |
| |
| opcode = __glXSetupForCommand(dpy); |
| if (!opcode) |
| return; |
| |
| LockDisplay(dpy); |
| GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXVendorPrivate; |
| req->vendorCode = X_GLXvop_ReleaseTexImageEXT; |
| req->contextTag = gc->currentContextTag; |
| |
| drawable_ptr = (CARD32 *) (req + 1); |
| buffer_ptr = (INT32 *) (drawable_ptr + 1); |
| |
| *drawable_ptr = drawable; |
| *buffer_ptr = buffer; |
| |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| } |
| |
| static const struct glx_context_vtable indirect_context_vtable = { |
| indirect_destroy_context, |
| indirect_bind_context, |
| indirect_unbind_context, |
| indirect_wait_gl, |
| indirect_wait_x, |
| indirect_use_x_font, |
| indirect_bind_tex_image, |
| indirect_release_tex_image, |
| }; |
| |
| /** |
| * \todo Eliminate \c __glXInitVertexArrayState. Replace it with a new |
| * function called \c __glXAllocateClientState that allocates the memory and |
| * does all the initialization (including the pixel pack / unpack). |
| */ |
| _X_HIDDEN struct glx_context * |
| indirect_create_context(struct glx_screen *psc, |
| struct glx_config *mode, |
| struct glx_context *shareList, int renderType) |
| { |
| struct glx_context *gc; |
| int bufSize; |
| CARD8 opcode; |
| __GLXattribute *state; |
| |
| opcode = __glXSetupForCommand(psc->dpy); |
| if (!opcode) { |
| return NULL; |
| } |
| |
| /* Allocate our context record */ |
| gc = Xmalloc(sizeof *gc); |
| if (!gc) { |
| /* Out of memory */ |
| return NULL; |
| } |
| memset(gc, 0, sizeof *gc); |
| |
| glx_context_init(gc, psc, mode); |
| gc->isDirect = GL_FALSE; |
| gc->vtable = &indirect_context_vtable; |
| state = Xmalloc(sizeof(struct __GLXattributeRec)); |
| if (state == NULL) { |
| /* Out of memory */ |
| Xfree(gc); |
| return NULL; |
| } |
| gc->client_state_private = state; |
| memset(gc->client_state_private, 0, sizeof(struct __GLXattributeRec)); |
| state->NoDrawArraysProtocol = (getenv("LIBGL_NO_DRAWARRAYS") != NULL); |
| |
| /* |
| ** Create a temporary buffer to hold GLX rendering commands. The size |
| ** of the buffer is selected so that the maximum number of GLX rendering |
| ** commands can fit in a single X packet and still have room in the X |
| ** packet for the GLXRenderReq header. |
| */ |
| |
| bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq; |
| gc->buf = (GLubyte *) Xmalloc(bufSize); |
| if (!gc->buf) { |
| Xfree(gc->client_state_private); |
| Xfree(gc); |
| return NULL; |
| } |
| gc->bufSize = bufSize; |
| |
| /* Fill in the new context */ |
| gc->renderMode = GL_RENDER; |
| |
| state->storePack.alignment = 4; |
| state->storeUnpack.alignment = 4; |
| |
| gc->attributes.stackPointer = &gc->attributes.stack[0]; |
| |
| /* |
| ** PERFORMANCE NOTE: A mode dependent fill image can speed things up. |
| ** Other code uses the fastImageUnpack bit, but it is never set |
| ** to GL_TRUE. |
| */ |
| gc->fastImageUnpack = GL_FALSE; |
| gc->fillImage = __glFillImage; |
| gc->pc = gc->buf; |
| gc->bufEnd = gc->buf + bufSize; |
| gc->isDirect = GL_FALSE; |
| if (__glXDebug) { |
| /* |
| ** Set limit register so that there will be one command per packet |
| */ |
| gc->limit = gc->buf; |
| } |
| else { |
| gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE; |
| } |
| gc->majorOpcode = opcode; |
| |
| /* |
| ** Constrain the maximum drawing command size allowed to be |
| ** transfered using the X_GLXRender protocol request. First |
| ** constrain by a software limit, then constrain by the protocl |
| ** limit. |
| */ |
| if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) { |
| bufSize = __GLX_RENDER_CMD_SIZE_LIMIT; |
| } |
| if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) { |
| bufSize = __GLX_MAX_RENDER_CMD_SIZE; |
| } |
| gc->maxSmallRenderCommandSize = bufSize; |
| |
| |
| return gc; |
| } |
| |
| struct glx_screen_vtable indirect_screen_vtable = { |
| indirect_create_context |
| }; |
| |
| _X_HIDDEN struct glx_screen * |
| indirect_create_screen(int screen, struct glx_display * priv) |
| { |
| struct glx_screen *psc; |
| |
| psc = Xmalloc(sizeof *psc); |
| if (psc == NULL) |
| return NULL; |
| |
| memset(psc, 0, sizeof *psc); |
| glx_screen_init(psc, screen, priv); |
| psc->vtable = &indirect_screen_vtable; |
| |
| return psc; |
| } |