--- /dev/null
+// Prototypes for auto-generating forwarders for OpenGL functions
+DEF_GLX_PROTO(void, glClearIndex,(GLfloat c), c)
+DEF_GLX_PROTO(void, glClearColor,(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glClear,(GLbitfield mask), mask)
+DEF_GLX_PROTO(void, glIndexMask,(GLuint mask), mask)
+DEF_GLX_PROTO(void, glColorMask,(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glAlphaFunc,(GLenum func, GLclampf ref), func, ref)
+DEF_GLX_PROTO(void, glBlendFunc,(GLenum sfactor, GLenum dfactor), sfactor, dfactor)
+DEF_GLX_PROTO(void, glLogicOp,(GLenum opcode), opcode)
+DEF_GLX_PROTO(void, glCullFace,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glFrontFace,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glPointSize,(GLfloat size), size)
+DEF_GLX_PROTO(void, glLineWidth,(GLfloat width), width)
+DEF_GLX_PROTO(void, glLineStipple,(GLint factor, GLushort pattern), factor, pattern)
+DEF_GLX_PROTO(void, glPolygonMode,(GLenum face, GLenum mode), face, mode)
+DEF_GLX_PROTO(void, glPolygonOffset,(GLfloat factor, GLfloat units), factor, units)
+DEF_GLX_PROTO(void, glPolygonStipple,(const GLubyte *mask), mask)
+DEF_GLX_PROTO(void, glGetPolygonStipple,(GLubyte *mask), mask)
+DEF_GLX_PROTO(void, glEdgeFlag,(GLboolean flag), flag)
+DEF_GLX_PROTO(void, glEdgeFlagv,(const GLboolean *flag), flag)
+DEF_GLX_PROTO(void, glScissor,(GLint x, GLint y, GLsizei width, GLsizei height), x, y, width, height)
+DEF_GLX_PROTO(void, glClipPlane,(GLenum plane, const GLdouble *equation), plane, equation)
+DEF_GLX_PROTO(void, glGetClipPlane,(GLenum plane, GLdouble *equation), plane, equation)
+DEF_GLX_PROTO(void, glDrawBuffer,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glReadBuffer,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glEnable,(GLenum cap), cap)
+DEF_GLX_PROTO(void, glDisable,(GLenum cap), cap)
+DEF_GLX_PROTO(GLboolean, glIsEnabled,(GLenum cap), cap)
+DEF_GLX_PROTO(void, glEnableClientState,(GLenum cap), cap)
+DEF_GLX_PROTO(void, glDisableClientState,(GLenum cap), cap)
+DEF_GLX_PROTO(void, glGetBooleanv,(GLenum pname, GLboolean *params), pname, params)
+DEF_GLX_PROTO(void, glGetDoublev,(GLenum pname, GLdouble *params), pname, params)
+DEF_GLX_PROTO(void, glGetFloatv,(GLenum pname, GLfloat *params), pname, params)
+DEF_GLX_PROTO(void, glGetIntegerv,(GLenum pname, GLint *params), pname, params)
+DEF_GLX_PROTO(void, glPushAttrib,(GLbitfield mask), mask)
+DEF_GLX_PROTO(void, glPopAttrib,(void))
+DEF_GLX_PROTO(void, glPushClientAttrib,(GLbitfield mask), mask)
+DEF_GLX_PROTO(void, glPopClientAttrib,(void))
+DEF_GLX_PROTO(GLint, glRenderMode,(GLenum mode), mode)
+DEF_GLX_PROTO(GLenum, glGetError,(void))
+DEF_GLX_PROTO(const GLubyte *, glGetString,(GLenum name), name)
+DEF_GLX_PROTO(void, glFinish,(void))
+DEF_GLX_PROTO(void, glFlush,(void))
+DEF_GLX_PROTO(void, glHint,(GLenum target, GLenum mode), target, mode)
+DEF_GLX_PROTO(void, glClearDepth,(GLclampd depth), depth)
+DEF_GLX_PROTO(void, glDepthFunc,(GLenum func), func)
+DEF_GLX_PROTO(void, glDepthMask,(GLboolean flag), flag)
+DEF_GLX_PROTO(void, glDepthRange,(GLclampd near_val, GLclampd far_val), near_val, far_val)
+DEF_GLX_PROTO(void, glClearAccum,(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glAccum,(GLenum op, GLfloat value), op, value)
+DEF_GLX_PROTO(void, glMatrixMode,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glOrtho,(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val), left, right, bottom, top, near_val, far_val)
+DEF_GLX_PROTO(void, glFrustum,(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val), left, right, bottom, top, near_val, far_val)
+DEF_GLX_PROTO(void, glViewport,(GLint x, GLint y, GLsizei width, GLsizei height), x, y, width, height)
+DEF_GLX_PROTO(void, glPushMatrix,(void))
+DEF_GLX_PROTO(void, glPopMatrix,(void))
+DEF_GLX_PROTO(void, glLoadIdentity,(void))
+DEF_GLX_PROTO(void, glLoadMatrixd,(const GLdouble *m), m)
+DEF_GLX_PROTO(void, glLoadMatrixf,(const GLfloat *m), m)
+DEF_GLX_PROTO(void, glMultMatrixd,(const GLdouble *m), m)
+DEF_GLX_PROTO(void, glMultMatrixf,(const GLfloat *m), m)
+DEF_GLX_PROTO(void, glRotated,(GLdouble angle, GLdouble x, GLdouble y, GLdouble z), angle, x, y, z)
+DEF_GLX_PROTO(void, glRotatef,(GLfloat angle, GLfloat x, GLfloat y, GLfloat z), angle, x, y, z)
+DEF_GLX_PROTO(void, glScaled,(GLdouble x, GLdouble y, GLdouble z), x, y, z)
+DEF_GLX_PROTO(void, glScalef,(GLfloat x, GLfloat y, GLfloat z), x, y, z)
+DEF_GLX_PROTO(void, glTranslated,(GLdouble x, GLdouble y, GLdouble z), x, y, z)
+DEF_GLX_PROTO(void, glTranslatef,(GLfloat x, GLfloat y, GLfloat z), x, y, z)
+DEF_GLX_PROTO(GLboolean, glIsList,(GLuint list), list)
+DEF_GLX_PROTO(void, glDeleteLists,(GLuint list, GLsizei range), list, range)
+DEF_GLX_PROTO(GLuint, glGenLists,(GLsizei range), range)
+DEF_GLX_PROTO(void, glNewList,(GLuint list, GLenum mode), list, mode)
+DEF_GLX_PROTO(void, glEndList,(void))
+DEF_GLX_PROTO(void, glCallList,(GLuint list), list)
+DEF_GLX_PROTO(void, glCallLists,(GLsizei n, GLenum type, const GLvoid *lists), n, type, lists)
+DEF_GLX_PROTO(void, glListBase,(GLuint base), base)
+DEF_GLX_PROTO(void, glBegin,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glEnd,(void))
+DEF_GLX_PROTO(void, glVertex2d,(GLdouble x, GLdouble y), x, y)
+DEF_GLX_PROTO(void, glVertex2f,(GLfloat x, GLfloat y), x, y)
+DEF_GLX_PROTO(void, glVertex2i,(GLint x, GLint y), x, y)
+DEF_GLX_PROTO(void, glVertex2s,(GLshort x, GLshort y), x, y)
+DEF_GLX_PROTO(void, glVertex3d,(GLdouble x, GLdouble y, GLdouble z), x, y, z)
+DEF_GLX_PROTO(void, glVertex3f,(GLfloat x, GLfloat y, GLfloat z), x, y, z)
+DEF_GLX_PROTO(void, glVertex3i,(GLint x, GLint y, GLint z), x, y, z)
+DEF_GLX_PROTO(void, glVertex3s,(GLshort x, GLshort y, GLshort z), x, y, z)
+DEF_GLX_PROTO(void, glVertex4d,(GLdouble x, GLdouble y, GLdouble z, GLdouble w), x, y, z, w)
+DEF_GLX_PROTO(void, glVertex4f,(GLfloat x, GLfloat y, GLfloat z, GLfloat w), x, y, z, w)
+DEF_GLX_PROTO(void, glVertex4i,(GLint x, GLint y, GLint z, GLint w), x, y, z, w)
+DEF_GLX_PROTO(void, glVertex4s,(GLshort x, GLshort y, GLshort z, GLshort w), x, y, z, w)
+DEF_GLX_PROTO(void, glVertex2dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glVertex2fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glVertex2iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glVertex2sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glVertex3dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glVertex3fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glVertex3iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glVertex3sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glVertex4dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glVertex4fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glVertex4iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glVertex4sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glNormal3b,(GLbyte nx, GLbyte ny, GLbyte nz), nx, ny, nz)
+DEF_GLX_PROTO(void, glNormal3d,(GLdouble nx, GLdouble ny, GLdouble nz), nx, ny, nz)
+DEF_GLX_PROTO(void, glNormal3f,(GLfloat nx, GLfloat ny, GLfloat nz), nx, ny, nz)
+DEF_GLX_PROTO(void, glNormal3i,(GLint nx, GLint ny, GLint nz), nx, ny, nz)
+DEF_GLX_PROTO(void, glNormal3s,(GLshort nx, GLshort ny, GLshort nz), nx, ny, nz)
+DEF_GLX_PROTO(void, glNormal3bv,(const GLbyte *v), v)
+DEF_GLX_PROTO(void, glNormal3dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glNormal3fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glNormal3iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glNormal3sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glIndexd,(GLdouble c), c)
+DEF_GLX_PROTO(void, glIndexf,(GLfloat c), c)
+DEF_GLX_PROTO(void, glIndexi,(GLint c), c)
+DEF_GLX_PROTO(void, glIndexs,(GLshort c), c)
+DEF_GLX_PROTO(void, glIndexub,(GLubyte c), c)
+DEF_GLX_PROTO(void, glIndexdv,(const GLdouble *c), c)
+DEF_GLX_PROTO(void, glIndexfv,(const GLfloat *c), c)
+DEF_GLX_PROTO(void, glIndexiv,(const GLint *c), c)
+DEF_GLX_PROTO(void, glIndexsv,(const GLshort *c), c)
+DEF_GLX_PROTO(void, glIndexubv,(const GLubyte *c), c)
+DEF_GLX_PROTO(void, glColor3b,(GLbyte red, GLbyte green, GLbyte blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3d,(GLdouble red, GLdouble green, GLdouble blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3f,(GLfloat red, GLfloat green, GLfloat blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3i,(GLint red, GLint green, GLint blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3s,(GLshort red, GLshort green, GLshort blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3ub,(GLubyte red, GLubyte green, GLubyte blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3ui,(GLuint red, GLuint green, GLuint blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor3us,(GLushort red, GLushort green, GLushort blue), red, green, blue)
+DEF_GLX_PROTO(void, glColor4b,(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4d,(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4f,(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4i,(GLint red, GLint green, GLint blue, GLint alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4s,(GLshort red, GLshort green, GLshort blue, GLshort alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4ub,(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4ui,(GLuint red, GLuint green, GLuint blue, GLuint alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor4us,(GLushort red, GLushort green, GLushort blue, GLushort alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glColor3bv,(const GLbyte *v), v)
+DEF_GLX_PROTO(void, glColor3dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glColor3fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glColor3iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glColor3sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glColor3ubv,(const GLubyte *v), v)
+DEF_GLX_PROTO(void, glColor3uiv,(const GLuint *v), v)
+DEF_GLX_PROTO(void, glColor3usv,(const GLushort *v), v)
+DEF_GLX_PROTO(void, glColor4bv,(const GLbyte *v), v)
+DEF_GLX_PROTO(void, glColor4dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glColor4fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glColor4iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glColor4sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glColor4ubv,(const GLubyte *v), v)
+DEF_GLX_PROTO(void, glColor4uiv,(const GLuint *v), v)
+DEF_GLX_PROTO(void, glColor4usv,(const GLushort *v), v)
+DEF_GLX_PROTO(void, glTexCoord1d,(GLdouble s), s)
+DEF_GLX_PROTO(void, glTexCoord1f,(GLfloat s), s)
+DEF_GLX_PROTO(void, glTexCoord1i,(GLint s), s)
+DEF_GLX_PROTO(void, glTexCoord1s,(GLshort s), s)
+DEF_GLX_PROTO(void, glTexCoord2d,(GLdouble s, GLdouble t), s, t)
+DEF_GLX_PROTO(void, glTexCoord2f,(GLfloat s, GLfloat t), s, t)
+DEF_GLX_PROTO(void, glTexCoord2i,(GLint s, GLint t), s, t)
+DEF_GLX_PROTO(void, glTexCoord2s,(GLshort s, GLshort t), s, t)
+DEF_GLX_PROTO(void, glTexCoord3d,(GLdouble s, GLdouble t, GLdouble r), s, t, r)
+DEF_GLX_PROTO(void, glTexCoord3f,(GLfloat s, GLfloat t, GLfloat r), s, t, r)
+DEF_GLX_PROTO(void, glTexCoord3i,(GLint s, GLint t, GLint r), s, t, r)
+DEF_GLX_PROTO(void, glTexCoord3s,(GLshort s, GLshort t, GLshort r), s, t, r)
+DEF_GLX_PROTO(void, glTexCoord4d,(GLdouble s, GLdouble t, GLdouble r, GLdouble q), s, t, r, q)
+DEF_GLX_PROTO(void, glTexCoord4f,(GLfloat s, GLfloat t, GLfloat r, GLfloat q), s, t, r, q)
+DEF_GLX_PROTO(void, glTexCoord4i,(GLint s, GLint t, GLint r, GLint q), s, t, r, q)
+DEF_GLX_PROTO(void, glTexCoord4s,(GLshort s, GLshort t, GLshort r, GLshort q), s, t, r, q)
+DEF_GLX_PROTO(void, glTexCoord1dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glTexCoord1fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glTexCoord1iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glTexCoord1sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glTexCoord2dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glTexCoord2fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glTexCoord2iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glTexCoord2sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glTexCoord3dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glTexCoord3fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glTexCoord3iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glTexCoord3sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glTexCoord4dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glTexCoord4fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glTexCoord4iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glTexCoord4sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glRasterPos2d,(GLdouble x, GLdouble y), x, y)
+DEF_GLX_PROTO(void, glRasterPos2f,(GLfloat x, GLfloat y), x, y)
+DEF_GLX_PROTO(void, glRasterPos2i,(GLint x, GLint y), x, y)
+DEF_GLX_PROTO(void, glRasterPos2s,(GLshort x, GLshort y), x, y)
+DEF_GLX_PROTO(void, glRasterPos3d,(GLdouble x, GLdouble y, GLdouble z), x, y, z)
+DEF_GLX_PROTO(void, glRasterPos3f,(GLfloat x, GLfloat y, GLfloat z), x, y, z)
+DEF_GLX_PROTO(void, glRasterPos3i,(GLint x, GLint y, GLint z), x, y, z)
+DEF_GLX_PROTO(void, glRasterPos3s,(GLshort x, GLshort y, GLshort z), x, y, z)
+DEF_GLX_PROTO(void, glRasterPos4d,(GLdouble x, GLdouble y, GLdouble z, GLdouble w), x, y, z, w)
+DEF_GLX_PROTO(void, glRasterPos4f,(GLfloat x, GLfloat y, GLfloat z, GLfloat w), x, y, z, w)
+DEF_GLX_PROTO(void, glRasterPos4i,(GLint x, GLint y, GLint z, GLint w), x, y, z, w)
+DEF_GLX_PROTO(void, glRasterPos4s,(GLshort x, GLshort y, GLshort z, GLshort w), x, y, z, w)
+DEF_GLX_PROTO(void, glRasterPos2dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glRasterPos2fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glRasterPos2iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glRasterPos2sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glRasterPos3dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glRasterPos3fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glRasterPos3iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glRasterPos3sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glRasterPos4dv,(const GLdouble *v), v)
+DEF_GLX_PROTO(void, glRasterPos4fv,(const GLfloat *v), v)
+DEF_GLX_PROTO(void, glRasterPos4iv,(const GLint *v), v)
+DEF_GLX_PROTO(void, glRasterPos4sv,(const GLshort *v), v)
+DEF_GLX_PROTO(void, glRectd,(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2), x1, y1, x2, y2)
+DEF_GLX_PROTO(void, glRectf,(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2), x1, y1, x2, y2)
+DEF_GLX_PROTO(void, glRecti,(GLint x1, GLint y1, GLint x2, GLint y2), x1, y1, x2, y2)
+DEF_GLX_PROTO(void, glRects,(GLshort x1, GLshort y1, GLshort x2, GLshort y2), x1, y1, x2, y2)
+DEF_GLX_PROTO(void, glRectdv,(const GLdouble *v1, const GLdouble *v2), v1, v2)
+DEF_GLX_PROTO(void, glRectfv,(const GLfloat *v1, const GLfloat *v2), v1, v2)
+DEF_GLX_PROTO(void, glRectiv,(const GLint *v1, const GLint *v2), v1, v2)
+DEF_GLX_PROTO(void, glRectsv,(const GLshort *v1, const GLshort *v2), v1, v2)
+DEF_GLX_PROTO(void, glVertexPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr), size, type, stride, ptr)
+DEF_GLX_PROTO(void, glNormalPointer,(GLenum type, GLsizei stride, const GLvoid *ptr), type, stride, ptr)
+DEF_GLX_PROTO(void, glColorPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr), size, type, stride, ptr)
+DEF_GLX_PROTO(void, glIndexPointer,(GLenum type, GLsizei stride, const GLvoid *ptr), type, stride, ptr)
+DEF_GLX_PROTO(void, glTexCoordPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr), size, type, stride, ptr)
+DEF_GLX_PROTO(void, glEdgeFlagPointer,(GLsizei stride, const GLvoid *ptr), stride, ptr)
+DEF_GLX_PROTO(void, glGetPointerv,(GLenum pname, GLvoid **params), pname, params)
+DEF_GLX_PROTO(void, glArrayElement,(GLint i), i)
+DEF_GLX_PROTO(void, glDrawArrays,(GLenum mode, GLint first, GLsizei count), mode, first, count)
+DEF_GLX_PROTO(void, glDrawElements,(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices), mode, count, type, indices)
+DEF_GLX_PROTO(void, glInterleavedArrays,(GLenum format, GLsizei stride, const GLvoid *pointer), format, stride, pointer)
+DEF_GLX_PROTO(void, glShadeModel,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glLightf,(GLenum light, GLenum pname, GLfloat param), light, pname, param)
+DEF_GLX_PROTO(void, glLighti,(GLenum light, GLenum pname, GLint param), light, pname, param)
+DEF_GLX_PROTO(void, glLightfv,(GLenum light, GLenum pname, const GLfloat *params), light, pname, params)
+DEF_GLX_PROTO(void, glLightiv,(GLenum light, GLenum pname, const GLint *params), light, pname, params)
+DEF_GLX_PROTO(void, glGetLightfv,(GLenum light, GLenum pname, GLfloat *params), light, pname, params)
+DEF_GLX_PROTO(void, glGetLightiv,(GLenum light, GLenum pname, GLint *params), light, pname, params)
+DEF_GLX_PROTO(void, glLightModelf,(GLenum pname, GLfloat param), pname, param)
+DEF_GLX_PROTO(void, glLightModeli,(GLenum pname, GLint param), pname, param)
+DEF_GLX_PROTO(void, glLightModelfv,(GLenum pname, const GLfloat *params), pname, params)
+DEF_GLX_PROTO(void, glLightModeliv,(GLenum pname, const GLint *params), pname, params)
+DEF_GLX_PROTO(void, glMaterialf,(GLenum face, GLenum pname, GLfloat param), face, pname, param)
+DEF_GLX_PROTO(void, glMateriali,(GLenum face, GLenum pname, GLint param), face, pname, param)
+DEF_GLX_PROTO(void, glMaterialfv,(GLenum face, GLenum pname, const GLfloat *params), face, pname, params)
+DEF_GLX_PROTO(void, glMaterialiv,(GLenum face, GLenum pname, const GLint *params), face, pname, params)
+DEF_GLX_PROTO(void, glGetMaterialfv,(GLenum face, GLenum pname, GLfloat *params), face, pname, params)
+DEF_GLX_PROTO(void, glGetMaterialiv,(GLenum face, GLenum pname, GLint *params), face, pname, params)
+DEF_GLX_PROTO(void, glColorMaterial,(GLenum face, GLenum mode), face, mode)
+DEF_GLX_PROTO(void, glPixelZoom,(GLfloat xfactor, GLfloat yfactor), xfactor, yfactor)
+DEF_GLX_PROTO(void, glPixelStoref,(GLenum pname, GLfloat param), pname, param)
+DEF_GLX_PROTO(void, glPixelStorei,(GLenum pname, GLint param), pname, param)
+DEF_GLX_PROTO(void, glPixelTransferf,(GLenum pname, GLfloat param), pname, param)
+DEF_GLX_PROTO(void, glPixelTransferi,(GLenum pname, GLint param), pname, param)
+DEF_GLX_PROTO(void, glPixelMapfv,(GLenum map, GLsizei mapsize, const GLfloat *values), map, mapsize, values)
+DEF_GLX_PROTO(void, glPixelMapuiv,(GLenum map, GLsizei mapsize, const GLuint *values), map, mapsize, values)
+DEF_GLX_PROTO(void, glPixelMapusv,(GLenum map, GLsizei mapsize, const GLushort *values), map, mapsize, values)
+DEF_GLX_PROTO(void, glGetPixelMapfv,(GLenum map, GLfloat *values), map, values)
+DEF_GLX_PROTO(void, glGetPixelMapuiv,(GLenum map, GLuint *values), map, values)
+DEF_GLX_PROTO(void, glGetPixelMapusv,(GLenum map, GLushort *values), map, values)
+DEF_GLX_PROTO(void, glBitmap,(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap), width, height, xorig, yorig, xmove, ymove, bitmap)
+DEF_GLX_PROTO(void, glReadPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels), x, y, width, height, format, type, pixels)
+DEF_GLX_PROTO(void, glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels), width, height, format, type, pixels)
+DEF_GLX_PROTO(void, glCopyPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type), x, y, width, height, type)
+DEF_GLX_PROTO(void, glStencilFunc,(GLenum func, GLint ref, GLuint mask), func, ref, mask)
+DEF_GLX_PROTO(void, glStencilMask,(GLuint mask), mask)
+DEF_GLX_PROTO(void, glStencilOp,(GLenum fail, GLenum zfail, GLenum zpass), fail, zfail, zpass)
+DEF_GLX_PROTO(void, glClearStencil,(GLint s), s)
+DEF_GLX_PROTO(void, glTexGend,(GLenum coord, GLenum pname, GLdouble param), coord, pname, param)
+DEF_GLX_PROTO(void, glTexGenf,(GLenum coord, GLenum pname, GLfloat param), coord, pname, param)
+DEF_GLX_PROTO(void, glTexGeni,(GLenum coord, GLenum pname, GLint param), coord, pname, param)
+DEF_GLX_PROTO(void, glTexGendv,(GLenum coord, GLenum pname, const GLdouble *params), coord, pname, params)
+DEF_GLX_PROTO(void, glTexGenfv,(GLenum coord, GLenum pname, const GLfloat *params), coord, pname, params)
+DEF_GLX_PROTO(void, glTexGeniv,(GLenum coord, GLenum pname, const GLint *params), coord, pname, params)
+DEF_GLX_PROTO(void, glGetTexGendv,(GLenum coord, GLenum pname, GLdouble *params), coord, pname, params)
+DEF_GLX_PROTO(void, glGetTexGenfv,(GLenum coord, GLenum pname, GLfloat *params), coord, pname, params)
+DEF_GLX_PROTO(void, glGetTexGeniv,(GLenum coord, GLenum pname, GLint *params), coord, pname, params)
+DEF_GLX_PROTO(void, glTexEnvf,(GLenum target, GLenum pname, GLfloat param), target, pname, param)
+DEF_GLX_PROTO(void, glTexEnvi,(GLenum target, GLenum pname, GLint param), target, pname, param)
+DEF_GLX_PROTO(void, glTexEnvfv,(GLenum target, GLenum pname, const GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glTexEnviv,(GLenum target, GLenum pname, const GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetTexEnvfv,(GLenum target, GLenum pname, GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetTexEnviv,(GLenum target, GLenum pname, GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glTexParameterf,(GLenum target, GLenum pname, GLfloat param), target, pname, param)
+DEF_GLX_PROTO(void, glTexParameteri,(GLenum target, GLenum pname, GLint param), target, pname, param)
+DEF_GLX_PROTO(void, glTexParameterfv,(GLenum target, GLenum pname, const GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glTexParameteriv,(GLenum target, GLenum pname, const GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetTexParameterfv,(GLenum target, GLenum pname, GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetTexParameteriv,(GLenum target, GLenum pname, GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetTexLevelParameterfv,(GLenum target, GLint level, GLenum pname, GLfloat *params), target, level, pname, params)
+DEF_GLX_PROTO(void, glGetTexLevelParameteriv,(GLenum target, GLint level, GLenum pname, GLint *params), target, level, pname, params)
+DEF_GLX_PROTO(void, glTexImage1D,(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels), target, level, internalFormat, width, border, format, type, pixels)
+DEF_GLX_PROTO(void, glTexImage2D,(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels), target, level, internalFormat, width, height, border, format, type, pixels)
+DEF_GLX_PROTO(void, glGetTexImage,(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels), target, level, format, type, pixels)
+DEF_GLX_PROTO(void, glGenTextures,(GLsizei n, GLuint *textures), n, textures)
+DEF_GLX_PROTO(void, glDeleteTextures,(GLsizei n, const GLuint *textures), n, textures)
+DEF_GLX_PROTO(void, glBindTexture,(GLenum target, GLuint texture), target, texture)
+DEF_GLX_PROTO(void, glPrioritizeTextures,(GLsizei n, const GLuint *textures, const GLclampf *priorities), n, textures, priorities)
+DEF_GLX_PROTO(GLboolean, glAreTexturesResident,(GLsizei n, const GLuint *textures, GLboolean *residences), n, textures, residences)
+DEF_GLX_PROTO(GLboolean, glIsTexture,(GLuint texture), texture)
+DEF_GLX_PROTO(void, glTexSubImage1D,(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels), target, level, xoffset, width, format, type, pixels)
+DEF_GLX_PROTO(void, glTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels), target, level, xoffset, yoffset, width, height, format, type, pixels)
+DEF_GLX_PROTO(void, glCopyTexImage1D,(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border), target, level, internalformat, x, y, width, border)
+DEF_GLX_PROTO(void, glCopyTexImage2D,(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border), target, level, internalformat, x, y, width, height, border)
+DEF_GLX_PROTO(void, glCopyTexSubImage1D,(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width), target, level, xoffset, x, y, width)
+DEF_GLX_PROTO(void, glCopyTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height), target, level, xoffset, yoffset, x, y, width, height)
+DEF_GLX_PROTO(void, glMap1d,(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points), target, u1, u2, stride, order, points)
+DEF_GLX_PROTO(void, glMap1f,(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points), target, u1, u2, stride, order, points)
+DEF_GLX_PROTO(void, glMap2d,(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points), target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points)
+DEF_GLX_PROTO(void, glMap2f,(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points), target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points)
+DEF_GLX_PROTO(void, glGetMapdv,(GLenum target, GLenum query, GLdouble *v), target, query, v)
+DEF_GLX_PROTO(void, glGetMapfv,(GLenum target, GLenum query, GLfloat *v), target, query, v)
+DEF_GLX_PROTO(void, glGetMapiv,(GLenum target, GLenum query, GLint *v), target, query, v)
+DEF_GLX_PROTO(void, glEvalCoord1d,(GLdouble u), u)
+DEF_GLX_PROTO(void, glEvalCoord1f,(GLfloat u), u)
+DEF_GLX_PROTO(void, glEvalCoord1dv,(const GLdouble *u), u)
+DEF_GLX_PROTO(void, glEvalCoord1fv,(const GLfloat *u), u)
+DEF_GLX_PROTO(void, glEvalCoord2d,(GLdouble u, GLdouble v), u, v)
+DEF_GLX_PROTO(void, glEvalCoord2f,(GLfloat u, GLfloat v), u, v)
+DEF_GLX_PROTO(void, glEvalCoord2dv,(const GLdouble *u), u)
+DEF_GLX_PROTO(void, glEvalCoord2fv,(const GLfloat *u), u)
+DEF_GLX_PROTO(void, glMapGrid1d,(GLint un, GLdouble u1, GLdouble u2), un, u1, u2)
+DEF_GLX_PROTO(void, glMapGrid1f,(GLint un, GLfloat u1, GLfloat u2), un, u1, u2)
+DEF_GLX_PROTO(void, glMapGrid2d,(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2), un, u1, u2, vn, v1, v2)
+DEF_GLX_PROTO(void, glMapGrid2f,(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2), un, u1, u2, vn, v1, v2)
+DEF_GLX_PROTO(void, glEvalPoint1,(GLint i), i)
+DEF_GLX_PROTO(void, glEvalPoint2,(GLint i, GLint j), i, j)
+DEF_GLX_PROTO(void, glEvalMesh1,(GLenum mode, GLint i1, GLint i2), mode, i1, i2)
+DEF_GLX_PROTO(void, glEvalMesh2,(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2), mode, i1, i2, j1, j2)
+DEF_GLX_PROTO(void, glFogf,(GLenum pname, GLfloat param), pname, param)
+DEF_GLX_PROTO(void, glFogi,(GLenum pname, GLint param), pname, param)
+DEF_GLX_PROTO(void, glFogfv,(GLenum pname, const GLfloat *params), pname, params)
+DEF_GLX_PROTO(void, glFogiv,(GLenum pname, const GLint *params), pname, params)
+DEF_GLX_PROTO(void, glFeedbackBuffer,(GLsizei size, GLenum type, GLfloat *buffer), size, type, buffer)
+DEF_GLX_PROTO(void, glPassThrough,(GLfloat token), token)
+DEF_GLX_PROTO(void, glSelectBuffer,(GLsizei size, GLuint *buffer), size, buffer)
+DEF_GLX_PROTO(void, glInitNames,(void))
+DEF_GLX_PROTO(void, glLoadName,(GLuint name), name)
+DEF_GLX_PROTO(void, glPushName,(GLuint name), name)
+DEF_GLX_PROTO(void, glPopName,(void))
+DEF_GLX_PROTO(void, glDrawRangeElements,(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices), mode, start, end, count, type, indices)
+DEF_GLX_PROTO(void, glTexImage3D,(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels), target, level, internalFormat, width, height, depth, border, format, type, pixels)
+DEF_GLX_PROTO(void, glTexSubImage3D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels), target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)
+DEF_GLX_PROTO(void, glCopyTexSubImage3D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height), target, level, xoffset, yoffset, zoffset, x, y, width, height)
+DEF_GLX_PROTO(void, glColorTable,(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table), target, internalformat, width, format, type, table)
+DEF_GLX_PROTO(void, glColorSubTable,(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data), target, start, count, format, type, data)
+DEF_GLX_PROTO(void, glColorTableParameteriv,(GLenum target, GLenum pname, const GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glColorTableParameterfv,(GLenum target, GLenum pname, const GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glCopyColorSubTable,(GLenum target, GLsizei start, GLint x, GLint y, GLsizei width), target, start, x, y, width)
+DEF_GLX_PROTO(void, glCopyColorTable,(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width), target, internalformat, x, y, width)
+DEF_GLX_PROTO(void, glGetColorTable,(GLenum target, GLenum format, GLenum type, GLvoid *table), target, format, type, table)
+DEF_GLX_PROTO(void, glGetColorTableParameterfv,(GLenum target, GLenum pname, GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetColorTableParameteriv,(GLenum target, GLenum pname, GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glBlendEquation,(GLenum mode), mode)
+DEF_GLX_PROTO(void, glBlendColor,(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha), red, green, blue, alpha)
+DEF_GLX_PROTO(void, glHistogram,(GLenum target, GLsizei width, GLenum internalformat, GLboolean sink), target, width, internalformat, sink)
+DEF_GLX_PROTO(void, glResetHistogram,(GLenum target), target)
+DEF_GLX_PROTO(void, glGetHistogram,(GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values), target, reset, format, type, values)
+DEF_GLX_PROTO(void, glGetHistogramParameterfv,(GLenum target, GLenum pname, GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetHistogramParameteriv,(GLenum target, GLenum pname, GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glMinmax,(GLenum target, GLenum internalformat, GLboolean sink), target, internalformat, sink)
+DEF_GLX_PROTO(void, glResetMinmax,(GLenum target), target)
+DEF_GLX_PROTO(void, glGetMinmax,(GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values), target, reset, format, types, values)
+DEF_GLX_PROTO(void, glGetMinmaxParameterfv,(GLenum target, GLenum pname, GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetMinmaxParameteriv,(GLenum target, GLenum pname, GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glConvolutionFilter1D,(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image), target, internalformat, width, format, type, image)
+DEF_GLX_PROTO(void, glConvolutionFilter2D,(GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image), target, internalformat, width, height, format, type, image)
+DEF_GLX_PROTO(void, glConvolutionParameterf,(GLenum target, GLenum pname, GLfloat params), target, pname, params)
+DEF_GLX_PROTO(void, glConvolutionParameterfv,(GLenum target, GLenum pname, const GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glConvolutionParameteri,(GLenum target, GLenum pname, GLint params), target, pname, params)
+DEF_GLX_PROTO(void, glConvolutionParameteriv,(GLenum target, GLenum pname, const GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glCopyConvolutionFilter1D,(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width), target, internalformat, x, y, width)
+DEF_GLX_PROTO(void, glCopyConvolutionFilter2D,(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height), target, internalformat, x, y, width, height)
+DEF_GLX_PROTO(void, glGetConvolutionFilter,(GLenum target, GLenum format, GLenum type, GLvoid *image), target, format, type, image)
+DEF_GLX_PROTO(void, glGetConvolutionParameterfv,(GLenum target, GLenum pname, GLfloat *params), target, pname, params)
+DEF_GLX_PROTO(void, glGetConvolutionParameteriv,(GLenum target, GLenum pname, GLint *params), target, pname, params)
+DEF_GLX_PROTO(void, glSeparableFilter2D,(GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column), target, internalformat, width, height, format, type, row, column)
+DEF_GLX_PROTO(void, glGetSeparableFilter,(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span), target, format, type, row, column, span)
+DEF_GLX_PROTO(void, glActiveTexture,(GLenum texture), texture)
+DEF_GLX_PROTO(void, glClientActiveTexture,(GLenum texture), texture)
+DEF_GLX_PROTO(void, glCompressedTexImage1D,(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data), target, level, internalformat, width, border, imageSize, data)
+DEF_GLX_PROTO(void, glCompressedTexImage2D,(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data), target, level, internalformat, width, height, border, imageSize, data)
+DEF_GLX_PROTO(void, glCompressedTexImage3D,(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data), target, level, internalformat, width, height, depth, border, imageSize, data)
+DEF_GLX_PROTO(void, glCompressedTexSubImage1D,(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data), target, level, xoffset, width, format, imageSize, data)
+DEF_GLX_PROTO(void, glCompressedTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data), target, level, xoffset, yoffset, width, height, format, imageSize, data)
+DEF_GLX_PROTO(void, glCompressedTexSubImage3D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data), target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data)
+DEF_GLX_PROTO(void, glGetCompressedTexImage,(GLenum target, GLint lod, GLvoid *img), target, lod, img)
+DEF_GLX_PROTO(void, glMultiTexCoord1d,(GLenum target, GLdouble s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1dv,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord1f,(GLenum target, GLfloat s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1fv,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord1i,(GLenum target, GLint s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1iv,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord1s,(GLenum target, GLshort s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1sv,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2d,(GLenum target, GLdouble s, GLdouble t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2dv,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2f,(GLenum target, GLfloat s, GLfloat t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2fv,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2i,(GLenum target, GLint s, GLint t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2iv,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2s,(GLenum target, GLshort s, GLshort t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2sv,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3d,(GLenum target, GLdouble s, GLdouble t, GLdouble r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3dv,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3f,(GLenum target, GLfloat s, GLfloat t, GLfloat r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3fv,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3i,(GLenum target, GLint s, GLint t, GLint r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3iv,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3s,(GLenum target, GLshort s, GLshort t, GLshort r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3sv,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4d,(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4dv,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4f,(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4fv,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4i,(GLenum target, GLint s, GLint t, GLint r, GLint q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4iv,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4s,(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4sv,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glLoadTransposeMatrixd,(const GLdouble m[16]), m)
+DEF_GLX_PROTO(void, glLoadTransposeMatrixf,(const GLfloat m[16]), m)
+DEF_GLX_PROTO(void, glMultTransposeMatrixd,(const GLdouble m[16]), m)
+DEF_GLX_PROTO(void, glMultTransposeMatrixf,(const GLfloat m[16]), m)
+DEF_GLX_PROTO(void, glSampleCoverage,(GLclampf value, GLboolean invert), value, invert)
+DEF_GLX_PROTO(void, glActiveTextureARB,(GLenum texture), texture)
+DEF_GLX_PROTO(void, glClientActiveTextureARB,(GLenum texture), texture)
+DEF_GLX_PROTO(void, glMultiTexCoord1dARB,(GLenum target, GLdouble s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1dvARB,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord1fARB,(GLenum target, GLfloat s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1fvARB,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord1iARB,(GLenum target, GLint s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1ivARB,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord1sARB,(GLenum target, GLshort s), target, s)
+DEF_GLX_PROTO(void, glMultiTexCoord1svARB,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2dARB,(GLenum target, GLdouble s, GLdouble t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2dvARB,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2fARB,(GLenum target, GLfloat s, GLfloat t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2fvARB,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2iARB,(GLenum target, GLint s, GLint t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2ivARB,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord2sARB,(GLenum target, GLshort s, GLshort t), target, s, t)
+DEF_GLX_PROTO(void, glMultiTexCoord2svARB,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3dARB,(GLenum target, GLdouble s, GLdouble t, GLdouble r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3dvARB,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3fARB,(GLenum target, GLfloat s, GLfloat t, GLfloat r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3fvARB,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3iARB,(GLenum target, GLint s, GLint t, GLint r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3ivARB,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord3sARB,(GLenum target, GLshort s, GLshort t, GLshort r), target, s, t, r)
+DEF_GLX_PROTO(void, glMultiTexCoord3svARB,(GLenum target, const GLshort *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4dARB,(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4dvARB,(GLenum target, const GLdouble *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4fARB,(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4fvARB,(GLenum target, const GLfloat *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4iARB,(GLenum target, GLint s, GLint t, GLint r, GLint q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4ivARB,(GLenum target, const GLint *v), target, v)
+DEF_GLX_PROTO(void, glMultiTexCoord4sARB,(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q), target, s, t, r, q)
+DEF_GLX_PROTO(void, glMultiTexCoord4svARB,(GLenum target, const GLshort *v), target, v)
--- /dev/null
+#include <dlfcn.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+#include <cassert>
+#include <map>
+#include <string>
+#include <X11/Xatom.h>
+#pragma GCC visibility push(default)
+#define GLX_GLXEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glx.h>
+#pragma GCC visibility pop
+
+#define primus_print(c, ...) do { if (c) fprintf(stderr, "primus: " __VA_ARGS__); } while (0)
+
+#define die_if(cond, ...) do {if (cond) {primus_print(true, "fatal: " __VA_ARGS__); exit(1);} } while (0)
+#define primus_warn(...) primus_print(primus.loglevel >= 1, "warning: " __VA_ARGS__)
+#define primus_perf(...) primus_print(primus.loglevel >= 2, "profiling: " __VA_ARGS__)
+
+// Try to load any of the colon-separated libraries
+static void *mdlopen(const char *paths, int flag)
+{
+ char *p = strdupa(paths);
+ char errors[1024], *errors_ptr = errors, *errors_end = errors + 1024;
+ for (char *c = p; c; p = c + 1)
+ {
+ if ((c = strchr(p, ':')))
+ *c = 0;
+ die_if(p[0] != '/', "need absolute library path: %s\n", p);
+ void *handle = dlopen(p, flag);
+ if (handle)
+ return handle;
+ errors_ptr += snprintf(errors_ptr, errors_end - errors_ptr, "%s\n", dlerror());
+ }
+ die_if(true, "failed to load any of the libraries: %s\n%s", paths, errors);
+}
+
+static void *real_dlsym(void *handle, const char *symbol)
+{
+ typedef void* (*dlsym_fn)(void *, const char*);
+ static dlsym_fn pdlsym = (dlsym_fn) dlsym(dlopen("libdl.so.2", RTLD_LAZY), "dlsym");
+ return pdlsym(handle, symbol);
+}
+
+// Pointers to implemented/forwarded GLX and OpenGL functions
+struct CapturedFns {
+ void *handle;
+ // Declare functions as fields of the struct
+#define DEF_GLX_PROTO(ret, name, args, ...) ret (*name) args;
+#include "glx-reimpl.def"
+#include "glx-dpyredir.def"
+#include "glxext-reimpl.def"
+#include "gl-passthru.def"
+#include "gl-needed.def"
+#undef DEF_GLX_PROTO
+ CapturedFns(const char *lib)
+ {
+ handle = mdlopen(lib, RTLD_LAZY);
+#define DEF_GLX_PROTO(ret, name, args, ...) name = (ret (*) args)real_dlsym(handle, #name);
+#include "glx-reimpl.def"
+#include "glx-dpyredir.def"
+#undef DEF_GLX_PROTO
+#define DEF_GLX_PROTO(ret, name, args, ...) name = (ret (*) args)this->glXGetProcAddress((GLubyte*)#name);
+#include "glxext-reimpl.def"
+#include "gl-passthru.def"
+#include "gl-needed.def"
+#undef DEF_GLX_PROTO
+ }
+ ~CapturedFns()
+ {
+ dlclose(handle);
+ }
+};
+
+// Drawable tracking info
+struct DrawableInfo {
+ // Only XWindow is not explicitely created via GLX
+ enum {XWindow, Window, Pixmap, Pbuffer} kind;
+ GLXFBConfig fbconfig;
+ GLXPbuffer pbuffer;
+ Drawable window;
+ int width, height;
+ enum ReinitTodo {NONE, RESIZE, SHUTDOWN} reinit;
+ GLvoid *pixeldata;
+ GLsync sync;
+ GLXContext actx;
+
+ struct {
+ pthread_t worker;
+ sem_t acqsem, relsem;
+ ReinitTodo reinit;
+
+ void spawn_worker(GLXDrawable draw, void* (*work)(void*))
+ {
+ reinit = RESIZE;
+ sem_init(&acqsem, 0, 0);
+ sem_init(&relsem, 0, 0);
+ pthread_create(&worker, NULL, work, (void*)draw);
+ }
+ void reap_worker()
+ {
+ //pthread_cancel(worker);
+ pthread_join(worker, NULL);
+ sem_destroy(&relsem);
+ sem_destroy(&acqsem);
+ worker = 0;
+ }
+ } r, d;
+ void reap_workers()
+ {
+ if (r.worker)
+ {
+ r.reinit = SHUTDOWN;
+ sem_post(&r.acqsem);
+ sem_wait(&r.relsem);
+ r.reap_worker();
+ d.reap_worker();
+ }
+ }
+ void update_geometry(int width, int height)
+ {
+ if (this->width == width && this->height == height)
+ return;
+ this->width = width; this->height = height;
+ __sync_synchronize();
+ reinit = RESIZE;
+ }
+ ~DrawableInfo();
+};
+
+struct DrawablesInfo: public std::map<GLXDrawable, DrawableInfo> {
+ bool known(GLXDrawable draw)
+ {
+ return this->find(draw) != this->end();
+ }
+};
+
+struct ContextInfo {
+ GLXFBConfig fbconfig;
+ int sharegroup;
+};
+
+struct ContextsInfo: public std::map<GLXContext, ContextInfo> {
+ void record(GLXContext ctx, GLXFBConfig config, GLXContext share)
+ {
+ static int nsharegroups;
+ int sharegroup = share ? (*this)[share].sharegroup : nsharegroups++;
+ (*this)[ctx] = (ContextInfo){config, sharegroup};
+ }
+};
+
+// Shorthand for obtaining compile-time configurable value that can be
+// overridden by environment
+#define getconf(V) (getenv(#V) ? getenv(#V) : V)
+
+// Runs before all other initialization takes place
+struct EarlyInitializer {
+ EarlyInitializer(const char **adpy_strp, const char **libgla_strp)
+ {
+#ifdef BUMBLEBEE_SOCKET
+ // Signal the Bumblebee daemon to bring up secondary X
+ int sock = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, getconf(BUMBLEBEE_SOCKET), sizeof(addr.sun_path));
+ die_if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0,
+ "failed to connect to Bumblebee daemon: %s\n", strerror(errno));
+ static char c[256];
+ if (!getenv("PRIMUS_DISPLAY"))
+ {
+ send(sock, "Q VirtualDisplay", strlen("Q VirtualDisplay") + 1, 0);
+ recv(sock, &c, 255, 0);
+ die_if(memcmp(c, "Value: ", strlen("Value: ")), "unexpected query response\n");
+ *strchrnul(c, '\n') = 0;
+ *adpy_strp = strdup(c + 7);
+ }
+ if (!getenv("PRIMUS_libGLa"))
+ {
+ send(sock, "Q LibraryPath", strlen("Q LibraryPath") + 1, 0);
+ recv(sock, &c, 255, 0);
+ die_if(memcmp(c, "Value: ", strlen("Value: ")), "unexpected query response\n");
+ *strchrnul(c, '\n') = 0;
+ int npaths = 0;
+ for (char *p = c + 7; *p; npaths++, p = strchrnul(p + 1, ':'));
+ if (npaths)
+ {
+ char *bblibs = new char[strlen(c + 7) + npaths * strlen("/libGL.so.1") + 1], *b = bblibs, *n, *p;
+ for (p = c + 7; *p; p = n)
+ {
+ n = strchrnul(p + 1, ':');
+ b += sprintf(b, "%.*s/libGL.so.1", (int)(n - p), p);
+ }
+ *libgla_strp = bblibs;
+ }
+ }
+ send(sock, "C", 1, 0);
+ recv(sock, &c, 255, 0);
+ die_if(c[0] == 'N', "Bumblebee daemon reported: %s\n", c + 5);
+ die_if(c[0] != 'Y', "failure contacting Bumblebee daemon\n");
+ // the socket will be closed when the application quits, then bumblebee will shut down the secondary X
+#else
+#warning Building without Bumblebee daemon support
+#endif
+ }
+};
+
+// Process-wide data
+static struct PrimusInfo {
+ const char *adpy_str, *libgla_str;
+ EarlyInitializer ei;
+ // Readback-display synchronization method
+ // 0: no sync, 1: D lags behind one frame, 2: fully synced
+ int sync;
+ // 0: only errors, 1: warnings, 2: profiling
+ int loglevel;
+ // 0: autodetect, 1: texture, 2: PBO glDrawPixels
+ int dispmethod;
+ // sleep ratio in readback thread, percent
+ int autosleep;
+ // The "accelerating" X display
+ Display *adpy;
+ // The "displaying" X display. The same as the application is using, but
+ // primus opens its own connection.
+ Display *ddpy;
+ // An artifact: primus needs to make symbols from libglapi.so globally
+ // visible before loading Mesa
+ const void *needed_global;
+ CapturedFns afns;
+ CapturedFns dfns;
+ // FIXME: there are race conditions in accesses to these
+ DrawablesInfo drawables;
+ ContextsInfo contexts;
+
+ PrimusInfo():
+ adpy_str(getconf(PRIMUS_DISPLAY)),
+ libgla_str(getconf(PRIMUS_libGLa)),
+ ei(&adpy_str, &libgla_str),
+ sync(atoi(getconf(PRIMUS_SYNC))),
+ loglevel(atoi(getconf(PRIMUS_VERBOSE))),
+ dispmethod(atoi(getconf(PRIMUS_UPLOAD))),
+ autosleep(atoi(getconf(PRIMUS_SLEEP))),
+ adpy(XOpenDisplay(adpy_str)),
+ ddpy(XOpenDisplay(NULL)),
+ needed_global(dlopen(getconf(PRIMUS_LOAD_GLOBAL), RTLD_LAZY | RTLD_GLOBAL)),
+ afns(libgla_str),
+ dfns(getconf(PRIMUS_libGLd))
+ {
+ die_if(!adpy, "failed to open secondary X display\n");
+ die_if(!ddpy, "failed to open main X display\n");
+ die_if(!needed_global, "failed to load PRIMUS_LOAD_GLOBAL\n");
+ }
+} primus;
+
+// Thread-specific data
+static __thread struct {
+ Display *dpy;
+ GLXDrawable drawable, read_drawable;
+ void make_current(Display *dpy, GLXDrawable draw, GLXDrawable read)
+ {
+ this->dpy = dpy;
+ this->drawable = draw;
+ this->read_drawable = read;
+ }
+} tsdata;
+
+// Profiler
+struct Profiler {
+ const char *name;
+ const char * const *state_names;
+
+ double state_time[6], prev_timestamp, print_timestamp;
+ int state, nframes, width, height;
+
+ static double get_timestamp()
+ {
+ struct timespec tp;
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ return tp.tv_sec + 1e-9 * tp.tv_nsec;
+ }
+
+ Profiler(const char *name, const char * const *state_names):
+ name(name),
+ state_names(state_names),
+ state(0), nframes(0), width(0), height(0)
+ {
+ memset(state_time, 0, sizeof(state_time));
+ prev_timestamp = print_timestamp = get_timestamp();
+ }
+
+ void tick(bool state_reset = false)
+ {
+ if (primus.loglevel < 2)
+ return;
+ double timestamp = get_timestamp();
+ assert(state_reset || state_names[state]);
+ if (state_reset)
+ state = 0;
+ assert(state * sizeof(state_time[0]) < sizeof(state_time));
+ state_time[state++] += timestamp - prev_timestamp;
+ prev_timestamp = timestamp;
+ if (state_names[state])
+ return;
+ nframes++;
+ // check if it's time to print again
+ double period = timestamp - print_timestamp; // time since we printed
+ if (period < 5)
+ return;
+ // construct output
+ char buf[128], *cbuf = buf, *end = buf+128;
+ for (int i = 0; i < state; i++)
+ cbuf += snprintf(cbuf, end - cbuf, ", %.1f%% %s", 100 * state_time[i] / period, state_names[i]);
+ primus_perf("%s: %dx%d, %.1f fps%s\n", name, width, height, nframes / period, buf);
+ // start counting again
+ print_timestamp = timestamp;
+ nframes = 0;
+ memset(state_time, 0, sizeof(state_time));
+ }
+};
+
+// Find out the dimensions of the window
+static void note_geometry(Display *dpy, Drawable draw, int *width, int *height)
+{
+ Window root;
+ int x, y;
+ unsigned bw, d;
+ XGetGeometry(dpy, draw, &root, &x, &y, (unsigned *)width, (unsigned *)height, &bw, &d);
+}
+
+static GLXFBConfig* get_dconfigs(Display *dpy)
+{
+ static const int attrs[] = {GLX_DOUBLEBUFFER, GL_TRUE, None};
+ int ncfg;
+ GLXFBConfig *dconfigs = primus.dfns.glXChooseFBConfig(dpy, 0, attrs, &ncfg);
+ die_if(!dconfigs, "broken GLX on main X display\n");
+ return dconfigs;
+}
+
+static bool test_drawpixels_fast(Display *dpy, GLXContext ctx, GLXFBConfig dconfig)
+{
+ int width = 1920, height = 1080;
+ int pbattrs[] = {GLX_PBUFFER_WIDTH, width, GLX_PBUFFER_HEIGHT, height, GLX_PRESERVED_CONTENTS, True, None};
+ GLXPbuffer pbuffer = primus.dfns.glXCreatePbuffer(dpy, dconfig, pbattrs);
+ primus.dfns.glXMakeCurrent(dpy, pbuffer, ctx);
+ GLuint pbo;
+ primus.dfns.glGenBuffers(1, &pbo);
+ primus.dfns.glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, pbo);
+ primus.dfns.glBufferData(GL_PIXEL_UNPACK_BUFFER_EXT, width*height*4, NULL, GL_STREAM_DRAW);
+ void *pixeldata = malloc(width*height*4);
+
+ double end = 0.2 + Profiler::get_timestamp();
+ int iters = 0;
+ do {
+ primus.dfns.glBufferSubData(GL_PIXEL_UNPACK_BUFFER_EXT, 0, width*height*4, pixeldata);
+ primus.dfns.glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ primus.dfns.glXSwapBuffers(dpy, pbuffer);
+ iters++;
+ } while (end > Profiler::get_timestamp());
+
+ free(pixeldata);
+ primus.dfns.glDeleteBuffers(1, &pbo);
+ primus.dfns.glXDestroyPbuffer(dpy, pbuffer);
+
+ bool is_fast = iters >= 12;
+ primus_perf("upload autodetection: will use %s path (%d iters)\n", is_fast ? "PBO" : "texture", iters);
+ return is_fast;
+}
+
+static void* display_work(void *vd)
+{
+ GLXDrawable drawable = (GLXDrawable)vd;
+ DrawableInfo &di = primus.drawables[drawable];
+ int width, height;
+ static const float quad_vertex_coords[] = {-1, -1, -1, 1, 1, 1, 1, -1};
+ static const float quad_texture_coords[] = { 0, 0, 0, 1, 1, 1, 1, 0};
+ GLuint textures[2] = {0}, pbos[2] = {0};
+ int ctex = 0;
+ static const char *state_names[] = {"wait", "upload", "draw+swap", NULL};
+ Profiler profiler("display", state_names);
+ Display *ddpy = XOpenDisplay(NULL);
+ if (!ddpy) // Chromium sandbox prevents opening new connections
+ {
+ ddpy = primus.ddpy;
+ primus_warn("reusing initial X connection for display thread\n");
+ }
+ assert(di.kind == di.XWindow || di.kind == di.Window);
+ XSelectInput(ddpy, di.window, StructureNotifyMask);
+ note_geometry(ddpy, di.window, &width, &height);
+ di.update_geometry(width, height);
+ GLXFBConfig *dconfigs = get_dconfigs(ddpy);
+ GLXContext context = primus.dfns.glXCreateNewContext(ddpy, *dconfigs, GLX_RGBA_TYPE, NULL, True);
+ die_if(!primus.dfns.glXIsDirect(ddpy, context),
+ "failed to acquire direct rendering context for display thread\n");
+ if (!primus.dispmethod)
+ primus.dispmethod = test_drawpixels_fast(ddpy, context, *dconfigs) ? 2 : 1;
+ XFree(dconfigs);
+ primus.dfns.glXMakeCurrent(ddpy, di.window, context);
+ bool use_textures = (primus.dispmethod == 1);
+ if (use_textures)
+ {
+ primus.dfns.glVertexPointer (2, GL_FLOAT, 0, quad_vertex_coords);
+ primus.dfns.glTexCoordPointer(2, GL_FLOAT, 0, quad_texture_coords);
+ primus.dfns.glEnableClientState(GL_VERTEX_ARRAY);
+ primus.dfns.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ primus.dfns.glGenTextures(2, textures);
+ primus.dfns.glEnable(GL_TEXTURE_2D);
+ }
+ else
+ primus.dfns.glGenBuffers(2, pbos);
+ for (;;)
+ {
+ sem_wait(&di.d.acqsem);
+ profiler.tick(true);
+ if (di.d.reinit)
+ {
+ if (di.d.reinit == di.SHUTDOWN)
+ {
+ if (use_textures)
+ primus.dfns.glDeleteTextures(2, textures);
+ else
+ primus.dfns.glDeleteBuffers(2, pbos);
+ primus.dfns.glXMakeCurrent(ddpy, 0, NULL);
+ primus.dfns.glXDestroyContext(ddpy, context);
+ if (ddpy != primus.ddpy)
+ XCloseDisplay(ddpy);
+ sem_post(&di.d.relsem);
+ return NULL;
+ }
+ di.d.reinit = di.NONE;
+ profiler.width = width = di.width;
+ profiler.height = height = di.height;
+ primus.dfns.glViewport(0, 0, width, height);
+ if (use_textures)
+ {
+ primus.dfns.glBindTexture(GL_TEXTURE_2D, textures[ctex ^ 1]);
+ primus.dfns.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ primus.dfns.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ primus.dfns.glBindTexture(GL_TEXTURE_2D, textures[ctex]);
+ primus.dfns.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ primus.dfns.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ }
+ else
+ {
+ primus.dfns.glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, pbos[ctex ^ 1]);
+ primus.dfns.glBufferData(GL_PIXEL_UNPACK_BUFFER_EXT, width*height*4, NULL, GL_STREAM_DRAW);
+ primus.dfns.glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, pbos[ctex]);
+ primus.dfns.glBufferData(GL_PIXEL_UNPACK_BUFFER_EXT, width*height*4, NULL, GL_STREAM_DRAW);
+ }
+ sem_post(&di.d.relsem);
+ continue;
+ }
+ if (use_textures)
+ primus.dfns.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, di.pixeldata);
+ else
+ primus.dfns.glBufferSubData(GL_PIXEL_UNPACK_BUFFER_EXT, 0, width*height*4, di.pixeldata);
+ if (!primus.sync)
+ sem_post(&di.d.relsem); // Unlock as soon as possible
+ profiler.tick();
+ if (use_textures)
+ {
+ primus.dfns.glDrawArrays(GL_QUADS, 0, 4);
+ primus.dfns.glBindTexture(GL_TEXTURE_2D, textures[ctex ^= 1]);
+ }
+ else
+ {
+ primus.dfns.glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ primus.dfns.glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, pbos[ctex ^= 1]);
+ }
+ primus.dfns.glXSwapBuffers(ddpy, di.window);
+ for (int pending = XPending(ddpy); pending > 0; pending--)
+ {
+ XEvent event;
+ XNextEvent(ddpy, &event);
+ if (event.type == ConfigureNotify)
+ di.update_geometry(event.xconfigure.width, event.xconfigure.height);
+ }
+ if (primus.sync)
+ sem_post(&di.d.relsem); // Unlock only after drawing
+ profiler.tick();
+ }
+ return NULL;
+}
+
+static void* readback_work(void *vd)
+{
+ GLXDrawable drawable = (GLXDrawable)vd;
+ DrawableInfo &di = primus.drawables[drawable];
+ int width, height;
+ GLuint pbos[2] = {0};
+ int cbuf = 0;
+ unsigned sleep_usec = 0;
+ static const char *state_names[] = {"app", "sleep", "map", "wait", NULL};
+ Profiler profiler("readback", state_names);
+ struct timespec tp;
+ if (!primus.sync)
+ sem_post(&di.d.relsem); // No PBO is mapped initially
+ GLXContext context = primus.afns.glXCreateNewContext(primus.adpy, di.fbconfig, GLX_RGBA_TYPE, di.actx, True);
+ die_if(!primus.afns.glXIsDirect(primus.adpy, context),
+ "failed to acquire direct rendering context for readback thread\n");
+ primus.afns.glXMakeCurrent(primus.adpy, di.pbuffer, context);
+ primus.afns.glGenBuffers(2, &pbos[0]);
+ primus.afns.glReadBuffer(GL_FRONT);
+ for (;;)
+ {
+ sem_wait(&di.r.acqsem);
+ profiler.tick(true);
+ if (di.r.reinit)
+ {
+ clock_gettime(CLOCK_REALTIME, &tp);
+ tp.tv_sec += 1;
+ // Wait for D worker, if active
+ if (!primus.sync && sem_timedwait(&di.d.relsem, &tp))
+ {
+ pthread_cancel(di.d.worker);
+ sem_post(&di.d.relsem); // Pretend that D worker completed reinit
+ primus_warn("timeout waiting for display worker\n");
+ die_if(di.r.reinit != di.SHUTDOWN, "killed worker on resize\n");
+ }
+ di.d.reinit = di.r.reinit;
+ sem_post(&di.d.acqsem); // Signal D worker to reinit
+ sem_wait(&di.d.relsem); // Wait until reinit was completed
+ if (!primus.sync)
+ sem_post(&di.d.relsem); // Unlock as no PBO is currently mapped
+ if (di.r.reinit == di.SHUTDOWN)
+ {
+ primus.afns.glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, pbos[cbuf ^ 1]);
+ primus.afns.glUnmapBuffer(GL_PIXEL_PACK_BUFFER_EXT);
+ primus.afns.glDeleteBuffers(2, &pbos[0]);
+ primus.afns.glXMakeCurrent(primus.adpy, 0, NULL);
+ primus.afns.glXDestroyContext(primus.adpy, context);
+ sem_post(&di.r.relsem);
+ return NULL;
+ }
+ di.r.reinit = di.NONE;
+ profiler.width = width = di.width;
+ profiler.height = height = di.height;
+ primus.afns.glXMakeCurrent(primus.adpy, di.pbuffer, context);
+ primus.afns.glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, pbos[cbuf ^ 1]);
+ primus.afns.glBufferData(GL_PIXEL_PACK_BUFFER_EXT, width*height*4, NULL, GL_STREAM_READ);
+ primus.afns.glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, pbos[cbuf]);
+ primus.afns.glBufferData(GL_PIXEL_PACK_BUFFER_EXT, width*height*4, NULL, GL_STREAM_READ);
+ }
+ primus.afns.glWaitSync(di.sync, 0, GL_TIMEOUT_IGNORED);
+ primus.afns.glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ if (!primus.sync)
+ sem_post(&di.r.relsem); // Unblock main thread as soon as possible
+ usleep(sleep_usec);
+ profiler.tick();
+ if (primus.sync == 1) // Get the previous framebuffer
+ primus.afns.glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, pbos[cbuf ^ 1]);
+ double map_time = Profiler::get_timestamp();
+ GLvoid *pixeldata = primus.afns.glMapBuffer(GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY);
+ map_time = Profiler::get_timestamp() - map_time;
+ sleep_usec = (map_time * 1e6 + sleep_usec) * primus.autosleep / 100;
+ profiler.tick();
+ clock_gettime(CLOCK_REALTIME, &tp);
+ tp.tv_sec += 1;
+ if (!primus.sync && sem_timedwait(&di.d.relsem, &tp))
+ primus_warn("dropping a frame to avoid deadlock\n");
+ else
+ {
+ di.pixeldata = pixeldata;
+ sem_post(&di.d.acqsem);
+ if (primus.sync)
+ {
+ sem_wait(&di.d.relsem);
+ sem_post(&di.r.relsem); // Unblock main thread only after D::work has completed
+ }
+ cbuf ^= 1;
+ primus.afns.glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, pbos[cbuf]);
+ }
+ primus.afns.glUnmapBuffer(GL_PIXEL_PACK_BUFFER_EXT);
+ profiler.tick();
+ }
+ return NULL;
+}
+
+// Find appropriate FBConfigs on adpy for a given Visual on ddpy
+static GLXFBConfig* match_fbconfig(Display *dpy, XVisualInfo *vis)
+{
+ int ncfg, attrs[] = {
+ GLX_DOUBLEBUFFER, 0, GLX_STEREO, 0, GLX_AUX_BUFFERS, 0,
+ GLX_RED_SIZE, 0, GLX_GREEN_SIZE, 0, GLX_BLUE_SIZE, 0,
+ GLX_ALPHA_SIZE, 0, GLX_DEPTH_SIZE, 0, GLX_STENCIL_SIZE, 0,
+ GLX_ACCUM_RED_SIZE, 0, GLX_ACCUM_GREEN_SIZE, 0, GLX_ACCUM_BLUE_SIZE, 0, GLX_ACCUM_ALPHA_SIZE, 0,
+ GLX_SAMPLE_BUFFERS, 0, GLX_SAMPLES, 0, None
+ };
+ for (int i = 0; attrs[i] != None; i += 2)
+ primus.dfns.glXGetConfig(dpy, vis, attrs[i], &attrs[i+1]);
+ return primus.afns.glXChooseFBConfig(primus.adpy, 0, attrs, &ncfg);
+}
+
+GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct)
+{
+ GLXFBConfig *acfgs = match_fbconfig(dpy, vis);
+ GLXContext actx = primus.afns.glXCreateNewContext(primus.adpy, *acfgs, GLX_RGBA_TYPE, shareList, direct);
+ primus.contexts.record(actx, *acfgs, shareList);
+ return actx;
+}
+
+GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)
+{
+ GLXContext actx = primus.afns.glXCreateNewContext(primus.adpy, config, renderType, shareList, direct);
+ primus.contexts.record(actx, config, shareList);
+ return actx;
+}
+
+GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, GLXContext shareList, Bool direct, const int *attrib_list)
+{
+ GLXContext actx = primus.afns.glXCreateContextAttribsARB(primus.adpy, config, shareList, direct, attrib_list);
+ primus.contexts.record(actx, config, shareList);
+ return actx;
+}
+
+void glXDestroyContext(Display *dpy, GLXContext ctx)
+{
+ primus.contexts.erase(ctx);
+ // kludge: reap background tasks when deleting the last context
+ // otherwise something will deadlock during unloading the library
+ if (primus.contexts.empty())
+ for (DrawablesInfo::iterator i = primus.drawables.begin(); i != primus.drawables.end(); i++)
+ i->second.reap_workers();
+ primus.afns.glXDestroyContext(primus.adpy, ctx);
+}
+
+static GLXPbuffer create_pbuffer(DrawableInfo &di)
+{
+ int pbattrs[] = {GLX_PBUFFER_WIDTH, di.width, GLX_PBUFFER_HEIGHT, di.height, GLX_PRESERVED_CONTENTS, True, None};
+ return primus.afns.glXCreatePbuffer(primus.adpy, di.fbconfig, pbattrs);
+}
+
+// Create or recall backing Pbuffer for the drawable
+static GLXPbuffer lookup_pbuffer(Display *dpy, GLXDrawable draw, GLXContext ctx)
+{
+ if (!draw)
+ return 0;
+ bool known = primus.drawables.known(draw);
+ DrawableInfo &di = primus.drawables[draw];
+ if (!known)
+ {
+ // Drawable is a plain X Window. Get the FBConfig from the context
+ if (ctx)
+ di.fbconfig = primus.contexts[ctx].fbconfig;
+ else
+ {
+ XWindowAttributes attrs;
+ die_if(!XGetWindowAttributes(dpy, draw, &attrs), "failed to query attributes");
+ int nvis;
+ XVisualInfo tmpl = {0}, *vis;
+ tmpl.visualid = XVisualIDFromVisual(attrs.visual);
+ die_if(!(vis = XGetVisualInfo(dpy, VisualIDMask, &tmpl, &nvis)), "no visuals");
+ di.fbconfig = *match_fbconfig(dpy, vis);
+ XFree(vis);
+ }
+ di.kind = di.XWindow;
+ di.window = draw;
+ note_geometry(dpy, draw, &di.width, &di.height);
+ }
+ else if (ctx && di.fbconfig != primus.contexts[ctx].fbconfig)
+ {
+ if (di.pbuffer)
+ {
+ primus_warn("recreating incompatible pbuffer\n");
+ di.reap_workers();
+ primus.afns.glXDestroyPbuffer(primus.adpy, di.pbuffer);
+ di.pbuffer = 0;
+ }
+ di.fbconfig = primus.contexts[ctx].fbconfig;
+ }
+ if (!di.pbuffer)
+ di.pbuffer = create_pbuffer(di);
+ return di.pbuffer;
+}
+
+Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx)
+{
+ GLXPbuffer pbuffer = lookup_pbuffer(dpy, drawable, ctx);
+ tsdata.make_current(dpy, drawable, drawable);
+ return primus.afns.glXMakeCurrent(primus.adpy, pbuffer, ctx);
+}
+
+Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx)
+{
+ if (draw == read)
+ return glXMakeCurrent(dpy, draw, ctx);
+ GLXPbuffer pbuffer = lookup_pbuffer(dpy, draw, ctx);
+ GLXPbuffer pb_read = lookup_pbuffer(dpy, read, ctx);
+ tsdata.make_current(dpy, draw, read);
+ return primus.afns.glXMakeContextCurrent(primus.adpy, pbuffer, pb_read, ctx);
+}
+
+void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
+{
+ XFlush(dpy);
+ assert(primus.drawables.known(drawable));
+ DrawableInfo &di = primus.drawables[drawable];
+ primus.afns.glXSwapBuffers(primus.adpy, di.pbuffer);
+ if (di.kind == di.Pbuffer || di.kind == di.Pixmap)
+ return;
+ GLXContext ctx = glXGetCurrentContext();
+ if (!ctx)
+ primus_warn("glXSwapBuffers: no current context\n");
+ else if (drawable != tsdata.drawable)
+ primus_warn("glXSwapBuffers: drawable not current\n");
+ if (di.r.worker && ctx && (!di.actx || primus.contexts[di.actx].sharegroup != primus.contexts[ctx].sharegroup))
+ {
+ primus_warn("glXSwapBuffers: respawning threads after context change\n");
+ di.reap_workers();
+ }
+ if (!di.r.worker)
+ {
+ // Need to create a sharing context to use GL sync objects
+ di.actx = ctx;
+ di.d.spawn_worker(drawable, display_work);
+ di.r.spawn_worker(drawable, readback_work);
+ }
+ // Readback thread needs a sync object to avoid reading an incomplete frame
+ di.sync = primus.afns.glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ sem_post(&di.r.acqsem); // Signal the readback worker thread
+ sem_wait(&di.r.relsem); // Wait until it has issued glReadBuffer
+ primus.afns.glDeleteSync(di.sync);
+ if (di.reinit == di.RESIZE)
+ {
+ __sync_synchronize();
+ primus.afns.glXDestroyPbuffer(primus.adpy, di.pbuffer);
+ di.pbuffer = create_pbuffer(di);
+ if (ctx) // FIXME: drawable can be current in other threads
+ glXMakeContextCurrent(dpy, tsdata.drawable, tsdata.read_drawable, ctx);
+ di.r.reinit = di.reinit;
+ di.reinit = di.NONE;
+ }
+}
+
+GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, const int *attribList)
+{
+ GLXFBConfig *dconfigs = get_dconfigs(dpy);
+ GLXWindow glxwin = primus.dfns.glXCreateWindow(dpy, *dconfigs, win, attribList);
+ XFree(dconfigs);
+ DrawableInfo &di = primus.drawables[glxwin];
+ di.kind = di.Window;
+ di.fbconfig = config;
+ di.window = win;
+ note_geometry(dpy, win, &di.width, &di.height);
+ return glxwin;
+}
+
+DrawableInfo::~DrawableInfo()
+{
+ reap_workers();
+ if (pbuffer)
+ primus.afns.glXDestroyPbuffer(primus.adpy, pbuffer);
+}
+
+void glXDestroyWindow(Display *dpy, GLXWindow window)
+{
+ assert(primus.drawables.known(window));
+ primus.drawables.erase(window);
+ primus.dfns.glXDestroyWindow(dpy, window);
+}
+
+GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attribList)
+{
+ GLXFBConfig *dconfigs = get_dconfigs(dpy);
+ GLXPbuffer pbuffer = primus.dfns.glXCreatePbuffer(dpy, *dconfigs, attribList);
+ XFree(dconfigs);
+ DrawableInfo &di = primus.drawables[pbuffer];
+ di.kind = di.Pbuffer;
+ di.fbconfig = config;
+ for (int i = 0; attribList[i] != None; i++)
+ if (attribList[i] == GLX_PBUFFER_WIDTH)
+ di.width = attribList[i+1];
+ else if (attribList[i] == GLX_PBUFFER_HEIGHT)
+ di.height = attribList[i+1];
+ return pbuffer;
+}
+
+void glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
+{
+ assert(primus.drawables.known(pbuf));
+ primus.drawables.erase(pbuf);
+ primus.dfns.glXDestroyPbuffer(dpy, pbuf);
+}
+
+GLXPixmap glXCreatePixmap(Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList)
+{
+ GLXFBConfig *dconfigs = get_dconfigs(dpy);
+ GLXPixmap glxpix = primus.dfns.glXCreatePixmap(dpy, *dconfigs, pixmap, attribList);
+ XFree(dconfigs);
+ DrawableInfo &di = primus.drawables[glxpix];
+ di.kind = di.Pixmap;
+ di.fbconfig = config;
+ note_geometry(dpy, pixmap, &di.width, &di.height);
+ return glxpix;
+}
+
+void glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
+{
+ assert(primus.drawables.known(pixmap));
+ primus.drawables.erase(pixmap);
+ primus.dfns.glXDestroyPixmap(dpy, pixmap);
+}
+
+GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *visual, Pixmap pixmap)
+{
+ GLXPixmap glxpix = primus.dfns.glXCreateGLXPixmap(dpy, visual, pixmap);
+ DrawableInfo &di = primus.drawables[glxpix];
+ di.kind = di.Pixmap;
+ note_geometry(dpy, pixmap, &di.width, &di.height);
+ GLXFBConfig *acfgs = match_fbconfig(dpy, visual);
+ di.fbconfig = *acfgs;
+ return glxpix;
+}
+
+void glXDestroyGLXPixmap(Display *dpy, GLXPixmap pixmap)
+{
+ glXDestroyPixmap(dpy, pixmap);
+}
+
+static XVisualInfo *match_visual(Display *dpy, int attrs[])
+{
+ XVisualInfo *vis = glXChooseVisual(dpy, 0, attrs);
+ for (int i = 2; attrs[i] != None && vis; i += 2)
+ {
+ int tmp = attrs[i+1];
+ primus.dfns.glXGetConfig(dpy, vis, attrs[i], &attrs[i+1]);
+ if (tmp != attrs[i+1])
+ vis = NULL;
+ }
+ return vis;
+}
+
+XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
+{
+ if (!primus.afns.glXGetVisualFromFBConfig(primus.adpy, config))
+ return NULL;
+ int i, attrs[] = {
+ GLX_RGBA, GLX_DOUBLEBUFFER,
+ GLX_RED_SIZE, 0, GLX_GREEN_SIZE, 0, GLX_BLUE_SIZE, 0,
+ GLX_ALPHA_SIZE, 0, GLX_DEPTH_SIZE, 0, GLX_STENCIL_SIZE, 0,
+ GLX_SAMPLE_BUFFERS, 0, GLX_SAMPLES, 0, None
+ };
+ for (i = 2; attrs[i] != None; i += 2)
+ primus.afns.glXGetFBConfigAttrib(primus.adpy, config, attrs[i], &attrs[i+1]);
+ XVisualInfo *vis = NULL;
+ for (i -= 2; i >= 0 && !vis; i -= 2)
+ {
+ vis = match_visual(dpy, attrs);
+ attrs[i] = None;
+ }
+ return vis;
+}
+
+int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config, int attribute, int *value)
+{
+ int r = primus.afns.glXGetFBConfigAttrib(primus.adpy, config, attribute, value);
+ if (attribute == GLX_VISUAL_ID && *value)
+ return primus.dfns.glXGetConfig(dpy, glXGetVisualFromFBConfig(dpy, config), attribute, value);
+ return r;
+}
+
+void glXQueryDrawable(Display *dpy, GLXDrawable draw, int attribute, unsigned int *value)
+{
+ primus.afns.glXQueryDrawable(primus.adpy, lookup_pbuffer(dpy, draw, NULL), attribute, value);
+}
+
+void glXUseXFont(Font font, int first, int count, int list)
+{
+ unsigned long prop;
+ Display *dpy = glXGetCurrentDisplay();
+ XFontStruct *fs = XQueryFont(dpy, font);
+ XGetFontProperty(fs, XA_FONT, &prop);
+ char *xlfd = XGetAtomName(dpy, prop);
+ Font afont = XLoadFont(primus.adpy, xlfd);
+ primus.afns.glXUseXFont(afont, first, count, list);
+ XUnloadFont(primus.adpy, afont);
+ XFree(xlfd);
+ XFreeFontInfo(NULL, fs, 1);
+}
+
+GLXContext glXGetCurrentContext(void)
+{
+ return primus.afns.glXGetCurrentContext();
+}
+
+GLXDrawable glXGetCurrentDrawable(void)
+{
+ return tsdata.drawable;
+}
+
+void glXWaitGL(void)
+{
+}
+
+void glXWaitX(void)
+{
+}
+
+Display *glXGetCurrentDisplay(void)
+{
+ return tsdata.dpy;
+}
+
+GLXDrawable glXGetCurrentReadDrawable(void)
+{
+ return tsdata.read_drawable;
+}
+
+// Application sees ddpy-side Visuals, but adpy-side FBConfigs and Contexts
+XVisualInfo* glXChooseVisual(Display *dpy, int screen, int *attribList)
+{
+ return primus.dfns.glXChooseVisual(dpy, screen, attribList);
+}
+
+int glXGetConfig(Display *dpy, XVisualInfo *visual, int attrib, int *value)
+{
+ return primus.dfns.glXGetConfig(dpy, visual, attrib, value);
+}
+
+// GLX forwarders that reroute to adpy
+#define DEF_GLX_PROTO(ret, name, par, ...) \
+ret name par \
+{ return primus.afns.name(primus.adpy, __VA_ARGS__); }
+#include "glx-dpyredir.def"
+#undef DEF_GLX_PROTO
+
+// OpenGL forwarders
+#define DEF_GLX_PROTO(ret, name, par, ...) \
+void ifunc_##name(void) asm(#name) __attribute__((visibility("default"),ifunc("i" #name))); \
+extern "C" { \
+static ret l##name par \
+{ return primus.afns.name(__VA_ARGS__); } \
+static void *i##name(void) \
+{ return primus.afns.handle ? real_dlsym(primus.afns.handle, #name) : (void*)l##name; } }
+#include "gl-passthru.def"
+#undef DEF_GLX_PROTO
+
+// GLX extensions
+
+int glXSwapIntervalSGI(int interval)
+{
+ return 1; // Indicate failure to set swapinterval
+}
+
+__GLXextFuncPtr glXGetProcAddress(const GLubyte *procName)
+{
+ static const char * const redefined_names[] = {
+#define DEF_GLX_PROTO(ret, name, args, ...) #name,
+#include "glx-reimpl.def"
+#include "glxext-reimpl.def"
+#include "glx-dpyredir.def"
+#undef DEF_GLX_PROTO
+ };
+ static const __GLXextFuncPtr redefined_fns[] = {
+#define DEF_GLX_PROTO(ret, name, args, ...) (__GLXextFuncPtr)name,
+#include "glx-reimpl.def"
+#include "glxext-reimpl.def"
+#include "glx-dpyredir.def"
+#undef DEF_GLX_PROTO
+ };
+ enum {n_redefined = sizeof(redefined_fns) / sizeof(redefined_fns[0])};
+ // Non-GLX functions are forwarded to the accelerating libGL
+ if (memcmp(procName, "glX", 3))
+ return primus.afns.glXGetProcAddress(procName);
+ // All GLX functions are either implemented in primus or not available
+ for (int i = 0; i < n_redefined; i++)
+ if (!strcmp((const char *)procName, redefined_names[i]))
+ return redefined_fns[i];
+ return NULL;
+}
+
+__GLXextFuncPtr glXGetProcAddressARB(const GLubyte *procName)
+{
+ return glXGetProcAddress(procName);
+}
+
+static const char glxext_clientside[] = "GLX_ARB_get_proc_address ";
+static const char glxext_adpy[] = "GLX_ARB_create_context GLX_ARB_create_context_profile ";
+static const char glxext_ddpy[] = "";
+
+const char *glXGetClientString(Display *dpy, int name)
+{
+ static std::string exts(std::string(glxext_clientside) + glxext_adpy + glxext_ddpy);
+ switch (name)
+ {
+ case GLX_VENDOR: return "primus";
+ case GLX_VERSION: return "1.4";
+ case GLX_EXTENSIONS: return exts.c_str();
+ default: return NULL;
+ }
+}
+
+static std::string intersect_exts(const char *set1, const char *set2)
+{
+ std::string r;
+ for (const char *p; *set1; set1 = p + 1)
+ {
+ p = strchr(set1, ' ');
+ if (memmem(set2, strlen(set2), set1, p - set1))
+ r.append(set1, p - set1 + 1);
+ }
+ return r;
+}
+
+const char *glXQueryExtensionsString(Display *dpy, int screen)
+{
+ static std::string exts
+ (std::string(glxext_clientside)
+ + intersect_exts(glxext_adpy, primus.afns.glXQueryExtensionsString(primus.adpy, 0))
+ + intersect_exts(glxext_ddpy, primus.dfns.glXQueryExtensionsString(dpy, 0)));
+ return exts.c_str();
+}
+
+// OpenGL ABI specifies that anything above OpenGL 1.2 + ARB_multitexture must
+// be obtained via glXGetProcAddress, but some applications link against
+// extension functions, and Mesa and vendor libraries let them
+#ifndef PRIMUS_STRICT
+#warning Enabled workarounds for applications demanding more than promised by the OpenGL ABI
+
+// OpenGL extension forwarders
+#define P(name) \
+void ifunc_##name(void) asm(#name) __attribute__((visibility("default"),ifunc("i" #name))); \
+extern "C" { static void *i##name(void) \
+{ return primus.afns.handle ? real_dlsym(primus.afns.handle, #name) : NULL; } }
+#include "glext-passthru.def"
+#undef P
+#endif