#include <stdbool.h>
#include "glapi.h"
#include "glxclient.h"
#include "indirect.h"
#include "util/debug.h"
#ifndef GLX_USE_APPLEGL
extern struct _glapi_table *__glXNewIndirectAPI(void);
static struct _glapi_table *IndirectAPI = NULL;
static void
indirect_destroy_context(struct glx_context *gc)
{
__glXFreeVertexArrayState(gc);
free((char *) gc->vendor);
free((char *) gc->renderer);
free((char *) gc->version);
free((char *) gc->extensions);
__glFreeAttributeState(gc);
free((char *) gc->buf);
free((char *) gc->client_state_private);
free((char *) gc);
}
static Bool
SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id,
GLXContextTag gc_tag, GLXDrawable draw,
GLXDrawable read, GLXContextTag *out_tag)
{
xGLXMakeCurrentReply reply;
Bool ret;
int opcode = __glXSetupForCommand(dpy);
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 (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);
if (out_tag)
*out_tag = reply.contextTag;
UnlockDisplay(dpy);
SyncHandle();
return ret;
}
static int
indirect_bind_context(struct glx_context *gc, struct glx_context *old,
GLXDrawable draw, GLXDrawable read)
{
GLXContextTag tag;
Display *dpy = gc->psc->dpy;
Bool sent;
if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) {
tag = old->currentContextTag;
old->currentContextTag = 0;
} else {
tag = 0;
}
sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read,
&gc->currentContextTag);
if (sent) {
if (!IndirectAPI)
IndirectAPI = __glXNewIndirectAPI();
_glapi_set_dispatch(IndirectAPI);
__GLXattribute *state = gc->client_state_private;
if (state && state->array_state == NULL) {
gc->currentDpy = gc->psc->dpy;
__glXSetCurrentContext(gc);
__indirect_glGetString(GL_EXTENSIONS);
__indirect_glGetString(GL_VERSION);
__glXInitVertexArrayState(gc);
}
}
return !sent;
}
static void
indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
{
Display *dpy = gc->psc->dpy;
if (gc == new)
return;
if (!new || new->isDirect || new->psc->dpy != dpy) {
SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None,
NULL);
gc->currentContextTag = 0;
}
}
static void
indirect_wait_gl(struct glx_context *gc)
{
xGLXWaitGLReq *req;
Display *dpy = gc->currentDpy;
__glXFlushRenderBuffer(gc, gc->pc);
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;
__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 const struct glx_context_vtable indirect_context_vtable = {
.destroy = indirect_destroy_context,
.bind = indirect_bind_context,
.unbind = indirect_unbind_context,
.wait_gl = indirect_wait_gl,
.wait_x = indirect_wait_x,
};
_X_HIDDEN struct glx_context *
indirect_create_context(struct glx_screen *psc,
struct glx_config *mode,
struct glx_context *shareList, int renderType)
{
unsigned error = 0;
const uint32_t attribs[] = { GLX_RENDER_TYPE, renderType };
return indirect_create_context_attribs(psc, mode, shareList,
1, attribs, &error);
}
_X_HIDDEN struct glx_context *
indirect_create_context_attribs(struct glx_screen *psc,
struct glx_config *mode,
struct glx_context *shareList,
unsigned num_attribs,
const uint32_t *attribs,
unsigned *error)
{
struct glx_context *gc;
int bufSize;
CARD8 opcode;
__GLXattribute *state;
int i, renderType = GLX_RGBA_TYPE;
uint32_t mask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
uint32_t major = 1;
uint32_t minor = 0;
opcode = __glXSetupForCommand(psc->dpy);
if (!opcode) {
return NULL;
}
for (i = 0; i < num_attribs; i++) {
uint32_t attr = attribs[i*2], val = attribs[i*2 + 1];
if (attr == GLX_RENDER_TYPE)
renderType = val;
if (attr == GLX_CONTEXT_PROFILE_MASK_ARB)
mask = val;
if (attr == GLX_CONTEXT_MAJOR_VERSION_ARB)
major = val;
if (attr == GLX_CONTEXT_MINOR_VERSION_ARB)
minor = val;
}
if (mask != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ||
major != 1 ||
minor > 4) {
return NULL;
}
gc = calloc(1, sizeof *gc);
if (!gc) {
return NULL;
}
glx_context_init(gc, psc, mode);
gc->isDirect = GL_FALSE;
gc->vtable = &indirect_context_vtable;
state = calloc(1, sizeof(struct __GLXattributeRec));
gc->renderType = renderType;
if (state == NULL) {
free(gc);
return NULL;
}
gc->client_state_private = state;
state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
gc->buf = malloc(bufSize);
if (!gc->buf) {
free(gc->client_state_private);
free(gc);
return NULL;
}
gc->bufSize = bufSize;
gc->renderMode = GL_RENDER;
state->storePack.alignment = 4;
state->storeUnpack.alignment = 4;
gc->attributes.stackPointer = &gc->attributes.stack[0];
gc->pc = gc->buf;
gc->bufEnd = gc->buf + bufSize;
gc->isDirect = GL_FALSE;
if (__glXDebug) {
gc->limit = gc->buf;
}
else {
gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
}
gc->majorOpcode = opcode;
gc->maxSmallRenderCommandSize = MIN3(bufSize, __GLX_RENDER_CMD_SIZE_LIMIT,
__GLX_MAX_RENDER_CMD_SIZE);
return gc;
}
static const struct glx_screen_vtable indirect_screen_vtable = {
.create_context = indirect_create_context,
.create_context_attribs = indirect_create_context_attribs,
.query_renderer_integer = NULL,
.query_renderer_string = NULL,
};
_X_HIDDEN struct glx_screen *
indirect_create_screen(int screen, struct glx_display * priv)
{
struct glx_screen *psc;
psc = calloc(1, sizeof *psc);
if (psc == NULL)
return NULL;
glx_screen_init(psc, screen, priv);
psc->vtable = &indirect_screen_vtable;
return psc;
}
#endif