2010-07-28 21:40:43 +01:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2010-07-29 23:44:26 +01:00
|
|
|
if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy)
|
2010-07-28 21:40:43 +01:00
|
|
|
tag = old->currentContextTag;
|
|
|
|
else
|
|
|
|
tag = None;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|