From dd6ca0976dc6bf1b3d1dedc67b3120c96e5ddcab Mon Sep 17 00:00:00 2001 From: Vincent Cheng Date: Wed, 15 Jan 2014 22:14:25 +0000 Subject: [PATCH 1/1] Import primus_0~20140711.orig.tar.gz [dgit import orig primus_0~20140711.orig.tar.gz] --- .gitignore | 3 + LICENSE.txt | 13 + Makefile | 33 ++ README.md | 73 +++ gl-needed.def | 12 + gl-passthru.def | 455 ++++++++++++++++++ glext-passthru.def | 803 +++++++++++++++++++++++++++++++ glx-dpyredir.def | 11 + glx-reimpl.def | 36 ++ glxext-reimpl.def | 3 + libglfork.cpp | 1015 ++++++++++++++++++++++++++++++++++++++++ primus.bash-completion | 1 + primusrun | 42 ++ primusrun.1 | 51 ++ technotes.md | 180 +++++++ 15 files changed, 2731 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 README.md create mode 100644 gl-needed.def create mode 100644 gl-passthru.def create mode 100644 glext-passthru.def create mode 100644 glx-dpyredir.def create mode 100644 glx-reimpl.def create mode 100644 glxext-reimpl.def create mode 100644 libglfork.cpp create mode 100644 primus.bash-completion create mode 100755 primusrun create mode 100644 primusrun.1 create mode 100644 technotes.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63ad451 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +lib +lib32 +lib64 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..c3a839a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright (c) 2012, Alexander Monakov + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL 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 +PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..86743f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +CXX ?= g++ +CXXFLAGS ?= -Wall -g + +CXXFLAGS += -Werror=missing-declarations +CXXFLAGS += -Werror=attributes + +# On multilib systems, this needs to point to distribution-specific library +# subdir like in /usr (lib or lib64 for 64-bit, lib32 or lib for 32-bit) +LIBDIR ?= lib + +BUMBLEBEE_SOCKET ?= /var/run/bumblebee.socket +PRIMUS_SYNC ?= 0 +PRIMUS_VERBOSE ?= 1 +PRIMUS_UPLOAD ?= 0 +PRIMUS_SLEEP ?= 90 +PRIMUS_DISPLAY ?= :8 +PRIMUS_LOAD_GLOBAL ?= libglapi.so.0 +PRIMUS_libGLa ?= /usr/$$LIB/nvidia/libGL.so.1 +PRIMUS_libGLd ?= /usr/$$LIB/libGL.so.1 + +CXXFLAGS += -DBUMBLEBEE_SOCKET='"$(BUMBLEBEE_SOCKET)"' +CXXFLAGS += -DPRIMUS_SYNC='"$(PRIMUS_SYNC)"' +CXXFLAGS += -DPRIMUS_VERBOSE='"$(PRIMUS_VERBOSE)"' +CXXFLAGS += -DPRIMUS_UPLOAD='"$(PRIMUS_UPLOAD)"' +CXXFLAGS += -DPRIMUS_SLEEP='"$(PRIMUS_SLEEP)"' +CXXFLAGS += -DPRIMUS_DISPLAY='"$(PRIMUS_DISPLAY)"' +CXXFLAGS += -DPRIMUS_LOAD_GLOBAL='"$(PRIMUS_LOAD_GLOBAL)"' +CXXFLAGS += -DPRIMUS_libGLa='"$(PRIMUS_libGLa)"' +CXXFLAGS += -DPRIMUS_libGLd='"$(PRIMUS_libGLd)"' + +$(LIBDIR)/libGL.so.1: libglfork.cpp + mkdir -p $(LIBDIR) + $(CXX) $(CXXFLAGS) -fvisibility=hidden -fPIC -shared -Wl,-Bsymbolic -o $@ $< -lX11 -lpthread -lrt diff --git a/README.md b/README.md new file mode 100644 index 0000000..6adfd30 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +primus +====== + +Primus is a shared library that provides OpenGL and GLX APIs and +implements low-overhead +local-only client-side OpenGL offloading via GLX forking, similar to +VirtualGL. It intercepts GLX calls and redirects GL rendering to a +secondary X display, presumably driven by a faster GPU. On swapping +buffers, rendered contents are read back using a PBO and copied onto +the drawable it was supposed to be rendered on in the first place. +For more information, refer to [technotes.md] +(https://github.com/amonakov/primus/blob/master/technotes.md). + +To use, install or build from source and use `primusrun` wrapper script. + +In distributions +---------------- + +* Arch: [primus-git](https://aur.archlinux.org/packages.php?ID=63239) + and [lib32-primus-git](https://aur.archlinux.org/packages.php?ID=63240) + in AUR +* Gentoo: `primus-9999.ebuild` in the `bumblebee` overlay +* Ubuntu: in the [Bumblebee PPA](https://launchpad.net/~bumblebee/+archive/stable) + +Building for multilib (32-bit + 64-bit) systems +----------------------------------------------- + + LIBDIR=lib make && CXX=g++\ -m32 LIBDIR=lib32 make + +Adjust `LIBDIR` variables above as appropriate for your distribution +(reflecting how `/usr/lib*` are named): + +* Arch needs `lib` and `lib32` as above +* Gentoo needs `lib64` and `lib32` +* RPM-based may need `lib64` and `lib` +* Debian (with multiarch) needs `lib/x86_64-linux-gnu` and `lib/i386-linux-gnu` +* Ubuntu (with multiarch) seems rather inconsistent. The dynamic linker + expands `$LIB` to `x86_64-linux-gnu`/`i386-linux-gnu` (without `lib/`), but + Nvidia drivers are installed into `/usr/lib{,32}/nvidia-current`. Something + like the following is needed: + + export PRIMUS_libGLd='/usr/lib/$$LIB/mesa/libGL.so.1' + LIBDIR=x86_64-linux-gnu make + LIBDIR=i386-linux-gnu CXX=g++\ -m32 make + unset PRIMUS_libGLd + + Starting from 13.04, Ubuntu needs the same `LIBDIR` paths as Debian (with + leading `lib/`); consequently, `lib/` in `PRIMUS_libGLd` should be omitted. + + Furthermore, `libnvidia-tls.so` is not present in default shared library + search directories. Uncomment the corresponding line in `primusrun`. + +Issues under compositing WMs +---------------------------- + +Since compositing hurts performance, invoking primus when a compositing WM is +active is not recommended. If you need to use primus with compositing and see +flickering or bad performance, synchronizing primus' display thread with the +application's rendering thread may help (can anyone investigate why?): + + PRIMUS_SYNC=1 primusrun ... + +This makes primus display the previously rendered frame. Alternatively, +with `PRIMUS_SYNC=2` primus will display the latest rendered frame, trading +frame rate for reduced visual latency. + +FAQ +--- + +Q: Performance does not exceed 60 fps, I was getting more with optirun/VirtualGL. +A: This is the effect of vblank synchronisation. For benchmarking, you can use +`vblank_mode=0 primusrun ...`, but in practice this will probably only waste power, +as your LCD panel does not display more than 60 frames per second anyway. diff --git a/gl-needed.def b/gl-needed.def new file mode 100644 index 0000000..907eed6 --- /dev/null +++ b/gl-needed.def @@ -0,0 +1,12 @@ +// OpenGL extension functions needed by primus itself +DEF_GLX_PROTO(void, glGenBuffers, (GLsizei n, GLuint *buffers)) +DEF_GLX_PROTO(void, glDeleteBuffers, (GLsizei n, const GLuint *buffers)) +DEF_GLX_PROTO(void, glBindBuffer, (GLenum target, GLuint buffer)) +DEF_GLX_PROTO(void, glBufferData, (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)) +DEF_GLX_PROTO(void, glBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)) +DEF_GLX_PROTO(GLvoid*, glMapBuffer, (GLenum target, GLenum access)) +DEF_GLX_PROTO(GLboolean,glUnmapBuffer,(GLenum target)) + +DEF_GLX_PROTO(GLsync, glFenceSync, (GLenum condition, GLbitfield flags)) +DEF_GLX_PROTO(void, glDeleteSync,(GLsync sync)) +DEF_GLX_PROTO(void, glWaitSync, (GLsync sync, GLbitfield flags, GLuint64 timeout)) diff --git a/gl-passthru.def b/gl-passthru.def new file mode 100644 index 0000000..8dcddae --- /dev/null +++ b/gl-passthru.def @@ -0,0 +1,455 @@ +// 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) diff --git a/glext-passthru.def b/glext-passthru.def new file mode 100644 index 0000000..2b7fba5 --- /dev/null +++ b/glext-passthru.def @@ -0,0 +1,803 @@ +P(glActiveProgramEXT) +P(glAlphaFragmentOp1ATI) +P(glAlphaFragmentOp2ATI) +P(glAlphaFragmentOp3ATI) +P(glAreProgramsResidentNV) +P(glAreTexturesResidentEXT) +P(glArrayElementEXT) +P(glAttachObjectARB) +P(glAttachShader) +P(glBeginConditionalRender) +P(glBeginConditionalRenderNV) +P(glBeginFragmentShaderATI) +P(glBeginQuery) +P(glBeginQueryARB) +P(glBeginQueryIndexed) +P(glBeginTransformFeedback) +P(glBeginTransformFeedbackEXT) +P(glBindAttribLocation) +P(glBindAttribLocationARB) +P(glBindBuffer) +P(glBindBufferARB) +P(glBindBufferBase) +P(glBindBufferBaseEXT) +P(glBindBufferOffsetEXT) +P(glBindBufferRange) +P(glBindBufferRangeEXT) +P(glBindFragDataLocation) +P(glBindFragDataLocationEXT) +P(glBindFragDataLocationIndexed) +P(glBindFragmentShaderATI) +P(glBindFramebuffer) +P(glBindFramebufferEXT) +P(glBindProgramARB) +P(glBindProgramNV) +P(glBindRenderbuffer) +P(glBindRenderbufferEXT) +P(glBindSampler) +P(glBindTextureEXT) +P(glBindTransformFeedback) +P(glBindVertexArray) +P(glBindVertexArrayOES) +P(glBlendColorEXT) +P(glBlendEquationEXT) +P(glBlendEquationIndexedAMD) +P(glBlendEquationSeparate) +P(glBlendEquationSeparateIndexedAMD) +P(glBlendEquationSeparateiARB) +P(glBlendEquationiARB) +P(glBlendFuncIndexedAMD) +P(glBlendFuncSeparate) +P(glBlendFuncSeparateEXT) +P(glBlendFuncSeparateIndexedAMD) +P(glBlendFuncSeparateiARB) +P(glBlendFunciARB) +P(glBlitFramebuffer) +P(glBufferData) +P(glBufferDataARB) +P(glBufferSubData) +P(glBufferSubDataARB) +P(glCheckFramebufferStatus) +P(glCheckFramebufferStatusEXT) +P(glClampColor) +P(glClampColorARB) +P(glClearBufferfi) +P(glClearBufferfv) +P(glClearBufferiv) +P(glClearBufferuiv) +P(glClearColorIiEXT) +P(glClearColorIuiEXT) +P(glClearDepthf) +P(glClientWaitSync) +P(glColorFragmentOp1ATI) +P(glColorFragmentOp2ATI) +P(glColorFragmentOp3ATI) +P(glColorMaskIndexedEXT) +P(glColorMaski) +P(glColorP3ui) +P(glColorP3uiv) +P(glColorP4ui) +P(glColorP4uiv) +P(glColorPointerEXT) +P(glColorTableEXT) +P(glCompileShader) +P(glCompileShaderARB) +P(glCompressedTexImage1DARB) +P(glCompressedTexImage2DARB) +P(glCompressedTexImage3DARB) +P(glCompressedTexSubImage1DARB) +P(glCompressedTexSubImage2DARB) +P(glCompressedTexSubImage3DARB) +P(glCopyBufferSubData) +P(glCopyTexImage1DEXT) +P(glCopyTexImage2DEXT) +P(glCopyTexSubImage1DEXT) +P(glCopyTexSubImage2DEXT) +P(glCopyTexSubImage3DEXT) +P(glCreateProgram) +P(glCreateProgramObjectARB) +P(glCreateShader) +P(glCreateShaderObjectARB) +P(glCreateShaderProgramEXT) +P(glDebugMessageCallbackARB) +P(glDebugMessageControlARB) +P(glDebugMessageInsertARB) +P(glDeleteBuffers) +P(glDeleteBuffersARB) +P(glDeleteFragmentShaderATI) +P(glDeleteFramebuffers) +P(glDeleteFramebuffersEXT) +P(glDeleteObjectARB) +P(glDeleteProgram) +P(glDeleteProgramsARB) +P(glDeleteProgramsNV) +P(glDeleteQueries) +P(glDeleteQueriesARB) +P(glDeleteRenderbuffers) +P(glDeleteRenderbuffersEXT) +P(glDeleteSamplers) +P(glDeleteShader) +P(glDeleteSync) +P(glDeleteTexturesEXT) +P(glDeleteTransformFeedbacks) +P(glDeleteVertexArrays) +P(glDeleteVertexArraysOES) +P(glDepthRangef) +P(glDetachObjectARB) +P(glDetachShader) +P(glDisableIndexedEXT) +P(glDisableVertexAttribArray) +P(glDisableVertexAttribArrayARB) +P(glDisablei) +P(glDrawArraysEXT) +P(glDrawArraysInstanced) +P(glDrawArraysInstancedARB) +P(glDrawArraysInstancedBaseInstance) +P(glDrawArraysInstancedEXT) +P(glDrawBuffers) +P(glDrawBuffersARB) +P(glDrawBuffersATI) +P(glDrawBuffersNV) +P(glDrawElementsBaseVertex) +P(glDrawElementsInstanced) +P(glDrawElementsInstancedARB) +P(glDrawElementsInstancedBaseInstance) +P(glDrawElementsInstancedBaseVertex) +P(glDrawElementsInstancedBaseVertexBaseInstance) +P(glDrawElementsInstancedEXT) +P(glDrawRangeElementsBaseVertex) +P(glDrawRangeElementsEXT) +P(glDrawTransformFeedback) +P(glDrawTransformFeedbackInstanced) +P(glDrawTransformFeedbackStream) +P(glDrawTransformFeedbackStreamInstanced) +P(glEGLImageTargetRenderbufferStorageOES) +P(glEGLImageTargetTexture2DOES) +P(glEdgeFlagPointerEXT) +P(glEnableIndexedEXT) +P(glEnableVertexAttribArray) +P(glEnableVertexAttribArrayARB) +P(glEnablei) +P(glEndConditionalRender) +P(glEndConditionalRenderNV) +P(glEndFragmentShaderATI) +P(glEndQuery) +P(glEndQueryARB) +P(glEndQueryIndexed) +P(glEndTransformFeedback) +P(glEndTransformFeedbackEXT) +P(glExecuteProgramNV) +P(glFenceSync) +P(glFlushMappedBufferRange) +P(glFogCoordPointer) +P(glFogCoordPointerEXT) +P(glFogCoordd) +P(glFogCoorddEXT) +P(glFogCoorddv) +P(glFogCoorddvEXT) +P(glFogCoordf) +P(glFogCoordfEXT) +P(glFogCoordfv) +P(glFogCoordfvEXT) +P(glFramebufferRenderbuffer) +P(glFramebufferRenderbufferEXT) +P(glFramebufferTexture) +P(glFramebufferTexture1D) +P(glFramebufferTexture1DEXT) +P(glFramebufferTexture2D) +P(glFramebufferTexture2DEXT) +P(glFramebufferTexture3D) +P(glFramebufferTexture3DEXT) +P(glFramebufferTextureARB) +P(glFramebufferTextureFaceARB) +P(glFramebufferTextureLayer) +P(glFramebufferTextureLayerARB) +P(glFramebufferTextureLayerEXT) +P(glGenBuffers) +P(glGenBuffersARB) +P(glGenFragmentShadersATI) +P(glGenFramebuffers) +P(glGenFramebuffersEXT) +P(glGenProgramsARB) +P(glGenProgramsNV) +P(glGenQueries) +P(glGenQueriesARB) +P(glGenRenderbuffers) +P(glGenRenderbuffersEXT) +P(glGenSamplers) +P(glGenTexturesEXT) +P(glGenTransformFeedbacks) +P(glGenVertexArrays) +P(glGenVertexArraysOES) +P(glGenerateMipmap) +P(glGenerateMipmapEXT) +P(glGetActiveAttrib) +P(glGetActiveAttribARB) +P(glGetActiveUniform) +P(glGetActiveUniformARB) +P(glGetActiveUniformBlockName) +P(glGetActiveUniformBlockiv) +P(glGetActiveUniformName) +P(glGetActiveUniformsiv) +P(glGetAttachedObjectsARB) +P(glGetAttachedShaders) +P(glGetAttribLocation) +P(glGetAttribLocationARB) +P(glGetBooleanIndexedvEXT) +P(glGetBooleani_v) +P(glGetBufferParameteri64v) +P(glGetBufferParameteriv) +P(glGetBufferParameterivARB) +P(glGetBufferPointerv) +P(glGetBufferPointervARB) +P(glGetBufferSubData) +P(glGetBufferSubDataARB) +P(glGetColorTableEXT) +P(glGetColorTableParameterfvEXT) +P(glGetColorTableParameterivEXT) +P(glGetCompressedTexImageARB) +P(glGetDebugMessageLogARB) +P(glGetFragDataIndex) +P(glGetFragDataLocation) +P(glGetFragDataLocationEXT) +P(glGetFramebufferAttachmentParameteriv) +P(glGetFramebufferAttachmentParameterivEXT) +P(glGetGraphicsResetStatusARB) +P(glGetHandleARB) +P(glGetInfoLogARB) +P(glGetInteger64i_v) +P(glGetInteger64v) +P(glGetIntegerIndexedvEXT) +P(glGetIntegeri_v) +P(glGetObjectParameterfvARB) +P(glGetObjectParameterivAPPLE) +P(glGetObjectParameterivARB) +P(glGetPointervEXT) +P(glGetProgramEnvParameterdvARB) +P(glGetProgramEnvParameterfvARB) +P(glGetProgramInfoLog) +P(glGetProgramLocalParameterdvARB) +P(glGetProgramLocalParameterfvARB) +P(glGetProgramNamedParameterdvNV) +P(glGetProgramNamedParameterfvNV) +P(glGetProgramParameterdvNV) +P(glGetProgramParameterfvNV) +P(glGetProgramStringARB) +P(glGetProgramStringNV) +P(glGetProgramiv) +P(glGetProgramivARB) +P(glGetProgramivNV) +P(glGetQueryIndexediv) +P(glGetQueryObjectiv) +P(glGetQueryObjectivARB) +P(glGetQueryObjectuiv) +P(glGetQueryObjectuivARB) +P(glGetQueryiv) +P(glGetQueryivARB) +P(glGetRenderbufferParameteriv) +P(glGetRenderbufferParameterivEXT) +P(glGetSamplerParameterIiv) +P(glGetSamplerParameterIuiv) +P(glGetSamplerParameterfv) +P(glGetSamplerParameteriv) +P(glGetShaderInfoLog) +P(glGetShaderPrecisionFormat) +P(glGetShaderSource) +P(glGetShaderSourceARB) +P(glGetShaderiv) +P(glGetStringi) +P(glGetSynciv) +P(glGetTexBumpParameterfvATI) +P(glGetTexBumpParameterivATI) +P(glGetTexParameterIiv) +P(glGetTexParameterIivEXT) +P(glGetTexParameterIuiv) +P(glGetTexParameterIuivEXT) +P(glGetTrackMatrixivNV) +P(glGetTransformFeedbackVarying) +P(glGetTransformFeedbackVaryingEXT) +P(glGetUniformBlockIndex) +P(glGetUniformIndices) +P(glGetUniformLocation) +P(glGetUniformLocationARB) +P(glGetUniformfv) +P(glGetUniformfvARB) +P(glGetUniformiv) +P(glGetUniformivARB) +P(glGetUniformuiv) +P(glGetUniformuivEXT) +P(glGetVertexAttribIiv) +P(glGetVertexAttribIivEXT) +P(glGetVertexAttribIuiv) +P(glGetVertexAttribIuivEXT) +P(glGetVertexAttribPointerv) +P(glGetVertexAttribPointervARB) +P(glGetVertexAttribPointervNV) +P(glGetVertexAttribdv) +P(glGetVertexAttribdvARB) +P(glGetVertexAttribdvNV) +P(glGetVertexAttribfv) +P(glGetVertexAttribfvARB) +P(glGetVertexAttribfvNV) +P(glGetVertexAttribiv) +P(glGetVertexAttribivARB) +P(glGetVertexAttribivNV) +P(glGetnColorTableARB) +P(glGetnCompressedTexImageARB) +P(glGetnConvolutionFilterARB) +P(glGetnHistogramARB) +P(glGetnMapdvARB) +P(glGetnMapfvARB) +P(glGetnMapivARB) +P(glGetnMinmaxARB) +P(glGetnPixelMapfvARB) +P(glGetnPixelMapuivARB) +P(glGetnPixelMapusvARB) +P(glGetnPolygonStippleARB) +P(glGetnSeparableFilterARB) +P(glGetnTexImageARB) +P(glGetnUniformdvARB) +P(glGetnUniformfvARB) +P(glGetnUniformivARB) +P(glGetnUniformuivARB) +P(glIndexPointerEXT) +P(glInvalidateBufferData) +P(glInvalidateBufferSubData) +P(glInvalidateFramebuffer) +P(glInvalidateSubFramebuffer) +P(glInvalidateTexImage) +P(glInvalidateTexSubImage) +P(glIsBuffer) +P(glIsBufferARB) +P(glIsEnabledIndexedEXT) +P(glIsEnabledi) +P(glIsFramebuffer) +P(glIsFramebufferEXT) +P(glIsProgram) +P(glIsProgramARB) +P(glIsProgramNV) +P(glIsQuery) +P(glIsQueryARB) +P(glIsRenderbuffer) +P(glIsRenderbufferEXT) +P(glIsSampler) +P(glIsShader) +P(glIsSync) +P(glIsTextureEXT) +P(glIsTransformFeedback) +P(glIsVertexArray) +P(glIsVertexArrayOES) +P(glLinkProgram) +P(glLinkProgramARB) +P(glLoadProgramNV) +P(glLoadTransposeMatrixdARB) +P(glLoadTransposeMatrixfARB) +P(glLockArraysEXT) +P(glMapBuffer) +P(glMapBufferARB) +P(glMapBufferRange) +P(glMultTransposeMatrixdARB) +P(glMultTransposeMatrixfARB) +P(glMultiDrawArrays) +P(glMultiDrawArraysEXT) +P(glMultiDrawElements) +P(glMultiDrawElementsBaseVertex) +P(glMultiDrawElementsEXT) +P(glMultiTexCoordP1ui) +P(glMultiTexCoordP1uiv) +P(glMultiTexCoordP2ui) +P(glMultiTexCoordP2uiv) +P(glMultiTexCoordP3ui) +P(glMultiTexCoordP3uiv) +P(glMultiTexCoordP4ui) +P(glMultiTexCoordP4uiv) +P(glNormalP3ui) +P(glNormalP3uiv) +P(glNormalPointerEXT) +P(glObjectPurgeableAPPLE) +P(glObjectUnpurgeableAPPLE) +P(glPassTexCoordATI) +P(glPauseTransformFeedback) +P(glPointParameterf) +P(glPointParameterfARB) +P(glPointParameterfEXT) +P(glPointParameterfv) +P(glPointParameterfvARB) +P(glPointParameterfvEXT) +P(glPointParameteri) +P(glPointParameteriNV) +P(glPointParameteriv) +P(glPointParameterivNV) +P(glPolygonOffsetEXT) +P(glPrimitiveRestartIndex) +P(glPrimitiveRestartIndexNV) +P(glPrimitiveRestartNV) +P(glPrioritizeTexturesEXT) +P(glProgramEnvParameter4dARB) +P(glProgramEnvParameter4dvARB) +P(glProgramEnvParameter4fARB) +P(glProgramEnvParameter4fvARB) +P(glProgramLocalParameter4dARB) +P(glProgramLocalParameter4dvARB) +P(glProgramLocalParameter4fARB) +P(glProgramLocalParameter4fvARB) +P(glProgramNamedParameter4dNV) +P(glProgramNamedParameter4dvNV) +P(glProgramNamedParameter4fNV) +P(glProgramNamedParameter4fvNV) +P(glProgramParameter4dNV) +P(glProgramParameter4dvNV) +P(glProgramParameter4fNV) +P(glProgramParameter4fvNV) +P(glProgramParameteriARB) +P(glProgramParameters4dvNV) +P(glProgramParameters4fvNV) +P(glProgramStringARB) +P(glProvokingVertex) +P(glProvokingVertexEXT) +P(glReadBufferNV) +P(glReadnPixelsARB) +P(glReleaseShaderCompiler) +P(glRenderbufferStorage) +P(glRenderbufferStorageEXT) +P(glRenderbufferStorageMultisample) +P(glRenderbufferStorageMultisampleEXT) +P(glRequestResidentProgramsNV) +P(glResumeTransformFeedback) +P(glSampleCoverageARB) +P(glSampleMapATI) +P(glSamplerParameterIiv) +P(glSamplerParameterIuiv) +P(glSamplerParameterf) +P(glSamplerParameterfv) +P(glSamplerParameteri) +P(glSamplerParameteriv) +P(glSecondaryColor3b) +P(glSecondaryColor3bEXT) +P(glSecondaryColor3bv) +P(glSecondaryColor3bvEXT) +P(glSecondaryColor3d) +P(glSecondaryColor3dEXT) +P(glSecondaryColor3dv) +P(glSecondaryColor3dvEXT) +P(glSecondaryColor3f) +P(glSecondaryColor3fEXT) +P(glSecondaryColor3fv) +P(glSecondaryColor3fvEXT) +P(glSecondaryColor3i) +P(glSecondaryColor3iEXT) +P(glSecondaryColor3iv) +P(glSecondaryColor3ivEXT) +P(glSecondaryColor3s) +P(glSecondaryColor3sEXT) +P(glSecondaryColor3sv) +P(glSecondaryColor3svEXT) +P(glSecondaryColor3ub) +P(glSecondaryColor3ubEXT) +P(glSecondaryColor3ubv) +P(glSecondaryColor3ubvEXT) +P(glSecondaryColor3ui) +P(glSecondaryColor3uiEXT) +P(glSecondaryColor3uiv) +P(glSecondaryColor3uivEXT) +P(glSecondaryColor3us) +P(glSecondaryColor3usEXT) +P(glSecondaryColor3usv) +P(glSecondaryColor3usvEXT) +P(glSecondaryColorP3ui) +P(glSecondaryColorP3uiv) +P(glSecondaryColorPointer) +P(glSecondaryColorPointerEXT) +P(glSetFragmentShaderConstantATI) +P(glShaderBinary) +P(glShaderSource) +P(glShaderSourceARB) +P(glStencilFuncSeparate) +P(glStencilMaskSeparate) +P(glStencilOpSeparate) +P(glTexBuffer) +P(glTexBufferARB) +P(glTexBumpParameterfvATI) +P(glTexBumpParameterivATI) +P(glTexCoordP1ui) +P(glTexCoordP1uiv) +P(glTexCoordP2ui) +P(glTexCoordP2uiv) +P(glTexCoordP3ui) +P(glTexCoordP3uiv) +P(glTexCoordP4ui) +P(glTexCoordP4uiv) +P(glTexCoordPointerEXT) +P(glTexImage3DEXT) +P(glTexParameterIiv) +P(glTexParameterIivEXT) +P(glTexParameterIuiv) +P(glTexParameterIuivEXT) +P(glTexStorage1D) +P(glTexStorage2D) +P(glTexStorage3D) +P(glTexSubImage1DEXT) +P(glTexSubImage2DEXT) +P(glTexSubImage3DEXT) +P(glTextureBarrierNV) +P(glTextureStorage1DEXT) +P(glTextureStorage2DEXT) +P(glTextureStorage3DEXT) +P(glTrackMatrixNV) +P(glTransformFeedbackVaryings) +P(glTransformFeedbackVaryingsEXT) +P(glUniform1f) +P(glUniform1fARB) +P(glUniform1fv) +P(glUniform1fvARB) +P(glUniform1i) +P(glUniform1iARB) +P(glUniform1iv) +P(glUniform1ivARB) +P(glUniform1ui) +P(glUniform1uiEXT) +P(glUniform1uiv) +P(glUniform1uivEXT) +P(glUniform2f) +P(glUniform2fARB) +P(glUniform2fv) +P(glUniform2fvARB) +P(glUniform2i) +P(glUniform2iARB) +P(glUniform2iv) +P(glUniform2ivARB) +P(glUniform2ui) +P(glUniform2uiEXT) +P(glUniform2uiv) +P(glUniform2uivEXT) +P(glUniform3f) +P(glUniform3fARB) +P(glUniform3fv) +P(glUniform3fvARB) +P(glUniform3i) +P(glUniform3iARB) +P(glUniform3iv) +P(glUniform3ivARB) +P(glUniform3ui) +P(glUniform3uiEXT) +P(glUniform3uiv) +P(glUniform3uivEXT) +P(glUniform4f) +P(glUniform4fARB) +P(glUniform4fv) +P(glUniform4fvARB) +P(glUniform4i) +P(glUniform4iARB) +P(glUniform4iv) +P(glUniform4ivARB) +P(glUniform4ui) +P(glUniform4uiEXT) +P(glUniform4uiv) +P(glUniform4uivEXT) +P(glUniformBlockBinding) +P(glUniformMatrix2fv) +P(glUniformMatrix2fvARB) +P(glUniformMatrix2x3fv) +P(glUniformMatrix2x4fv) +P(glUniformMatrix3fv) +P(glUniformMatrix3fvARB) +P(glUniformMatrix3x2fv) +P(glUniformMatrix3x4fv) +P(glUniformMatrix4fv) +P(glUniformMatrix4fvARB) +P(glUniformMatrix4x2fv) +P(glUniformMatrix4x3fv) +P(glUnlockArraysEXT) +P(glUnmapBuffer) +P(glUnmapBufferARB) +P(glUseProgram) +P(glUseProgramObjectARB) +P(glUseShaderProgramEXT) +P(glValidateProgram) +P(glValidateProgramARB) +P(glVertexAttrib1d) +P(glVertexAttrib1dARB) +P(glVertexAttrib1dNV) +P(glVertexAttrib1dv) +P(glVertexAttrib1dvARB) +P(glVertexAttrib1dvNV) +P(glVertexAttrib1f) +P(glVertexAttrib1fARB) +P(glVertexAttrib1fNV) +P(glVertexAttrib1fv) +P(glVertexAttrib1fvARB) +P(glVertexAttrib1fvNV) +P(glVertexAttrib1s) +P(glVertexAttrib1sARB) +P(glVertexAttrib1sNV) +P(glVertexAttrib1sv) +P(glVertexAttrib1svARB) +P(glVertexAttrib1svNV) +P(glVertexAttrib2d) +P(glVertexAttrib2dARB) +P(glVertexAttrib2dNV) +P(glVertexAttrib2dv) +P(glVertexAttrib2dvARB) +P(glVertexAttrib2dvNV) +P(glVertexAttrib2f) +P(glVertexAttrib2fARB) +P(glVertexAttrib2fNV) +P(glVertexAttrib2fv) +P(glVertexAttrib2fvARB) +P(glVertexAttrib2fvNV) +P(glVertexAttrib2s) +P(glVertexAttrib2sARB) +P(glVertexAttrib2sNV) +P(glVertexAttrib2sv) +P(glVertexAttrib2svARB) +P(glVertexAttrib2svNV) +P(glVertexAttrib3d) +P(glVertexAttrib3dARB) +P(glVertexAttrib3dNV) +P(glVertexAttrib3dv) +P(glVertexAttrib3dvARB) +P(glVertexAttrib3dvNV) +P(glVertexAttrib3f) +P(glVertexAttrib3fARB) +P(glVertexAttrib3fNV) +P(glVertexAttrib3fv) +P(glVertexAttrib3fvARB) +P(glVertexAttrib3fvNV) +P(glVertexAttrib3s) +P(glVertexAttrib3sARB) +P(glVertexAttrib3sNV) +P(glVertexAttrib3sv) +P(glVertexAttrib3svARB) +P(glVertexAttrib3svNV) +P(glVertexAttrib4Nbv) +P(glVertexAttrib4NbvARB) +P(glVertexAttrib4Niv) +P(glVertexAttrib4NivARB) +P(glVertexAttrib4Nsv) +P(glVertexAttrib4NsvARB) +P(glVertexAttrib4Nub) +P(glVertexAttrib4NubARB) +P(glVertexAttrib4Nubv) +P(glVertexAttrib4NubvARB) +P(glVertexAttrib4Nuiv) +P(glVertexAttrib4NuivARB) +P(glVertexAttrib4Nusv) +P(glVertexAttrib4NusvARB) +P(glVertexAttrib4bv) +P(glVertexAttrib4bvARB) +P(glVertexAttrib4d) +P(glVertexAttrib4dARB) +P(glVertexAttrib4dNV) +P(glVertexAttrib4dv) +P(glVertexAttrib4dvARB) +P(glVertexAttrib4dvNV) +P(glVertexAttrib4f) +P(glVertexAttrib4fARB) +P(glVertexAttrib4fNV) +P(glVertexAttrib4fv) +P(glVertexAttrib4fvARB) +P(glVertexAttrib4fvNV) +P(glVertexAttrib4iv) +P(glVertexAttrib4ivARB) +P(glVertexAttrib4s) +P(glVertexAttrib4sARB) +P(glVertexAttrib4sNV) +P(glVertexAttrib4sv) +P(glVertexAttrib4svARB) +P(glVertexAttrib4svNV) +P(glVertexAttrib4ubNV) +P(glVertexAttrib4ubv) +P(glVertexAttrib4ubvARB) +P(glVertexAttrib4ubvNV) +P(glVertexAttrib4uiv) +P(glVertexAttrib4uivARB) +P(glVertexAttrib4usv) +P(glVertexAttrib4usvARB) +P(glVertexAttribDivisor) +P(glVertexAttribDivisorARB) +P(glVertexAttribI1i) +P(glVertexAttribI1iEXT) +P(glVertexAttribI1iv) +P(glVertexAttribI1ivEXT) +P(glVertexAttribI1ui) +P(glVertexAttribI1uiEXT) +P(glVertexAttribI1uiv) +P(glVertexAttribI1uivEXT) +P(glVertexAttribI2i) +P(glVertexAttribI2iEXT) +P(glVertexAttribI2iv) +P(glVertexAttribI2ivEXT) +P(glVertexAttribI2ui) +P(glVertexAttribI2uiEXT) +P(glVertexAttribI2uiv) +P(glVertexAttribI2uivEXT) +P(glVertexAttribI3i) +P(glVertexAttribI3iEXT) +P(glVertexAttribI3iv) +P(glVertexAttribI3ivEXT) +P(glVertexAttribI3ui) +P(glVertexAttribI3uiEXT) +P(glVertexAttribI3uiv) +P(glVertexAttribI3uivEXT) +P(glVertexAttribI4bv) +P(glVertexAttribI4bvEXT) +P(glVertexAttribI4i) +P(glVertexAttribI4iEXT) +P(glVertexAttribI4iv) +P(glVertexAttribI4ivEXT) +P(glVertexAttribI4sv) +P(glVertexAttribI4svEXT) +P(glVertexAttribI4ubv) +P(glVertexAttribI4ubvEXT) +P(glVertexAttribI4ui) +P(glVertexAttribI4uiEXT) +P(glVertexAttribI4uiv) +P(glVertexAttribI4uivEXT) +P(glVertexAttribI4usv) +P(glVertexAttribI4usvEXT) +P(glVertexAttribIPointer) +P(glVertexAttribIPointerEXT) +P(glVertexAttribP1ui) +P(glVertexAttribP1uiv) +P(glVertexAttribP2ui) +P(glVertexAttribP2uiv) +P(glVertexAttribP3ui) +P(glVertexAttribP3uiv) +P(glVertexAttribP4ui) +P(glVertexAttribP4uiv) +P(glVertexAttribPointer) +P(glVertexAttribPointerARB) +P(glVertexAttribPointerNV) +P(glVertexAttribs1dvNV) +P(glVertexAttribs1fvNV) +P(glVertexAttribs1svNV) +P(glVertexAttribs2dvNV) +P(glVertexAttribs2fvNV) +P(glVertexAttribs2svNV) +P(glVertexAttribs3dvNV) +P(glVertexAttribs3fvNV) +P(glVertexAttribs3svNV) +P(glVertexAttribs4dvNV) +P(glVertexAttribs4fvNV) +P(glVertexAttribs4svNV) +P(glVertexAttribs4ubvNV) +P(glVertexP2ui) +P(glVertexP2uiv) +P(glVertexP3ui) +P(glVertexP3uiv) +P(glVertexP4ui) +P(glVertexP4uiv) +P(glVertexPointerEXT) +P(glWaitSync) +P(glWindowPos2d) +P(glWindowPos2dARB) +P(glWindowPos2dv) +P(glWindowPos2dvARB) +P(glWindowPos2f) +P(glWindowPos2fARB) +P(glWindowPos2fv) +P(glWindowPos2fvARB) +P(glWindowPos2i) +P(glWindowPos2iARB) +P(glWindowPos2iv) +P(glWindowPos2ivARB) +P(glWindowPos2s) +P(glWindowPos2sARB) +P(glWindowPos2sv) +P(glWindowPos2svARB) +P(glWindowPos3d) +P(glWindowPos3dARB) +P(glWindowPos3dv) +P(glWindowPos3dvARB) +P(glWindowPos3f) +P(glWindowPos3fARB) +P(glWindowPos3fv) +P(glWindowPos3fvARB) +P(glWindowPos3i) +P(glWindowPos3iARB) +P(glWindowPos3iv) +P(glWindowPos3ivARB) +P(glWindowPos3s) +P(glWindowPos3sARB) +P(glWindowPos3sv) +P(glWindowPos3svARB) diff --git a/glx-dpyredir.def b/glx-dpyredir.def new file mode 100644 index 0000000..295ee7b --- /dev/null +++ b/glx-dpyredir.def @@ -0,0 +1,11 @@ +// GLX functions which need to be simply forwarded +DEF_GLX_PROTO(void, glXCopyContext, (Display *dpy, GLXContext src, GLXContext dst, unsigned long mask),src,dst,mask) +DEF_GLX_PROTO(Bool, glXQueryExtension, (Display *dpy, int *errorb, int *event),errorb,event) +DEF_GLX_PROTO(Bool, glXQueryVersion, (Display *dpy, int *maj, int *min),maj,min) +DEF_GLX_PROTO(Bool, glXIsDirect, (Display *dpy, GLXContext ctx),ctx) +DEF_GLX_PROTO(const char*, glXQueryServerString, (Display *dpy, int screen, int name),screen,name) +DEF_GLX_PROTO(GLXFBConfig*, glXChooseFBConfig, (Display *dpy, int screen, const int *attribList, int *nitems),screen,attribList,nitems) +DEF_GLX_PROTO(GLXFBConfig*, glXGetFBConfigs, (Display *dpy, int screen, int *nelements),screen,nelements) +DEF_GLX_PROTO(int, glXQueryContext, (Display *dpy, GLXContext ctx, int attribute, int *value),ctx,attribute,value) +DEF_GLX_PROTO(void, glXSelectEvent, (Display *dpy, GLXDrawable drawable, unsigned long mask),drawable,mask) +DEF_GLX_PROTO(void, glXGetSelectedEvent, (Display *dpy, GLXDrawable drawable, unsigned long *mask),drawable,mask) diff --git a/glx-reimpl.def b/glx-reimpl.def new file mode 100644 index 0000000..4996443 --- /dev/null +++ b/glx-reimpl.def @@ -0,0 +1,36 @@ +// GLX Functions implemented by primus +DEF_GLX_PROTO(GLXContext, glXCreateContext, (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct)) +DEF_GLX_PROTO(GLXContext, glXCreateNewContext, (Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)) +DEF_GLX_PROTO(void, glXDestroyContext, (Display *dpy, GLXContext ctx)) +DEF_GLX_PROTO(Bool, glXMakeCurrent, (Display *dpy, GLXDrawable drawable, GLXContext ctx)) +DEF_GLX_PROTO(Bool, glXMakeContextCurrent,(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx)) +DEF_GLX_PROTO(void, glXSwapBuffers, (Display *dpy, GLXDrawable drawable)) + +DEF_GLX_PROTO(__GLXextFuncPtr, glXGetProcAddressARB, (const GLubyte *)) +DEF_GLX_PROTO(__GLXextFuncPtr, glXGetProcAddress, (const GLubyte *)) + +DEF_GLX_PROTO(const char*, glXGetClientString, (Display *dpy, int name),name) +DEF_GLX_PROTO(const char*, glXQueryExtensionsString, (Display *dpy, int screen),screen) + +DEF_GLX_PROTO(GLXWindow, glXCreateWindow, (Display *dpy, GLXFBConfig config, Window win, const int *attribList),config,win,attribList) +DEF_GLX_PROTO(void, glXDestroyWindow, (Display *dpy, GLXWindow window),window) +DEF_GLX_PROTO(GLXPbuffer, glXCreatePbuffer, (Display *dpy, GLXFBConfig config, const int *attribList),config,attribList) +DEF_GLX_PROTO(void, glXDestroyPbuffer, (Display *dpy, GLXPbuffer pbuf),pbuf) +DEF_GLX_PROTO(GLXPixmap, glXCreatePixmap, (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList),config,pixmap,attribList) +DEF_GLX_PROTO(void, glXDestroyPixmap, (Display *dpy, GLXPixmap pixmap),pixmap) +DEF_GLX_PROTO(GLXPixmap, glXCreateGLXPixmap, (Display *dpy, XVisualInfo *visual, Pixmap pixmap),visual,pixmap) +DEF_GLX_PROTO(void, glXDestroyGLXPixmap, (Display *dpy, GLXPixmap pixmap),pixmap) +DEF_GLX_PROTO(XVisualInfo*, glXGetVisualFromFBConfig, (Display *dpy, GLXFBConfig config),config) +DEF_GLX_PROTO(int, glXGetFBConfigAttrib, (Display *dpy, GLXFBConfig config, int attribute, int *value),config,attribute,value) +DEF_GLX_PROTO(void, glXQueryDrawable, (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value),draw,attribute,value) + +DEF_GLX_PROTO(XVisualInfo*, glXChooseVisual, (Display *dpy, int screen, int *attribList),screen,attribList) +DEF_GLX_PROTO(int, glXGetConfig, (Display *dpy, XVisualInfo *visual, int attrib, int *value),visual,attrib,value) + +DEF_GLX_PROTO(void, glXUseXFont, (Font font, int first, int count, int list)) +DEF_GLX_PROTO(GLXContext, glXGetCurrentContext, (void)) +DEF_GLX_PROTO(GLXDrawable, glXGetCurrentDrawable, (void)) +DEF_GLX_PROTO(void, glXWaitGL, (void)) +DEF_GLX_PROTO(void, glXWaitX, (void)) +DEF_GLX_PROTO(Display*, glXGetCurrentDisplay, (void)) +DEF_GLX_PROTO(GLXDrawable, glXGetCurrentReadDrawable,(void)) diff --git a/glxext-reimpl.def b/glxext-reimpl.def new file mode 100644 index 0000000..888f7ce --- /dev/null +++ b/glxext-reimpl.def @@ -0,0 +1,3 @@ +// GLX extension functions implemented in primus +DEF_GLX_PROTO(int, glXSwapIntervalSGI, (int interval)) +DEF_GLX_PROTO(GLXContext, glXCreateContextAttribsARB,(Display *dpy, GLXFBConfig config, GLXContext shareList, Bool direct, const int *attrib_list)) diff --git a/libglfork.cpp b/libglfork.cpp new file mode 100644 index 0000000..24e952c --- /dev/null +++ b/libglfork.cpp @@ -0,0 +1,1015 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma GCC visibility push(default) +#define GLX_GLXEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES +#include +#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 { + bool known(GLXDrawable draw) + { + return this->find(draw) != this->end(); + } +}; + +struct ContextInfo { + GLXFBConfig fbconfig; + int sharegroup; +}; + +struct ContextsInfo: public std::map { + 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 + errno = 0; + 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)); + connect(sock, (struct sockaddr *)&addr, sizeof(addr)); + die_if(errno, "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; + GLXFBConfig *dconfigs; + + 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"); + int ncfg, attrs[] = {GLX_DOUBLEBUFFER, GL_TRUE, None}; + dconfigs = dfns.glXChooseFBConfig(ddpy, 0, attrs, &ncfg); + die_if(!ncfg, "broken GLX on main X display\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 bool test_drawpixels_fast(Display *dpy, GLXContext ctx) +{ + 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, primus.dconfigs[0], 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); + 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); + GLXContext context = primus.dfns.glXCreateNewContext(ddpy, primus.dconfigs[0], 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) ? 2 : 1; + 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); + 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(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(primus.ddpy, 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(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(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) +{ + GLXWindow glxwin = primus.dfns.glXCreateWindow(dpy, primus.dconfigs[0], win, attribList); + 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) +{ + GLXPbuffer pbuffer = primus.dfns.glXCreatePbuffer(dpy, primus.dconfigs[0], attribList); + 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) +{ + GLXPixmap glxpix = primus.dfns.glXCreatePixmap(dpy, primus.dconfigs[0], pixmap, attribList); + 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(visual); + di.fbconfig = *acfgs; + return glxpix; +} + +void glXDestroyGLXPixmap(Display *dpy, GLXPixmap pixmap) +{ + glXDestroyPixmap(dpy, pixmap); +} + +static XVisualInfo *match_visual(int attrs[]) +{ + XVisualInfo *vis = glXChooseVisual(primus.ddpy, 0, attrs); + for (int i = 2; attrs[i] != None && vis; i += 2) + { + int tmp = attrs[i+1]; + primus.dfns.glXGetConfig(primus.ddpy, 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(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(primus.ddpy, 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; + XFontStruct *fs = XQueryFont(primus.ddpy, font); + XGetFontProperty(fs, XA_FONT, &prop); + char *xlfd = XGetAtomName(primus.ddpy, 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, ...) \ +static ret l##name par \ +{ return primus.afns.name(__VA_ARGS__); } \ +asm(".type " #name ", %gnu_indirect_function"); \ +void *ifunc_##name(void) asm(#name) __attribute__((visibility("default"))); \ +void *ifunc_##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(primus.ddpy, 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) \ +asm(".type " #name ", %gnu_indirect_function"); \ +void *ifunc_##name(void) asm(#name) __attribute__((visibility("default"))); \ +void *ifunc_##name(void) \ +{ return primus.afns.handle ? real_dlsym(primus.afns.handle, #name) : NULL; } +#include "glext-passthru.def" +#undef P +#endif diff --git a/primus.bash-completion b/primus.bash-completion new file mode 100644 index 0000000..6d5490a --- /dev/null +++ b/primus.bash-completion @@ -0,0 +1 @@ +have primusrun && complete -F _command primusrun diff --git a/primusrun b/primusrun new file mode 100755 index 0000000..81e2dc0 --- /dev/null +++ b/primusrun @@ -0,0 +1,42 @@ +#!/bin/bash + +# Readback-display synchronization method +# 0: no sync, 1: D lags behind one frame, 2: fully synced +# export PRIMUS_SYNC=${PRIMUS_SYNC:-0} + +# Verbosity level +# 0: only errors, 1: warnings (default), 2: profiling +# export PRIMUS_VERBOSE=${PRIMUS_VERBOSE:-1} + +# Upload/display method +# 0: autodetect, 1: textures, 2: PBO/glDrawPixels (needs Mesa-10.1+) +# export PRIMUS_UPLOAD=${PRIMUS_UPLOAD:-0} + +# Approximate sleep ratio in the readback thread, percent +# export PRIMUS_SLEEP=${PRIMUS_SLEEP:-90} + +# Secondary display +# export PRIMUS_DISPLAY=${PRIMUS_DISPLAY:-:8} + +# "Accelerating" libGL +# $LIB will be interpreted by the dynamic linker +# export PRIMUS_libGLa=${PRIMUS_libGLa:-'/usr/$LIB/nvidia/libGL.so.1'} + +# "Displaying" libGL +# export PRIMUS_libGLd=${PRIMUS_libGLd:-'/usr/$LIB/libGL.so.1'} + +# Directory containing primus libGL +PRIMUS_libGL=${PRIMUS_libGL:-$(dirname `readlink -ne $0`)/'$LIB'} + +# On some distributions, e.g. on Ubuntu, libnvidia-tls.so is not available +# in default search paths. Add its path manually after the primus library +# PRIMUS_libGL=${PRIMUS_libGL}:/usr/lib/nvidia-current:/usr/lib32/nvidia-current + +# Mesa drivers need a few symbols to be visible +# export PRIMUS_LOAD_GLOBAL=${PRIMUS_LOAD_GLOBAL:-'libglapi.so.0'} + +# Need functions from primus libGL to take precedence +export LD_LIBRARY_PATH=${PRIMUS_libGL}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} + +# And go! +exec "$@" diff --git a/primusrun.1 b/primusrun.1 new file mode 100644 index 0000000..d0bfa8e --- /dev/null +++ b/primusrun.1 @@ -0,0 +1,51 @@ +.TH PRIMUSRUN "1" "February 2013" "primusrun" +.SH NAME +primusrun \- run an application on a discrete NVIDIA video card +.SH SYNOPSIS +\fBprimusrun\fR \fIcommand \fR +.SH DESCRIPTION +Primus implements low-overhead local-only client-side OpenGL offloading via +GLX forking. +.sp +It is currently intended to be used alongside Bumblebee and provides a +drop-in replacement for optirun (i.e. "primusrun"). +.SH VARIABLES +The following is a list of environment variables affecting primus library that +may be relevant for end users: +.IP "\s-1PRIMUS_SYNC\s0" 4 +Readback-display synchronization method (default: 0) +.br +0: no sync, 1: synced, display previous frame, 2: synced, display latest frame +.IP "\s-1PRIMUS_VERBOSE\s0" 4 +Verbosity level (default: 1) +.br +0: only errors, 1: warnings, 2: profiling +.IP "\s-1PRIMUS_DISPLAY\s0" 4 +The secondary Xorg server display number (default: :8) +.SH EXAMPLES +.TP +\fBprimusrun glxgears \-info\fR +Runs the graphics demo supplied by mesa-utils to confirm whether the +discrete card is being used for GL rendering. +.TP +\fBPRIMUS_VERBOSE=2 primusrun glxgears\fR +Runs the graphics demo supplied by mesa-utils with verbose output from primus. +.TP +\fBvblank_mode=0 primusrun glxgears\fR +Disable vblank synchronisation, typically used for benchmarking purposes. +.SH ISSUES +Since compositing hurts performance, invoking primus when a compositing WM +is active is not recommended. If you need to use primus with compositing and +see flickering or bad performance, synchronizing primus' display thread with +the application's rendering thread may help. +.sp +\fBPRIMUS_SYNC=1 primusrun ...\fR +.sp +This makes primus display the previously rendered frame. Alternatively, with +PRIMUS_SYNC=2 primus will display the latest rendered frame, trading frame +rate for reduced visual latency. +.SH AUTHOR +Primus was created by Alexander Monakov . +.PP +This manual page was written by Vincent Cheng , +for the Debian project (and may be used by others). diff --git a/technotes.md b/technotes.md new file mode 100644 index 0000000..eb6d75c --- /dev/null +++ b/technotes.md @@ -0,0 +1,180 @@ +Notes on primus implementation +============================== + +primus: quick'n'dirty OpenGL offloading + +The purpose is to redirect OpenGL rendering to another X display, and copy +the rendered frames to the original (as if rendering was not redirected), +similar to VirtualGL, but with different assumptions and design goals. + +primus makes the following assumptions: + +* both X servers are local, and direct rendering is available on both +* the application is "well-behaved" (uses double buffering, does not use + color index rendering, does not draw on top of the OpenGL drawable, etc.) + +In contrast, VirtualGL: + +* assumes that the application's X display is remote +* supports obscure OpenGL functionality, making it more versatile + +The design goals are: + +* simplicity/minimalism: + - only GLX functions are overridden + - only two Xlib functions are used +* efficiency: + - minimal amount of framebuffer data copying achievable from + application-level offloading (unfortunately OpenGL does + not allow to reduce beyond 2 copies, readback+display) + - pipelining of rendering, readback and display + +Put another way, VirtualGL is optimized for running arbitrary OpenGL +applications over a network, with correctness and bandwidth being primary +concerns, while primus is optimized for running modern games on hybrid +graphics hardware setups, with simplicity and performance in mind. It is only +needed until DMA-BUF/PRIME offloading is implemented and mature. + +This document collects various interesting issues encountered while +implementing primus. + +Assuming that a secondary X server driving the rendering slave card is +present, OpenGL offloading can be achieved by intercepting GLX calls to +reroute application's rendering to a pbuffer on the secondary X server, and +then reading back the framebuffer and displaying it on the original drawable. + +Intercepting GLX calls +---------------------- + +The usual way to perform symbol interposition in Linux is to use LD_PRELOAD, +and that is what VirtualGL does. However, that is not enough when an +application uses dlopen+dlsym to access library functions. To support that, +VirtualGL overrides dlopen and dlsym via LD_PRELOAD as well, and it even +intercepts `dlopen("libdl")`. Perhaps a cleaner approach is to make the +wrapper provide the complete API (GLX+OpenGL in this case) and add the wrapper +into LD_LIBRARY_PATH instead, which is what primus implements. One problem +with this approach is that although primus overrides only GLX functions, it +has to implement trivial forwarding for OpenGL functions. + +If the underlying OpenGL library is compiled without -Bsymbolic and calls +GLX functions itself, those calls will invoke functions from the wrapper, +which will cause failures unless the wrapper is prepared for that by keeping a +per-thread boolean value indicating whether a wrapper function was entered but +not returned yet (primus does not do that yet). + +Implementing GLX redirection +---------------------------- + +For each rendering context created by the application, primus creates an +additional slave-side context for readback and master-side context for display +(the latter would not be necessary if displaying the framebuffer was performed +by some other means than OpenGL, but it's useful for vblank synchronization). + +For each application thread that calls glXMakeCurrent, primus additionally +spawns a readback thread and a display thread. Rendering, readback and display +are pipelined: application thread regains control as soon as readback thread +issued an asynchronous glReadPixels into a PBO, and readback thread uses two +PBOs to perform readback of a new frame into one while another is used by the +display thread. + +Threads signal data availability/release via posix semaphores. Additionally, a +GL sync object is required so that readback thread does not read an incomplete +frame. + +The application sees slave-side FBConfig and GLXContext IDs, but master-side X +Visuals. + +One GLX function that is not easily redirected is glXUseXFont, as it internally +calls OpenGL functions on bitmap data from the X server. We need bitmap data +from one server, but OpenGL functions need to be called in the other server's +context. + +Direct Rendering on Both Servers +-------------------------------- + +The worker threads each get a direct rendering context. One small issue that +was encountered is that symbols from libglapi.so need to be loaded by primus +in a global namespace (`dlopen("libglapi.so.0", RTLD_GLOBAL)`), otherwise DRI +modules would fail to load (they need symbols from libglapi, but don't link +against it). Starting with Mesa 9.0, DRI modules do link against libglapi, so +this is not a problem. + +However, this means that without shared libglapi, it is not possible to obtain +direct rendering context when loading Mesa with `dlopen("libGL.so.1", +RTLD_LOCAL)`. + +Xlib and threads +---------------- + +primus spawns additional threads for each application thread that calls +glXMakeCurrent: a readback thread and a display thread. The latter makes calls +to glXSwapBuffers after drawing a full-screen quad asynchronously with the +application. Initially, primus called XInitThreads to enable that, as +suggested by the Xlib error message. However, if an applications loads both +Xlib and libGL dynamically via dlopen, primus may not be able to call +XInitThreads early enough. It turned out that opening separate X connections +for primus' needs is a simpler and more robust solution. + +Forwarding OpenGL calls +----------------------- + +To provide OpenGL API functions, primus contains trivial forwarding functions +(VirtualGL overrides some of OpenGL functions, e.g. glFinish to support +single-buffered applications; primus does not support those). However, it +would be better to rely on a dynamic linker mechanism to avoid the need to +provide forwarder implementations, and instead make the dynamic linker resolve +OpenGL functions to definitions found in a slave libGL. On Solaris, that would +be possible with per-symbol DT_FILTER tagging; unfortunately, this is not +supported in binutils and glibc. + +Another question is what functions need to be forwarded. Per OpenGL ABI +document, libraries need to export only up to OpenGL 1.2 and ARB_multitexture, +and anything above that the applications must obtain via glXGetProcAddress. In +reality, Mesa's libGL and nVidia's libGL export a significant (but different) +amount of functions implementing extensions, and there are applications either +linking against those (fortunately not many, Braid and Trine 2 have been found +guilty so far) or even trying to obtain pointers via dlsym (Enemy Territory). + +Compositing +----------- + +There had been reports that using primus under a compositing WM causes +flickering or slow/uneven update rate. When worker threads are synchronized +in a way that the application's thread calling glXSwapBuffers does not regain +control until the display worker completed blitting and called glXSwapBuffers +itself, those issues are not observed. It's unclear what mechanism is causing +the problem. + +Waiting for the display worker to finish completely serializes +render-readback-display, so may cause a big degradation in performance. The +recommended mode is to make the display worker display the previously rendered +frame: this should achieve better performance at the expense of latency of +presentation (and black first frame unless special care is given). + + +Window Resizing +--------------- + +It is not obvious how to receive notifications of window resizing in primus. +At the moment, it simply calls XGetGeometry every frame (without that, the +only Xlib function called in primus would be XOpenDisplay). VirtualGL +intercepts several resizing-related functions from Xlib, and additionally +tries to deduce drawable size from glViewport calls. + +Window Destruction +------------------ + +Since display worker runs asynchronously by default, there is a problem that +the window it is drawing to may be destroyed after application regained +control after calling glXSwapBuffers, but before the display worker completed +drawing and called glXSwapBuffers itself. The worker then encounters an X +error and causes the application to terminate. This problem does not arise +when worker threads are synchronized as described above. How to avoid this +problem while still running the display worker asynchronously? + +Multilib +-------- + +Linux dynamic linker expands $LIB in paths according to current architecture +(since 2002). This nice feature is used both in dlopen() calls in primus and +the wrapper script. -- 2.30.2