summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml67
-rw-r--r--.dir-locals.el6
-rw-r--r--.editorconfig30
-rw-r--r--.gitignore94
-rw-r--r--.travis.yml54
-rw-r--r--.travis/Dockerfile29
-rwxr-xr-x.travis/epoxy-ci-linux.sh32
-rwxr-xr-x.travis/epoxy-ci-osx.sh27
-rwxr-xr-x.travis/run-docker.sh12
-rw-r--r--COPYING50
-rw-r--r--Makefile.am68
-rw-r--r--README.md123
-rwxr-xr-xautogen.sh16
-rw-r--r--configure.ac275
-rw-r--r--cross/fedora-mingw64.txt18
-rw-r--r--doc/Doxyfile.in241
-rw-r--r--doc/meson.build25
-rw-r--r--epoxy.pc.in16
-rw-r--r--include/epoxy/Makefile.am42
-rw-r--r--include/epoxy/common.h63
-rw-r--r--include/epoxy/egl.h54
-rw-r--r--include/epoxy/gl.h112
-rw-r--r--include/epoxy/glx.h57
-rw-r--r--include/epoxy/meson.build44
-rw-r--r--include/epoxy/wgl.h61
-rw-r--r--meson.build232
-rw-r--r--meson_options.txt21
-rw-r--r--registry/README.md13
-rw-r--r--registry/gl.xml47
-rw-r--r--src/Makefile.am184
-rw-r--r--src/dispatch_common.c923
-rw-r--r--src/dispatch_common.h203
-rw-r--r--src/dispatch_egl.c122
-rw-r--r--src/dispatch_glx.c172
-rw-r--r--src/dispatch_wgl.c196
-rwxr-xr-xsrc/gen_dispatch.py914
-rw-r--r--src/meson.build112
-rw-r--r--test/.gitignore24
-rw-r--r--test/Makefile.am192
-rw-r--r--test/cgl_core.c54
-rw-r--r--test/cgl_epoxy_api.c83
-rw-r--r--test/dlwrap.c325
-rw-r--r--test/dlwrap.h67
-rw-r--r--test/egl_common.c54
-rw-r--r--test/egl_common.h25
-rw-r--r--test/egl_epoxy_api.c148
-rw-r--r--test/egl_gl.c130
-rw-r--r--test/egl_has_extension_nocontext.c75
-rw-r--r--test/egl_without_glx.c165
-rw-r--r--test/gl_version.c89
-rw-r--r--test/glx_alias_prefer_same_name.c82
-rw-r--r--test/glx_beginend.c107
-rw-r--r--test/glx_common.c129
-rw-r--r--test/glx_common.h39
-rw-r--r--test/glx_gles2.c118
-rw-r--r--test/glx_glxgetprocaddress_nocontext.c57
-rw-r--r--test/glx_has_extension_nocontext.c56
-rw-r--r--test/glx_public_api.c123
-rw-r--r--test/glx_public_api_core.c181
-rw-r--r--test/glx_static.c70
-rw-r--r--test/headerguards.c60
-rw-r--r--test/khronos_typedefs.c65
-rw-r--r--test/khronos_typedefs.h47
-rw-r--r--test/khronos_typedefs_nonepoxy.c69
-rw-r--r--test/meson.build184
-rw-r--r--test/miscdefines.c67
-rw-r--r--test/wgl_common.c128
-rw-r--r--test/wgl_common.h27
-rw-r--r--test/wgl_core_and_exts.c80
-rw-r--r--test/wgl_per_context_funcptrs.c165
-rw-r--r--test/wgl_usefontbitmaps.c74
71 files changed, 8108 insertions, 6 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000..8e0cae2
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,67 @@
+version: 1.0.{build}
+
+image: Visual Studio 2015
+
+configuration: Release
+
+# Configure both 32-bit and 64-bit builds
+environment:
+ matrix:
+ - platform: x86
+ config: Win32
+ pout: x86
+ - platform: x64
+ config: x64
+ pout: x64
+
+shallow_clone: true
+
+# Download Meson and Ninja, create install directory
+before_build:
+- mkdir build
+- mkdir libepoxy-shared-%pout%
+- cd build
+- curl -LsSO https://github.com/mesonbuild/meson/releases/download/0.47.1/meson-0.47.1.tar.gz
+- 7z x meson-0.47.1.tar.gz
+- move dist\meson-0.47.1.tar .
+- 7z x meson-0.47.1.tar
+- rmdir dist
+- del meson-0.47.1.tar meson-0.47.1.tar.gz
+- curl -LsSO https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip
+- 7z x ninja-win.zip
+- del ninja-win.zip
+- cd ..
+
+# Build and install
+build_script:
+- cd build
+- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %PLATFORM%
+- C:\Python36\python.exe meson-0.47.1\meson.py .. . --backend=ninja --prefix=%APPVEYOR_BUILD_FOLDER%\libepoxy-shared-%pout%
+- ninja
+- ninja install
+- cd ..
+
+# Copy license into install directory and create .zip file
+after_build:
+- copy COPYING libepoxy-shared-%pout%
+- dir libepoxy-shared-%pout% /s /b
+- 7z a -tzip libepoxy-shared-%pout%.zip libepoxy-shared-%pout%
+
+artifacts:
+ - path: libepoxy-shared-%pout%.zip
+ name: libepoxy-shared-%pout%
+
+test: off
+
+# Upload .zip file to GitHub release
+deploy:
+ release: $(APPVEYOR_REPO_TAG_NAME)
+ description: "Epoxy $(APPVEYOR_REPO_TAG_NAME)"
+ provider: GitHub
+ auth_token:
+ secure: X7Ro8Y2RWYo/M1AAn93f9X0dEQFvu7gPb6li2eKRtzPYLGj/JKm7MNWRw2cCcjm6
+ artifact: libepoxy-shared-$(pout)
+ draft: false
+ prerelease: false
+ on:
+ appveyor_repo_tag: true # deploy on tag push only
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..7f3eee2
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,6 @@
+((nil
+ (indent-tabs-mode . nil)
+ (tab-width . 8)
+ (c-basic-offset . 4)
+ )
+ )
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..ce6000d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,30 @@
+root = true
+
+[*]
+charset = utf-8
+
+[*.{c,h}]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[configure.ac]
+indent_style = tab
+indent_size = 8
+
+[Makefile.am]
+indent_style = tab
+indent_size = 8
+
+[.travis.yml]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
+
+[meson.build]
+indent_style = space
+indent_size = 8
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..75d444d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,94 @@
+#
+# X.Org module default exclusion patterns
+# The next section if for module specific patterns
+#
+# Do not edit the following section
+# GNU Build System (Autotools)
+aclocal.m4
+autom4te.cache/
+autoscan.log
+ChangeLog
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config-ml.in
+config.py
+config.status
+config.status.lineno
+config.sub
+configure
+configure.scan
+depcomp
+.deps/
+INSTALL
+install-sh
+.libs/
+libtool
+libtool.m4
+ltmain.sh
+lt~obsolete.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+Makefile
+Makefile.in
+mdate-sh
+missing
+mkinstalldirs
+*.pc
+py-compile
+stamp-h?
+symlink-tree
+texinfo.tex
+ylwrap
+src/sna/git_version.h
+src/sna/brw/brw_test
+
+# Do not edit the following section
+# Edit Compile Debug Document Distribute
+*~
+*.[0-9]
+*.[0-9]x
+*.bak
+*.bin
+core
+*.dll
+*.exe
+*-ISO*.bdf
+*-JIS*.bdf
+*-KOI8*.bdf
+*.kld
+*.ko
+*.ko.cmd
+*.lai
+*.l[oa]
+*.[oa]
+*.obj
+*.so
+*.pcf.gz
+*.pdb
+*.tar.bz2
+*.tar.gz
+#
+# Add & Override patterns for gldispatch
+#
+# Edit the following section as needed
+# For example, !report.pc overrides *.pc. See 'man gitignore'
+#
+configure.lineno
+.dirstamp
+test-driver
+
+gl_generated_dispatch.c
+gl_generated.h
+
+glx_generated_dispatch.c
+glx_generated.h
+
+egl_generated_dispatch.c
+egl_generated.h
+
+wgl_generated_dispatch.c
+wgl_generated.h
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..52c043e
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,54 @@
+sudo: false
+
+branches:
+ except:
+ - debian
+ - khronos-registry
+
+os:
+ - linux
+ - osx
+
+compiler:
+ - gcc
+ - clang
+
+language:
+ - c
+
+services:
+ - docker
+
+matrix:
+ exclude:
+ - os: osx
+ compiler: gcc
+
+before_install:
+ - |
+ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ brew update
+ brew install python@3 meson
+ # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219
+ mkdir -p $HOME/tools; curl -L http://nirbheek.in/files/binaries/ninja/macos/ninja -o $HOME/tools/ninja; chmod +x $HOME/tools/ninja
+ fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull ebassi/epoxyci ; fi
+
+before_script:
+ - |
+ if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+ echo FROM ebassi/epoxyci > Dockerfile
+ echo ADD . /root >> Dockerfile
+ echo WORKDIR /root >> Dockerfile
+ docker build -t withgit .
+ fi
+
+env:
+ - BUILD_OPTS=""
+ - BUILD_OPTS="-Dglx=no"
+ - BUILD_OPTS="-Degl=no"
+ - BUILD_OPTS="-Dx11=false"
+
+script:
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "CC=$CC .travis/epoxy-ci-linux.sh $BUILD_OPTS" ; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then /bin/sh -c "CC=$CC .travis/epoxy-ci-osx.sh $BUILD_OPTS" ; fi
diff --git a/.travis/Dockerfile b/.travis/Dockerfile
new file mode 100644
index 0000000..bd9b40a
--- /dev/null
+++ b/.travis/Dockerfile
@@ -0,0 +1,29 @@
+FROM debian:stretch-slim
+MAINTAINER Emmanuele Bassi <ebassi@gmail.com>
+
+RUN apt-get update -qq && \
+ apt-get install --no-install-recommends -qq -y \
+ ca-certificates \
+ clang \
+ gcc \
+ libgl1-mesa-dev \
+ libegl1-mesa-dev \
+ libgles1-mesa-dev \
+ libgles2-mesa-dev \
+ libgl1-mesa-dri \
+ locales \
+ ninja-build \
+ pkg-config \
+ python3 \
+ python3-pip \
+ python3-setuptools \
+ python3-wheel \
+ xvfb && \
+ rm -rf /usr/share/doc/* /usr/share/man/*
+
+RUN locale-gen C.UTF-8 && /usr/sbin/update-locale LANG=C.UTF-8
+ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
+
+RUN pip3 install meson
+
+WORKDIR /root
diff --git a/.travis/epoxy-ci-linux.sh b/.travis/epoxy-ci-linux.sh
new file mode 100755
index 0000000..e95584f
--- /dev/null
+++ b/.travis/epoxy-ci-linux.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+dump_log_and_quit() {
+ local exitcode=$1
+
+ cat meson-logs/testlog.txt
+
+ exit $exitcode
+}
+
+# Start Xvfb
+XVFB_WHD=${XVFB_WHD:-1280x720x16}
+
+Xvfb :99 -ac -screen 0 $XVFB_WHD -nolisten tcp &
+xvfb=$!
+
+export DISPLAY=:99
+
+srcdir=$( pwd )
+builddir=$( mktemp -d build_XXXXXX )
+
+meson --prefix /usr "$@" $builddir $srcdir || exit $?
+
+cd $builddir
+
+ninja || exit $?
+meson test || dump_log_and_quit $?
+
+cd ..
+
+# Stop Xvfb
+kill -9 ${xvfb}
diff --git a/.travis/epoxy-ci-osx.sh b/.travis/epoxy-ci-osx.sh
new file mode 100755
index 0000000..1a062a1
--- /dev/null
+++ b/.travis/epoxy-ci-osx.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+dump_log_and_quit() {
+ local exitcode=$1
+
+ cat meson-logs/testlog.txt
+
+ exit $exitcode
+}
+
+export SDKROOT=$( xcodebuild -version -sdk macosx Path )
+export CPPFLAGS=-I/usr/local/include
+export LDFLAGS=-L/usr/local/lib
+export OBJC=$CC
+export PATH=$HOME/tools:$PATH
+
+srcdir=$( pwd )
+builddir=$( mktemp -d build_XXXXXX )
+
+meson ${BUILDOPTS} $builddir $srcdir || exit $?
+
+cd $builddir
+
+ninja || exit $?
+meson test || dump_log_and_quit $?
+
+cd ..
diff --git a/.travis/run-docker.sh b/.travis/run-docker.sh
new file mode 100755
index 0000000..4b3ecc7
--- /dev/null
+++ b/.travis/run-docker.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -xe
+
+srcdir="$(pwd)/.."
+
+sudo docker build \
+ --tag "epoxyci" \
+ --file "Dockerfile" .
+sudo docker run --rm \
+ --volume "${srcdir}:/root/epoxy" \
+ --tty --interactive "epoxyci" bash
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..8dd167c
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,50 @@
+The libepoxy project code is covered by the MIT license:
+
+/*
+ * Copyright © 2013-2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+The generated code is derived from Khronos's xml files, which appear
+under the following license:
+
+/*
+ * Copyright (c) 2013 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..8fead48
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,68 @@
+
+# Copyright © 2013 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = include/epoxy src
+
+SUBDIRS += test
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = epoxy.pc
+
+registry_files = \
+ registry/egl.xml \
+ registry/gl.xml \
+ registry/glx.xml \
+ registry/wgl.xml \
+ $()
+
+meson_build_files = \
+ meson_options.txt \
+ meson.build \
+ include/epoxy/meson.build \
+ src/meson.build \
+ test/meson.build \
+ doc/meson.build \
+ doc/Doxyfile.in \
+ cross/fedora-mingw64.txt \
+ $()
+
+EXTRA_DIST = \
+ .dir-locals.el \
+ README.md \
+ autogen.sh \
+ epoxy.pc.in \
+ $(registry_files) \
+ $(meson_build_files) \
+ $()
+
+dist-hook:
+ @if test -d "$(top_srcdir)/.git"; then \
+ echo Generating ChangeLog... ; \
+ ( $(top_srcdir)/missing --run git log --stat ) > "$(top_srcdir)/ChangeLog.tmp" \
+ && mv -f "$(top_srcdir)/ChangeLog.tmp" "$(top_distdir)/ChangeLog" \
+ || ( rm -f "$(top_srcdir)/ChangeLog.tmp"; \
+ echo Failed to generate ChangeLog >&2 ); \
+ else \
+ echo A git checkout is required to generate a ChangeLog >&2; \
+ fi
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..56b6a65
--- /dev/null
+++ b/README.md
@@ -0,0 +1,123 @@
+[![Build Status](https://travis-ci.org/anholt/libepoxy.svg?branch=master)](https://travis-ci.org/anholt/libepoxy)
+[![Build status](https://ci.appveyor.com/api/projects/status/xv6y5jurt5v5ngjx/branch/master?svg=true)](https://ci.appveyor.com/project/ebassi/libepoxy/branch/master)
+
+Epoxy is a library for handling OpenGL function pointer management for
+you.
+
+It hides the complexity of `dlopen()`, `dlsym()`, `glXGetProcAddress()`,
+`eglGetProcAddress()`, etc. from the app developer, with very little
+knowledge needed on their part. They get to read GL specs and write
+code using undecorated function names like `glCompileShader()`.
+
+Don't forget to check for your extensions or versions being present
+before you use them, just like before! We'll tell you what you forgot
+to check for instead of just segfaulting, though.
+
+Features
+--------
+
+ * Automatically initializes as new GL functions are used.
+ * GL 4.6 core and compatibility context support.
+ * GLES 1/2/3 context support.
+ * Knows about function aliases so (e.g.) `glBufferData()` can be
+ used with `GL_ARB_vertex_buffer_object` implementations, along
+ with GL 1.5+ implementations.
+ * EGL, GLX, and WGL support.
+ * Can be mixed with non-epoxy GL usage.
+
+Building
+--------
+
+```sh
+mkdir _build && cd _build
+meson
+ninja
+sudo ninja install
+```
+
+Dependencies for Debian:
+
+ * meson
+ * libegl1-mesa-dev
+
+Dependencies for macOS (using MacPorts):
+
+ * pkgconfig
+ * meson
+
+The test suite has additional dependencies depending on the platform.
+(X11, EGL, a running X Server).
+
+Switching your code to using epoxy
+----------------------------------
+
+It should be as easy as replacing:
+
+```cpp
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glext.h>
+```
+
+with:
+
+```cpp
+#include <epoxy/gl.h>
+#include <epoxy/glx.h>
+```
+
+As long as epoxy's headers appear first, you should be ready to go.
+Additionally, some new helpers become available, so you don't have to
+write them:
+
+`int epoxy_gl_version()` returns the GL version:
+
+ * 12 for GL 1.2
+ * 20 for GL 2.0
+ * 44 for GL 4.4
+
+`bool epoxy_has_gl_extension()` returns whether a GL extension is
+available (`GL_ARB_texture_buffer_object`, for example).
+
+Note that this is not terribly fast, so keep it out of your hot paths,
+ok?
+
+Why not use libGLEW?
+--------------------
+
+GLEW has several issues:
+
+ * Doesn't know about aliases of functions (There are 5 providers of
+ `glPointParameterfv()`, for example, and you don't want to have to
+ choose which one to call when they're all the same).
+ * Doesn't support OpenGL ES.
+ * Has a hard-to-maintain parser of extension specification text
+ instead of using the old .spec file or the new .xml.
+ * Has significant startup time overhead when `glewInit()`
+ autodetects the world.
+ * User-visible multithreading support choice for win32.
+
+The motivation for this project came out of previous use of libGLEW in
+[piglit](http://piglit.freedesktop.org/). Other GL dispatch code
+generation projects had similar failures. Ideally, piglit wants to be
+able to build a single binary for a test that can run on whatever
+context or window system it chooses, not based on link time choices.
+
+We had to solve some of GLEW's problems for piglit and solving them
+meant replacing every single piece of GLEW, so we built
+piglit-dispatch from scratch. And since we wanted to reuse it in
+other GL-related projects, this is the result.
+
+Known issues when running on Windows
+------------------------------------
+
+The automatic per-context symbol resolution for win32 requires that
+epoxy knows when `wglMakeCurrent()` is called, because `wglGetProcAddress()`
+returns values depend on the context's device and pixel format. If
+`wglMakeCurrent()` is called from outside of epoxy (in a way that might
+change the device or pixel format), then epoxy needs to be notified of
+the change using the `epoxy_handle_external_wglMakeCurrent()` function.
+
+The win32 `wglMakeCurrent()` variants are slower than they should be,
+because they should be caching the resolved dispatch tables instead of
+resetting an entire thread-local dispatch table every time.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..02b81ef
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd "$srcdir"
+
+mkdir m4 || exit 1
+
+autoreconf -v --install || exit $?
+cd "$ORIGDIR" || exit $?
+
+if test -z "$NOCONFIGURE"; then
+ exec "$srcdir/configure" "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..b0bb452
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,275 @@
+# Copyright © 2013 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+# Initialize Autoconf
+AC_PREREQ([2.60])
+AC_INIT([libepoxy],
+ [1.5.4],
+ [https://github.com/anholt/libepoxy],
+ [libepoxy])
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Initialize Automake
+AM_INIT_AUTOMAKE([foreign -Wno-portability dist-xz no-dist-gzip tar-ustar subdir-objects])
+
+# Require X.Org macros 1.8 or later for MAN_SUBSTS set by XORG_MANPAGE_SECTIONS
+m4_ifndef([XORG_MACROS_VERSION],
+ [m4_fatal([must install xorg-macros 1.8 or later before running autoconf/autogen.
+ Hint: either install from source, git://anongit.freedesktop.org/xorg/util/macros or,
+ depending on you distribution, try package 'xutils-dev' or 'xorg-x11-util-macros'])])
+
+XORG_MACROS_VERSION(1.8)
+XORG_DEFAULT_OPTIONS
+
+AC_CHECK_PROGS([PYTHON], [python3 python2 python])
+
+# Initialize libtool
+AC_DISABLE_STATIC
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL
+AC_SYS_LARGEFILE
+
+AC_CHECK_HEADER([KHR/khrplatform.h],
+ [AC_DEFINE([HAVE_KHRPLATFORM_H], [1],
+ [Define to 1 if you have <KHR/khrplatform.h> (used for tests)]
+ )]
+ )
+
+# OS X defaults to having -Wint-conversion ("warn when passing
+# uintptr_t to a void *") by default. Kill that.
+XORG_TESTSET_CFLAG(CWARNFLAGS, [-Wno-int-conversion])
+
+AC_ARG_ENABLE([x11],
+ [AC_HELP_STRING([--enable-x11=@<:@yes,no@:>@], [Enable X11 support @<:@default=yes@:>@])],
+ [enable_x11=$enableval],
+ [enable_x11=yes])
+
+AC_ARG_ENABLE([glx],
+ [AC_HELP_STRING([--enable-glx=@<:@auto,yes,no@:>@], [Enable GLX support @<:@default=auto@:>@])],
+ [enable_glx=$enableval],
+ [enable_glx=auto])
+
+# GLX can be used on different platforms, so we expose a
+# configure time switch to enable or disable it; in case
+# the "auto" default value is set, we only enable GLX
+# support on Linux and Unix
+AS_CASE([$enable_glx],
+ [auto], [
+ AS_CASE([$host_os],
+ [mingw*], [build_glx=no],
+ [darwin*], [build_glx=no],
+ [android*], [build_glx=no],
+ [build_glx=yes])
+ ],
+
+ [yes], [
+ build_glx=yes
+ ],
+
+ [no], [
+ build_glx=no
+ ],
+
+ [AC_MSG_ERROR([Invalid value "$enable_glx" for option "--enable-glx"])]
+])
+
+AC_ARG_ENABLE([egl],
+ [AC_HELP_STRING([--enable-egl=@<:@auto,yes,no@:>@], [Enable EGL support @<:@default=auto@:>@])],
+ [enable_egl=$enableval],
+ [enable_egl=auto])
+
+AS_CASE([$enable_egl],
+ [auto], [
+ AS_CASE([$host_os],
+ [mingw*], [build_egl=no],
+ [darwin*], [build_egl=no],
+ [build_egl=yes])
+ ],
+
+ [yes], [
+ build_egl=yes
+ ],
+
+ [no], [
+ build_egl=no
+ ],
+
+ [AC_MSG_ERROR([Invalid value "$enable_egl" for option "--enable-egl"])]
+])
+
+# The remaining platform specific API are enabled depending on the
+# platform we're building for
+AS_CASE([$host_os],
+ [mingw*], [
+ build_wgl=yes
+ has_znow=yes
+ # On windows, the DLL has to have all of its functions
+ # resolved at link time, so we have to link directly against
+ # opengl32.dll. But that's the only GL provider, anyway.
+ EPOXY_LINK_LIBS="-lopengl32"
+
+ # Testing our built windows binaries requires that they be run
+ # under wine. Yeah, we should be nice and autodetect, but
+ # there's lots of missing autodetection for the testsuite
+ # (like checking for EGL and GLX libs in non-windows.).
+ AC_SUBST([LOG_COMPILER], [wine])
+ ],
+
+ [darwin*], [
+ build_wgl=no
+ has_znow=no
+ EPOXY_LINK_LIBS=""
+ ],
+
+ [
+ build_wgl=no
+ has_znow=yes
+ # On platforms with dlopen, we load everything dynamically and
+ # don't link against a specific window system or GL implementation.
+ EPOXY_LINK_LIBS=""
+ ]
+)
+
+AC_SUBST(EPOXY_LINK_LIBS)
+
+if test x$enable_x11 = xno; then
+ if test x$enable_glx = xyes; then
+ AC_MSG_ERROR([GLX support is explicitly enabled, but X11 was disabled])
+ fi
+ build_glx=no
+else
+ AC_DEFINE([ENABLE_X11], [1], [Whether X11 support is enabled])
+fi
+
+AM_CONDITIONAL(BUILD_EGL, test x$build_egl = xyes)
+if test x$build_egl = xyes; then
+ PKG_CHECK_MODULES(EGL, [egl])
+ AC_DEFINE([BUILD_EGL], [1], [build EGL tests])
+ AC_DEFINE(ENABLE_EGL, [1], [Whether EGL support is enabled])
+fi
+
+AM_CONDITIONAL(BUILD_GLX, test x$build_glx = xyes)
+if test x$build_glx = xyes; then
+ AC_DEFINE([BUILD_GLX], [1], [build GLX tests])
+fi
+
+AM_CONDITIONAL(BUILD_WGL, test x$build_wgl = xyes)
+if test x$build_wgl = xyes; then
+ AC_DEFINE([BUILD_WGL], [1], [build WGL tests])
+fi
+
+AM_CONDITIONAL(HAS_ZNOW, test x$has_znow = xyes)
+
+AC_CHECK_LIB([GLESv1_CM], [glFlush], [has_gles1=yes], [has_gles1=no])
+AM_CONDITIONAL(HAS_GLES1, test x$has_gles1 = xyes)
+
+AC_CHECK_LIB([dl], [dlopen], [DLOPEN_LIBS="-ldl"])
+AC_SUBST([DLOPEN_LIBS])
+
+savelibs=$LIBS
+LIBS=$DLOPEN_LIBS
+AC_CHECK_FUNCS([dlvsym], [have_dlvsym=1], [have_dlvsym=0])
+AM_CONDITIONAL(HAVE_DLVSYM, test $have_dlvsym = 1)
+LIBS=$savelibs
+
+VISIBILITY_CFLAGS=""
+AS_CASE(["$host"],
+
+ [*-*-mingw*], [
+ dnl on mingw32 we do -fvisibility=hidden and __declspec(dllexport)
+ AC_DEFINE([EPOXY_PUBLIC],
+ [__attribute__((visibility("default"))) __declspec(dllexport) extern],
+ [defines how to decorate public symbols while building])
+ VISIBILITY_CFLAGS="-fvisibility=hidden"
+ ],
+
+ [
+ dnl on other compilers, check if we can do -fvisibility=hidden
+ SAVED_CFLAGS="${CFLAGS}"
+ CFLAGS="-fvisibility=hidden"
+ AC_MSG_CHECKING([for -fvisibility=hidden compiler flag])
+ AC_TRY_COMPILE([], [int main (void) { return 0; }], [
+ AC_MSG_RESULT(yes)
+ enable_fvisibility_hidden=yes
+ ], [
+ AC_MSG_RESULT(no)
+ enable_fvisibility_hidden=no
+ ])
+ CFLAGS="${SAVED_CFLAGS}"
+
+ AS_IF([test "${enable_fvisibility_hidden}" = "yes"], [
+ AC_DEFINE([EPOXY_PUBLIC],
+ [__attribute__((visibility("default"))) extern],
+ [defines how to decorate public symbols while building])
+ VISIBILITY_CFLAGS="-fvisibility=hidden"
+ ])
+ ]
+)
+
+AC_SUBST([VISIBILITY_CFLAGS])
+
+if test x$enable_x11 = xyes; then
+ PKG_CHECK_MODULES(X11, [x11], [x11=yes], [x11=no])
+ if test x$x11 = xno -a x$build_glx = xyes; then
+ AC_MSG_ERROR([libX11 headers (libx11-dev) are required to build with GLX support])
+ fi
+else
+ x11=no
+fi
+
+if test x$build_glx = xyes; then
+ AC_DEFINE(ENABLE_GLX, [1], [Whether GLX support is enabled])
+fi
+
+AM_CONDITIONAL(HAVE_X11, test x$x11 = xyes)
+
+PKG_CHECK_MODULES(GL, [gl], [gl=yes], [gl=no])
+PKG_CHECK_MODULES(EGL, [egl], [egl=yes], [egl=no])
+
+GL_REQS=""
+AS_IF([test x$gl = xyes], [GL_REQS="$GL_REQS gl"])
+AS_IF([test x$build_egl = xyes && test x$egl = xyes], [GL_REQS="$GL_REQS egl"])
+AC_SUBST(GL_REQS)
+
+# Variables for the pkg-config file; AC_SUBST does not do `test` substitutions,
+# so we need to specify the boolean values here
+AS_IF([test x$build_glx = xyes], [epoxy_has_glx=1], [epoxy_has_glx=0])
+AS_IF([test x$build_egl = xyes], [epoxy_has_egl=1], [epoxy_has_egl=0])
+AS_IF([test x$build_wgl = xyes], [epoxy_has_wgl=1], [epoxy_has_wgl=0])
+AC_SUBST(epoxy_has_glx)
+AC_SUBST(epoxy_has_egl)
+AC_SUBST(epoxy_has_wgl)
+
+AC_CONFIG_FILES([
+ epoxy.pc
+ Makefile
+ include/epoxy/Makefile
+ src/Makefile
+ test/Makefile
+])
+AC_OUTPUT
+
+echo " EGL: $build_egl"
+echo " GLX: $build_glx"
+echo " WGL: $build_wgl"
+echo " PYTHON: $PYTHON"
diff --git a/cross/fedora-mingw64.txt b/cross/fedora-mingw64.txt
new file mode 100644
index 0000000..7c0eda7
--- /dev/null
+++ b/cross/fedora-mingw64.txt
@@ -0,0 +1,18 @@
+[binaries]
+c = '/usr/bin/x86_64-w64-mingw32-gcc'
+cpp = '/usr/bin/x86_64-w64-mingw32-cpp'
+ar = '/usr/bin/x86_64-w64-mingw32-ar'
+strip = '/usr/bin/x86_64-w64-mingw32-strip'
+pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
+exe_wrapper = 'wine'
+
+[properties]
+root = '/usr/x86_64-w64-mingw32/sys-root/mingw'
+c_args = [ '-pipe', '-Wp,-D_FORTIFY_SOURCE=2', '-fexceptions', '--param=ssp-buffer-size=4', '-I/usr/x86_64-w64-mingw32/sys-root/mingw/include' ]
+c_link_args = [ '-L/usr/x86_64-w64-mingw32/sys-root/mingw/lib' ]
+
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..0f3c00d
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,241 @@
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = @PACKAGE_NAME@
+PROJECT_NUMBER = @PACKAGE_VERSION@
+PROJECT_BRIEF =
+PROJECT_LOGO =
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+ALLOW_UNICODE_NAMES = YES
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = "@top_srcdir@/include" "@top_builddir@/include"
+
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES = "newin{2}=\xrefitem since_\1_\2 \"Since @PACKAGE_NAME@ \1.\2\" \"New API in @PACKAGE_NAME@ \1.\2\""
+TCL_SUBST =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING =
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = NO
+GROUP_NESTED_COMPOUNDS = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = NO
+TYPEDEF_HIDES_STRUCT = NO
+LOOKUP_CACHE_SIZE = 0
+
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = NO
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = YES
+HIDE_IN_BODY_DOCS = YES
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+HIDE_COMPOUND_REFERENCE= NO
+SHOW_INCLUDE_FILES = YES
+SHOW_GROUPED_MEMB_INC = NO
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = YES
+SORT_GROUP_NAMES = YES
+SORT_BY_SCOPE_NAME = YES
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = NO
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 2
+SHOW_USED_FILES = YES
+SHOW_FILES = YES
+SHOW_NAMESPACES = NO
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+CITE_BIB_FILES =
+
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_AS_ERROR = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE = doc/doxygen.log
+
+INPUT = "@top_srcdir@/include/epoxy" "@top_srcdir@/src"
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = "*.h" "*.c"
+RECURSIVE = NO
+EXCLUDE = "@top_srcdir@/src/gen_dispatch.py"
+EXCLUDE_SYMLINKS = YES
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS = _* GLAPI* KHRONOS_* APIENTRY* GLX* wgl* EPOXY_CALLSPEC EPOXY_BEGIN_DECLS EPOXY_END_DECLS
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
+
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+SOURCE_TOOLTIPS = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX = "epoxy"
+
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = YES
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE =
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 1
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = NO
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE =
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+
+GENERATE_LATEX = NO
+GENERATE_RTF = NO
+GENERATE_MAN = NO
+GENERATE_XML = NO
+GENERATE_DOCBOOK = NO
+GENERATE_AUTOGEN_DEF = NO
+GENERATE_PERLMOD = NO
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+SEARCH_INCLUDES = YES
+INCLUDE_PATH = "@top_srcdir@/include" \
+ "@top_builddir@/include"
+INCLUDE_FILE_PATTERNS = *.h
+PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \
+ "EPOXY_BEGIN_DECLS=" \
+ "EPOXY_END_DECLS=" \
+ "EPOXY_PUBLIC="
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = NO
+EXTERNAL_PAGES = NO
+
+HAVE_DOT = @HAVE_DOT@
+CLASS_DIAGRAMS = NO
+MSCGEN_PATH =
+DIA_PATH =
+HIDE_UNDOC_RELATIONS = NO
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Sans
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = NO
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DIAFILE_DIRS =
+PLANTUML_JAR_PATH =
+PLANTUML_INCLUDE_PATH =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = YES
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 0000000..ef886da
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,25 @@
+doxyfile_conf = configuration_data()
+doxyfile_conf.set('PACKAGE_NAME', meson.project_name())
+doxyfile_conf.set('PACKAGE_VERSION', meson.project_version())
+doxyfile_conf.set('top_srcdir', meson.source_root())
+doxyfile_conf.set('top_builddir', meson.build_root())
+
+if find_program('dot', required: false).found()
+ doxyfile_conf.set('HAVE_DOT', 'YES')
+else
+ doxyfile_conf.set('HAVE_DOT', 'NO')
+endif
+
+doxyfile = configure_file(input: 'Doxyfile.in',
+ output: 'Doxyfile',
+ configuration: doxyfile_conf,
+ install: false)
+
+docdir = join_paths(epoxy_datadir, 'doc')
+
+html_target = custom_target('epoxy-docs',
+ input: [ doxyfile ],
+ output: [ 'html' ],
+ command: [ doxygen, doxyfile ],
+ install: true,
+ install_dir: join_paths(docdir, 'epoxy'))
diff --git a/epoxy.pc.in b/epoxy.pc.in
new file mode 100644
index 0000000..cdda8d9
--- /dev/null
+++ b/epoxy.pc.in
@@ -0,0 +1,16 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+epoxy_has_glx=@epoxy_has_glx@
+epoxy_has_egl=@epoxy_has_egl@
+epoxy_has_wgl=@epoxy_has_wgl@
+
+Name: epoxy
+Description: epoxy GL dispatch Library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lepoxy
+Libs.private: @DLOPEN_LIBS@
+Requires.private: @GL_REQS@
diff --git a/include/epoxy/Makefile.am b/include/epoxy/Makefile.am
new file mode 100644
index 0000000..494c96e
--- /dev/null
+++ b/include/epoxy/Makefile.am
@@ -0,0 +1,42 @@
+# Copyright © 2013 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+epoxyincludedir = $(includedir)/epoxy
+
+epoxyinclude_HEADERS = \
+ common.h \
+ gl.h \
+ $(EGL_INCLUDES) \
+ $(GLX_INCLUDES) \
+ $(WGL_INCLUDES) \
+ $()
+
+if BUILD_EGL
+EGL_INCLUDES = egl.h
+endif
+
+if BUILD_GLX
+GLX_INCLUDES = glx.h
+endif
+
+if BUILD_WGL
+WGL_INCLUDES = wgl.h
+endif
diff --git a/include/epoxy/common.h b/include/epoxy/common.h
new file mode 100644
index 0000000..cf58ab2
--- /dev/null
+++ b/include/epoxy/common.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 Emmanuele Bassi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** @file common.h
+ *
+ * A common header file, used to define macros and shared symbols.
+ */
+
+#ifndef EPOXY_COMMON_H
+#define EPOXY_COMMON_H
+
+#ifdef __cplusplus
+# define EPOXY_BEGIN_DECLS extern "C" {
+# define EPOXY_END_DECLS }
+#else
+# define EPOXY_BEGIN_DECLS
+# define EPOXY_END_DECLS
+#endif
+
+#ifndef EPOXY_PUBLIC
+# if defined(_MSC_VER)
+# define EPOXY_PUBLIC __declspec(dllimport) extern
+# else
+# define EPOXY_PUBLIC extern
+# endif
+#endif
+
+#if defined(_MSC_VER) && !defined(__bool_true_false_are_defined) && (_MSC_VER < 1800)
+typedef unsigned char bool;
+# define false 0
+# define true 1
+#else
+# include <stdbool.h>
+#endif
+
+EPOXY_BEGIN_DECLS
+
+EPOXY_PUBLIC bool epoxy_extension_in_string(const char *extension_list,
+ const char *ext);
+
+EPOXY_END_DECLS
+
+#endif /* EPOXY_COMMON_H */
diff --git a/include/epoxy/egl.h b/include/epoxy/egl.h
new file mode 100644
index 0000000..b5f8ee0
--- /dev/null
+++ b/include/epoxy/egl.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** @file egl.h
+ *
+ * Provides an implementation of an EGL dispatch layer using global
+ * function pointers
+ *
+ * You should include `<epoxy/egl.h>` instead of `<EGL/egl.h>`.
+ */
+
+#ifndef EPOXY_EGL_H
+#define EPOXY_EGL_H
+
+#include "epoxy/common.h"
+
+#if defined(__egl_h_) || defined(__eglext_h_)
+#error epoxy/egl.h must be included before (or in place of) GL/egl.h
+#else
+#define __egl_h_
+#define __eglext_h_
+#endif
+
+EPOXY_BEGIN_DECLS
+
+#include "epoxy/egl_generated.h"
+
+EPOXY_PUBLIC bool epoxy_has_egl_extension(EGLDisplay dpy, const char *extension);
+EPOXY_PUBLIC int epoxy_egl_version(EGLDisplay dpy);
+EPOXY_PUBLIC bool epoxy_has_egl(void);
+
+EPOXY_END_DECLS
+
+#endif /* EPOXY_EGL_H */
diff --git a/include/epoxy/gl.h b/include/epoxy/gl.h
new file mode 100644
index 0000000..1fef4ba
--- /dev/null
+++ b/include/epoxy/gl.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** @file gl.h
+ *
+ * Provides an implementation of a GL dispatch layer using either
+ * global function pointers or a hidden vtable.
+ *
+ * You should include `<epoxy/gl.h>` instead of `<GL/gl.h>` and `<GL/glext.h>`.
+ */
+
+#ifndef EPOXY_GL_H
+#define EPOXY_GL_H
+
+#include "epoxy/common.h"
+
+#if defined(__gl_h_) || defined(__glext_h_)
+#error epoxy/gl.h must be included before (or in place of) GL/gl.h
+#else
+#define __gl_h_
+#define __glext_h_
+#endif
+
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+#define KHRONOS_APIATTRIBUTES
+
+#ifndef _WIN32
+/* APIENTRY and GLAPIENTRY are not used on Linux or Mac. */
+#define APIENTRY
+#define GLAPIENTRY
+#define EPOXY_CALLSPEC
+#define GLAPI
+#define KHRONOS_APIENTRY
+#define KHRONOS_APICALL
+
+#else
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY APIENTRY
+#endif
+
+#ifndef EPOXY_CALLSPEC
+#define EPOXY_CALLSPEC __stdcall
+#endif
+
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+#define KHRONOS_APIENTRY __stdcall
+#define KHRONOS_APICALL __declspec(dllimport) __stdcall
+
+#endif /* _WIN32 */
+
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifndef GLAPIENTRYP
+#define GLAPIENTRYP GLAPIENTRY *
+#endif
+
+EPOXY_BEGIN_DECLS
+
+#include "epoxy/gl_generated.h"
+
+EPOXY_PUBLIC bool epoxy_has_gl_extension(const char *extension);
+EPOXY_PUBLIC bool epoxy_is_desktop_gl(void);
+EPOXY_PUBLIC int epoxy_gl_version(void);
+EPOXY_PUBLIC int epoxy_glsl_version(void);
+
+/*
+ * the type of the stub function that the failure handler must return;
+ * this function will be called on subsequent calls to the same bogus
+ * function name
+ */
+typedef void (*epoxy_resolver_stub_t)(void);
+
+/* the type of the failure handler itself */
+typedef epoxy_resolver_stub_t
+(*epoxy_resolver_failure_handler_t)(const char *name);
+
+EPOXY_PUBLIC epoxy_resolver_failure_handler_t
+epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler);
+
+EPOXY_END_DECLS
+
+#endif /* EPOXY_GL_H */
diff --git a/include/epoxy/glx.h b/include/epoxy/glx.h
new file mode 100644
index 0000000..8517063
--- /dev/null
+++ b/include/epoxy/glx.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** @file glx.h
+ *
+ * Provides an implementation of a GLX dispatch layer using global
+ * function pointers.
+ *
+ * You should include `<epoxy/glx.h>` instead of `<GL/glx.h>`.
+ */
+
+#ifndef EPOXY_GLX_H
+#define EPOXY_GLX_H
+
+#include <epoxy/gl.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#if defined(GLX_H) || defined(__glxext_h_)
+#error epoxy/glx.h must be included before (or in place of) GL/glx.h
+#else
+#define GLX_H
+#define __glx_h__
+#define __glxext_h_
+#endif
+
+EPOXY_BEGIN_DECLS
+
+#include "epoxy/glx_generated.h"
+
+EPOXY_PUBLIC bool epoxy_has_glx_extension(Display *dpy, int screen, const char *extension);
+EPOXY_PUBLIC int epoxy_glx_version(Display *dpy, int screen);
+EPOXY_PUBLIC bool epoxy_has_glx(Display *dpy);
+
+EPOXY_END_DECLS
+
+#endif /* EPOXY_GLX_H */
diff --git a/include/epoxy/meson.build b/include/epoxy/meson.build
new file mode 100644
index 0000000..65f83be
--- /dev/null
+++ b/include/epoxy/meson.build
@@ -0,0 +1,44 @@
+headers = [ 'common.h' ]
+
+# GL is always generated
+generated_headers = [ [ 'gl.h', 'gl_generated.h', gl_registry ] ]
+
+if build_egl
+ generated_headers += [ [ 'egl.h', 'egl_generated.h', egl_registry ] ]
+endif
+
+if build_glx
+ generated_headers += [ [ 'glx.h', 'glx_generated.h', glx_registry ] ]
+endif
+
+if build_wgl
+ generated_headers += [ [ 'wgl.h', 'wgl_generated.h', wgl_registry ] ]
+endif
+
+gen_headers = []
+
+foreach g: generated_headers
+ header = g[0]
+ gen_header = g[1]
+ registry = g[2]
+ generated = custom_target(gen_header,
+ input: registry,
+ output: [ gen_header ],
+ command: [
+ python,
+ gen_dispatch_py,
+ '--header',
+ '--no-source',
+ '--outputdir=@OUTDIR@',
+ '@INPUT@',
+ ],
+ install: true,
+ install_dir: join_paths(epoxy_includedir, 'epoxy'))
+
+ gen_headers += [ generated ]
+ headers += [ header ]
+endforeach
+
+epoxy_headers = files(headers) + gen_headers
+
+install_headers(headers, subdir: 'epoxy')
diff --git a/include/epoxy/wgl.h b/include/epoxy/wgl.h
new file mode 100644
index 0000000..7c85dec
--- /dev/null
+++ b/include/epoxy/wgl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** @file wgl.h
+ *
+ * Provides an implementation of a WGL dispatch layer using a hidden
+ * vtable.
+ */
+
+#ifndef EPOXY_WGL_H
+#define EPOXY_WGL_H
+
+#include <windows.h>
+
+#include "epoxy/common.h"
+
+#undef wglUseFontBitmaps
+#undef wglUseFontOutlines
+
+#if defined(__wglxext_h_)
+#error epoxy/wgl.h must be included before (or in place of) wgl.h
+#else
+#define __wglxext_h_
+#endif
+
+#ifdef UNICODE
+#define wglUseFontBitmaps wglUseFontBitmapsW
+#else
+#define wglUseFontBitmaps wglUseFontBitmapsA
+#endif
+
+EPOXY_BEGIN_DECLS
+
+#include "epoxy/wgl_generated.h"
+
+EPOXY_PUBLIC bool epoxy_has_wgl_extension(HDC hdc, const char *extension);
+EPOXY_PUBLIC void epoxy_handle_external_wglMakeCurrent(void);
+
+EPOXY_END_DECLS
+
+#endif /* EPOXY_WGL_H */
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..91d9792
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,232 @@
+project('libepoxy', 'c', version: '1.5.4',
+ default_options: [
+ 'buildtype=debugoptimized',
+ 'c_std=gnu99',
+ 'warning_level=1',
+ ],
+ license: 'MIT',
+ meson_version: '>= 0.47.0')
+
+epoxy_version = meson.project_version().split('.')
+epoxy_major_version = epoxy_version[0].to_int()
+epoxy_minor_version = epoxy_version[1].to_int()
+epoxy_micro_version = epoxy_version[2].to_int()
+
+epoxy_prefix = get_option('prefix')
+epoxy_libdir = join_paths(epoxy_prefix, get_option('libdir'))
+epoxy_datadir = join_paths(epoxy_prefix, get_option('datadir'))
+epoxy_includedir = join_paths(epoxy_prefix, get_option('includedir'))
+
+cc = meson.get_compiler('c')
+host_system = host_machine.system()
+
+conf = configuration_data()
+conf.set_quoted('PACKAGE_NAME', meson.project_name())
+conf.set_quoted('PACKAGE_VERSION', meson.project_version())
+conf.set_quoted('PACKAGE_STRING', '@0@-@1@'.format(meson.project_name(), meson.project_version()))
+conf.set_quoted('PACKAGE_DATADIR', join_paths(get_option('prefix'), get_option('datadir')))
+conf.set_quoted('PACKAGE_LIBDIR', join_paths(get_option('prefix'), get_option('libdir')))
+conf.set_quoted('PACKAGE_LOCALEDIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
+conf.set_quoted('PACKAGE_LIBEXECDIR', join_paths(get_option('prefix'), get_option('libexecdir')))
+conf.set('HAVE_KHRPLATFORM_H', cc.has_header('KHR/khrplatform.h'))
+
+# GLX can be used on different platforms, so we expose a
+# configure time switch to enable or disable it; in case
+# the "auto" default value is set, we only enable GLX
+# support on Linux and Unix
+enable_glx = get_option('glx')
+if enable_glx == 'auto'
+ build_glx = not ['windows', 'darwin', 'android', 'haiku'].contains(host_system)
+else
+ build_glx = enable_glx == 'yes'
+endif
+
+enable_egl = get_option('egl')
+if enable_egl == 'auto'
+ build_egl = not ['windows', 'darwin'].contains(host_system)
+else
+ build_egl = enable_egl == 'yes'
+endif
+
+enable_x11 = get_option('x11')
+if not enable_x11
+ if enable_glx == 'yes'
+ error('GLX support is explicitly enabled, but X11 was disabled')
+ endif
+ build_glx = false
+endif
+
+# The remaining platform specific API for GL/GLES are enabled
+# depending on the platform we're building for
+if host_system == 'windows'
+ build_wgl = true
+ has_znow = true
+elif host_system == 'darwin'
+ build_wgl = false
+ has_znow = false
+else
+ build_wgl = false
+ has_znow = true
+endif
+
+conf.set10('ENABLE_GLX', build_glx)
+conf.set10('ENABLE_EGL', build_egl)
+conf.set10('ENABLE_X11', enable_x11)
+
+# Compiler flags, taken from the Xorg macros
+if cc.get_id() == 'msvc'
+ # Compiler options taken from msvc_recommended_pragmas.h
+ # in GLib, based on _Win32_Programming_ by Rector and Newcomer
+ test_cflags = [
+ '-we4002', # too many actual parameters for macro
+ '-we4003', # not enough actual parameters for macro
+ '-w14010', # single-line comment contains line-continuation character
+ '-we4013', # 'function' undefined; assuming extern returning int
+ '-w14016', # no function return type; using int as default
+ '-we4020', # too many actual parameters
+ '-we4021', # too few actual parameters
+ '-we4027', # function declared without formal parameter list
+ '-we4029', # declared formal parameter list different from definition
+ '-we4033', # 'function' must return a value
+ '-we4035', # 'function' : no return value
+ '-we4045', # array bounds overflow
+ '-we4047', # different levels of indirection
+ '-we4049', # terminating line number emission
+ '-we4053', # an expression of type void was used as an operand
+ '-we4071', # no function prototype given
+ '-we4819', # the file contains a character that cannot be represented in the current code page
+ ]
+elif cc.get_id() == 'gcc' or cc.get_id() == 'clang'
+ test_cflags = [
+ '-Wpointer-arith',
+ '-Wmissing-declarations',
+ '-Wformat=2',
+ '-Wstrict-prototypes',
+ '-Wmissing-prototypes',
+ '-Wnested-externs',
+ '-Wbad-function-cast',
+ '-Wold-style-definition',
+ '-Wdeclaration-after-statement',
+ '-Wunused',
+ '-Wuninitialized',
+ '-Wshadow',
+ '-Wmissing-noreturn',
+ '-Wmissing-format-attribute',
+ '-Wredundant-decls',
+ '-Wlogical-op',
+ '-Werror=implicit',
+ '-Werror=nonnull',
+ '-Werror=init-self',
+ '-Werror=main',
+ '-Werror=missing-braces',
+ '-Werror=sequence-point',
+ '-Werror=return-type',
+ '-Werror=trigraphs',
+ '-Werror=array-bounds',
+ '-Werror=write-strings',
+ '-Werror=address',
+ '-Werror=int-to-pointer-cast',
+ '-Werror=pointer-to-int-cast',
+ '-fno-strict-aliasing',
+ '-Wno-int-conversion',
+ ]
+else
+ test_cflags = []
+endif
+
+common_cflags = cc.get_supported_arguments(test_cflags)
+
+libtype = get_option('default_library')
+
+# Visibility compiler flags; we only use this for shared libraries
+visibility_cflags = []
+if libtype == 'shared'
+ if host_system == 'windows'
+ conf.set('DLL_EXPORT', true)
+ conf.set('EPOXY_PUBLIC', '__declspec(dllexport) extern')
+ if cc.get_id() != 'msvc'
+ visibility_cflags += [ '-fvisibility=hidden' ]
+ endif
+ else
+ conf.set('EPOXY_PUBLIC', '__attribute__((visibility("default"))) extern')
+ visibility_cflags += [ '-fvisibility=hidden' ]
+ endif
+endif
+
+# The inline keyword is available only for C++ in MSVC.
+# So we need to use Microsoft specific __inline.
+if host_system == 'windows'
+ if cc.get_id() == 'msvc'
+ conf.set('inline', '__inline')
+ endif
+endif
+
+# Dependencies
+dl_dep = cc.find_library('dl', required: false)
+gl_dep = dependency('gl', required: false)
+egl_dep = dependency('egl', required: false)
+
+# Optional dependencies for tests
+x11_dep = dependency('x11', required: false)
+
+# GLES v2 and v1 may have pkg-config files, courtesy of downstream
+# packagers; let's check those first, and fall back to find_library()
+# if we fail
+gles2_dep = dependency('glesv2', required: false)
+if not gles2_dep.found()
+ gles2_dep = cc.find_library('libGLESv2', required: false)
+endif
+
+gles1_dep = dependency('glesv1_cm', required: false)
+if not gles1_dep.found()
+ gles1_dep = cc.find_library('libGLESv1_CM', required: false)
+endif
+
+# On windows, the DLL has to have all of its functions
+# resolved at link time, so we have to link directly against
+# opengl32. But that's the only GL provider, anyway.
+if host_system == 'windows'
+ opengl32_dep = cc.find_library('opengl32', required: true)
+
+ # When building against static libraries, we need to control
+ # the order of the dependencies, and gdi32 provides symbols
+ # needed when using opengl32, like SetPixelFormat and
+ # ChoosePixelFormat. This is mostly a workaround for older
+ # versions of Meson.
+ gdi32_dep = cc.find_library('gdi32', required: true)
+endif
+
+# Python
+python = import('python3').find_python()
+if not python.found()
+ python = find_program('python', required: true)
+endif
+
+# Generates the dispatch tables
+gen_dispatch_py = files('src/gen_dispatch.py')
+
+gl_registry = files('registry/gl.xml')
+egl_registry = files('registry/egl.xml')
+glx_registry = files('registry/glx.xml')
+wgl_registry = files('registry/wgl.xml')
+
+libepoxy_inc = [
+ include_directories('include'),
+ include_directories('src'),
+]
+
+subdir('include/epoxy')
+subdir('src')
+
+if get_option('tests')
+ subdir('test')
+endif
+
+if get_option('docs')
+ doxygen = find_program('doxygen', required: false)
+ if doxygen.found()
+ subdir('doc')
+ else
+ message('Documentation disabled without doxygen')
+ endif
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..dc30e68
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,21 @@
+option('docs',
+ type: 'boolean', value: false,
+ description: 'Enable generating the Epoxy API reference (depends on Doxygen)')
+option('glx',
+ type: 'combo',
+ choices: [ 'auto', 'yes', 'no' ],
+ value: 'auto',
+ description: 'Enable GLX support')
+option('egl',
+ type: 'combo',
+ choices: [ 'auto', 'yes', 'no' ],
+ value: 'auto',
+ description: 'Enable EGL support')
+option('x11',
+ type: 'boolean',
+ value: true,
+ description: 'Enable X11 support (GLX or EGL-X11)')
+option('tests',
+ type: 'boolean',
+ value: true,
+ description: 'Build the test suite')
diff --git a/registry/README.md b/registry/README.md
new file mode 100644
index 0000000..a35d9d9
--- /dev/null
+++ b/registry/README.md
@@ -0,0 +1,13 @@
+## Updating the registry XML
+
+In order to update the registry XML files and retain the history you cannot
+simply download the files the [Khronos website](https://khronos.org/registry/OpenGL/index_gl.php)
+and copy them into this directory. You should follow these steps, instead:
+
+ 1. check out the `khronos-registry` branch
+ 2. download the XML files from the Khronos repository
+ 3. copy them under the `registry` directory
+ 4. check the result for consistency and commit it
+ 5. check out the `master` branch and merge the `khronos-registry` branch
+ into it with the appropriate commit message
+
diff --git a/registry/gl.xml b/registry/gl.xml
index 00846ff..84fd26b 100644
--- a/registry/gl.xml
+++ b/registry/gl.xml
@@ -772,6 +772,9 @@ typedef unsigned int GLhandleARB;
<enum name="GL_MAX_EXT"/>
<enum name="GL_MIN"/>
<enum name="GL_MIN_EXT"/>
+ <enum name="GL_FUNC_ADD"/>
+ <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
+ <enum name="GL_FUNC_SUBTRACT"/>
</group>
<group name="Boolean">
@@ -1060,6 +1063,12 @@ typedef unsigned int GLhandleARB;
<enum name="GL_UNSIGNED_INT"/>
</group>
+ <group name="DrawElementsType">
+ <enum name="GL_UNSIGNED_BYTE"/>
+ <enum name="GL_UNSIGNED_SHORT"/>
+ <enum name="GL_UNSIGNED_INT"/>
+ </group>
+
<group name="EnableCap">
<enum name="GL_ALPHA_TEST"/>
<enum name="GL_ASYNC_DRAW_PIXELS_SGIX"/>
@@ -2088,6 +2097,8 @@ typedef unsigned int GLhandleARB;
<enum name="GL_HISTOGRAM_EXT"/>
<enum name="GL_PROXY_HISTOGRAM"/>
<enum name="GL_PROXY_HISTOGRAM_EXT"/>
+ <enum name="GL_HISTOGRAM"/>
+ <enum name="GL_PROXY_HISTOGRAM"/>
</group>
<group name="IndexPointerType">
@@ -2229,6 +2240,9 @@ typedef unsigned int GLhandleARB;
<enum name="GL_MAP_UNSYNCHRONIZED_BIT_EXT"/>
<enum name="GL_MAP_WRITE_BIT"/>
<enum name="GL_MAP_WRITE_BIT_EXT"/>
+ <enum name="GL_SPARSE_STORAGE_BIT_ARB"/>
+ <enum name="GL_LGPU_SEPARATE_STORAGE_BIT_NVX"/>
+ <enum name="GL_PER_GPU_STORAGE_BIT_NV"/>
</group>
<group name="MapTarget">
@@ -17737,7 +17751,7 @@ typedef unsigned int GLhandleARB;
</command>
<command>
<proto>void <name>glGetDoublei_v</name></proto>
- <param><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
<param><ptype>GLuint</ptype> <name>index</name></param>
<param len="COMPSIZE(target)"><ptype>GLdouble</ptype> *<name>data</name></param>
</command>
@@ -18057,7 +18071,7 @@ typedef unsigned int GLhandleARB;
</command>
<command>
<proto>void <name>glGetInteger64i_v</name></proto>
- <param><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
<param><ptype>GLuint</ptype> <name>index</name></param>
<param len="COMPSIZE(target)"><ptype>GLint64</ptype> *<name>data</name></param>
</command>
@@ -18082,13 +18096,13 @@ typedef unsigned int GLhandleARB;
</command>
<command>
<proto>void <name>glGetIntegeri_v</name></proto>
- <param><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
<param><ptype>GLuint</ptype> <name>index</name></param>
<param len="COMPSIZE(target)"><ptype>GLint</ptype> *<name>data</name></param>
</command>
<command>
<proto>void <name>glGetIntegeri_vEXT</name></proto>
- <param><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
<param><ptype>GLuint</ptype> <name>index</name></param>
<param><ptype>GLint</ptype> *<name>data</name></param>
</command>
@@ -18920,14 +18934,14 @@ typedef unsigned int GLhandleARB;
</command>
<command>
<proto>void <name>glGetPixelTransformParameterfvEXT</name></proto>
- <param><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
<param><ptype>GLenum</ptype> <name>pname</name></param>
<param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
<glx type="vendor" opcode="2051"/>
</command>
<command>
<proto>void <name>glGetPixelTransformParameterivEXT</name></proto>
- <param><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
<param><ptype>GLenum</ptype> <name>pname</name></param>
<param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
<glx type="vendor" opcode="2052"/>
@@ -22356,6 +22370,16 @@ typedef unsigned int GLhandleARB;
<alias name="glMultiDrawElementsIndirectCount"/>
</command>
<command>
+ <proto>void <name>glMultiDrawElementsIndirectCountARB</name></proto>
+ <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+ <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
+ <param>const void *<name>indirect</name></param>
+ <param><ptype>GLintptr</ptype> <name>drawcount</name></param>
+ <param><ptype>GLsizei</ptype> <name>maxdrawcount</name></param>
+ <param><ptype>GLsizei</ptype> <name>stride</name></param>
+ <alias name="glMultiDrawElementsIndirectCount"/>
+ </command>
+ <command>
<proto>void <name>glMultiDrawElementsIndirectEXT</name></proto>
<param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
<param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -29034,6 +29058,17 @@ typedef unsigned int GLhandleARB;
<param><ptype>GLsizei</ptype> <name>width</name></param>
<param><ptype>GLsizei</ptype> <name>height</name></param>
<param><ptype>GLsizei</ptype> <name>depth</name></param>
+ <param><ptype>GLboolean</ptype> <name>fixedSampleLocations</name></param>
+ <param><ptype>GLuint</ptype> <name>memory</name></param>
+ <param><ptype>GLuint64</ptype> <name>offset</name></param>
+ </command>
+ <command>
+ <proto>void <name>glTexStorageSparseAMD</name></proto>
+ <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+ <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalFormat</name></param>
+ <param><ptype>GLsizei</ptype> <name>width</name></param>
+ <param><ptype>GLsizei</ptype> <name>height</name></param>
+ <param><ptype>GLsizei</ptype> <name>depth</name></param>
<param><ptype>GLsizei</ptype> <name>layers</name></param>
<param group="TextureStorageMaskAMD"><ptype>GLbitfield</ptype> <name>flags</name></param>
</command>
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..73f7435
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,184 @@
+# Copyright © 2013 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ $()
+
+AM_CFLAGS = \
+ $(CWARNFLAGS) \
+ $(VISIBILITY_CFLAGS) \
+ $(X11_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $()
+
+epoxyincludedir = $(includedir)/epoxy
+lib_LTLIBRARIES = libepoxy.la
+
+epoxyinclude_DATA = \
+ $(GENERATED_GL_INCLUDES) \
+ $(INSTALL_GLX_INCLUDES) \
+ $(INSTALL_EGL_INCLUDES) \
+ $(INSTALL_WGL_INCLUDES) \
+ $()
+
+if BUILD_EGL
+INSTALL_EGL_INCLUDES = $(GENERATED_EGL_INCLUDES)
+endif
+
+if BUILD_GLX
+INSTALL_GLX_INCLUDES = $(GENERATED_GLX_INCLUDES)
+endif
+
+if BUILD_WGL
+INSTALL_WGL_INCLUDES = $(GENERATED_WGL_INCLUDES)
+endif
+
+GENERATED_GL_INCLUDES = \
+ $(builddir)/../include/epoxy/gl_generated.h \
+ $()
+
+GENERATED_GLX_INCLUDES = \
+ $(builddir)/../include/epoxy/glx_generated.h \
+ $()
+
+GENERATED_EGL_INCLUDES = \
+ $(builddir)/../include/epoxy/egl_generated.h \
+ $()
+
+GENERATED_WGL_INCLUDES = \
+ $(builddir)/../include/epoxy/wgl_generated.h \
+ $()
+
+GENERATED_GL_SOURCE = gl_generated_dispatch.c
+
+GENERATED_GL = \
+ $(GENERATED_GL_SOURCE) \
+ $(GENERATED_GL_INCLUDES) \
+ $()
+
+GENERATED_GLX_SOURCE = glx_generated_dispatch.c
+
+GENERATED_GLX = \
+ $(GENERATED_GLX_SOURCE) \
+ $(GENERATED_GLX_INCLUDES) \
+ $()
+
+GENERATED_EGL_SOURCE = egl_generated_dispatch.c
+
+GENERATED_EGL = \
+ $(GENERATED_EGL_SOURCE) \
+ $(GENERATED_EGL_INCLUDES) \
+ $()
+
+GENERATED_WGL_SOURCE = wgl_generated_dispatch.c
+
+GENERATED_WGL = \
+ $(GENERATED_WGL_SOURCE) \
+ $(GENERATED_WGL_INCLUDES) \
+ $()
+
+BUILT_SOURCES = \
+ $(GENERATED_GL) \
+ $(GENERATED_GLX) \
+ $(GENERATED_EGL) \
+ $(GENERATED_WGL) \
+ $()
+CLEANFILES = $(BUILT_SOURCES)
+
+libepoxy_la_SOURCES = \
+ dispatch_common.c \
+ dispatch_common.h \
+ $(GENERATED_GL) \
+ $(BUILD_EGL_CODE) \
+ $(BUILD_GLX_CODE) \
+ $(BUILD_WGL_CODE) \
+ $()
+
+libepoxy_la_LDFLAGS = \
+ -no-undefined \
+ -Bsymbolic-functions \
+ $()
+
+libepoxy_la_LIBADD = \
+ $(EPOXY_LINK_LIBS) \
+ $(DLOPEN_LIBS) \
+ $()
+
+if BUILD_EGL
+BUILD_EGL_CODE = \
+ $(GENERATED_EGL) \
+ dispatch_egl.c \
+ $()
+endif
+
+if BUILD_GLX
+BUILD_GLX_CODE = \
+ $(GENERATED_GLX) \
+ dispatch_glx.c \
+ $()
+endif
+
+if BUILD_WGL
+BUILD_WGL_CODE = \
+ $(GENERATED_WGL) \
+ dispatch_wgl.c \
+ $()
+endif
+
+# These are generated alongside the .c file.
+$(GENERATED_GL_INCLUDES): $(GENERATED_GL_SOURCE)
+$(GENERATED_GLX_INCLUDES): $(GENERATED_GLX_SOURCE)
+$(GENERATED_EGL_INCLUDES): $(GENERATED_EGL_SOURCE)
+$(GENERATED_WGL_INCLUDES): $(GENERATED_WGL_SOURCE)
+
+$(GENERATED_GL_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/gl.xml
+ @$(MKDIR_P) $(top_builddir)/include/epoxy
+ $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_dispatch.py \
+ --srcdir $(top_builddir)/src \
+ --includedir $(top_builddir)/include/epoxy \
+ $(top_srcdir)/registry/gl.xml
+
+$(GENERATED_GLX_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/glx.xml
+ @$(MKDIR_P) $(top_builddir)/include/epoxy
+ $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_dispatch.py \
+ --srcdir $(top_builddir)/src \
+ --includedir $(top_builddir)/include/epoxy \
+ $(top_srcdir)/registry/glx.xml
+
+$(GENERATED_EGL_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/egl.xml
+ @$(MKDIR_P) $(top_builddir)/include/epoxy
+ $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_dispatch.py \
+ --srcdir $(top_builddir)/src \
+ --includedir $(top_builddir)/include/epoxy \
+ $(top_srcdir)/registry/egl.xml
+
+$(GENERATED_WGL_SOURCE): $(srcdir)/gen_dispatch.py $(top_srcdir)/registry/wgl.xml
+ @$(MKDIR_P) $(top_builddir)/include/epoxy
+ $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_dispatch.py \
+ --srcdir $(top_builddir)/src \
+ --includedir $(top_builddir)/include/epoxy \
+ $(top_srcdir)/registry/wgl.xml
+
+EXTRA_DIST = \
+ gen_dispatch.py \
+ $()
diff --git a/src/dispatch_common.c b/src/dispatch_common.c
new file mode 100644
index 0000000..b3e4f5f
--- /dev/null
+++ b/src/dispatch_common.c
@@ -0,0 +1,923 @@
+/*
+ * Copyright © 2013-2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * \mainpage Epoxy
+ *
+ * \section intro_sec Introduction
+ *
+ * Epoxy is a library for handling OpenGL function pointer management for
+ * you.
+ *
+ * It hides the complexity of `dlopen()`, `dlsym()`, `glXGetProcAddress()`,
+ * `eglGetProcAddress()`, etc. from the app developer, with very little
+ * knowledge needed on their part. They get to read GL specs and write
+ * code using undecorated function names like `glCompileShader()`.
+ *
+ * Don't forget to check for your extensions or versions being present
+ * before you use them, just like before! We'll tell you what you forgot
+ * to check for instead of just segfaulting, though.
+ *
+ * \section features_sec Features
+ *
+ * - Automatically initializes as new GL functions are used.
+ * - GL 4.6 core and compatibility context support.
+ * - GLES 1/2/3 context support.
+ * - Knows about function aliases so (e.g.) `glBufferData()` can be
+ * used with `GL_ARB_vertex_buffer_object` implementations, along
+ * with GL 1.5+ implementations.
+ * - EGL, GLX, and WGL support.
+ * - Can be mixed with non-epoxy GL usage.
+ *
+ * \section using_sec Using Epoxy
+ *
+ * Using Epoxy should be as easy as replacing:
+ *
+ * ```cpp
+ * #include <GL/gl.h>
+ * #include <GL/glx.h>
+ * #include <GL/glext.h>
+ * ```
+ *
+ * with:
+ *
+ * ```cpp
+ * #include <epoxy/gl.h>
+ * #include <epoxy/glx.h>
+ * ```
+ *
+ * \subsection using_include_sec Headers
+ *
+ * Epoxy comes with the following public headers:
+ *
+ * - `epoxy/gl.h` - For GL API
+ * - `epoxy/egl.h` - For EGL API
+ * - `epoxy/glx.h` - For GLX API
+ * - `epoxy/wgl.h` - For WGL API
+ *
+ * \section links_sec Additional links
+ *
+ * The latest version of the Epoxy code is available on [GitHub](https://github.com/anholt/libepoxy).
+ *
+ * For bug reports and enhancements, please use the [Issues](https://github.com/anholt/libepoxy/issues)
+ * link.
+ *
+ * The scope of this API reference does not include the documentation for
+ * OpenGL and OpenGL ES. For more information on those programming interfaces
+ * please visit:
+ *
+ * - [Khronos](https://www.khronos.org/)
+ * - [OpenGL page on Khronos.org](https://www.khronos.org/opengl/)
+ * - [OpenGL ES page on Khronos.org](https://www.khronos.org/opengles/)
+ * - [docs.GL](http://docs.gl/)
+ */
+
+/**
+ * @file dispatch_common.c
+ *
+ * @brief Implements common code shared by the generated GL/EGL/GLX dispatch code.
+ *
+ * A collection of some important specs on getting GL function pointers.
+ *
+ * From the linux GL ABI (http://www.opengl.org/registry/ABI/):
+ *
+ * "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and
+ * ARB_multitexture entry points statically.
+ *
+ * 3.5. Because non-ARB extensions vary so widely and are constantly
+ * increasing in number, it's infeasible to require that they all be
+ * supported, and extensions can always be added to hardware drivers
+ * after the base link libraries are released. These drivers are
+ * dynamically loaded by libGL, so extensions not in the base
+ * library must also be obtained dynamically.
+ *
+ * 3.6. To perform the dynamic query, libGL also must export an entry
+ * point called
+ *
+ * void (*glXGetProcAddressARB(const GLubyte *))();
+ *
+ * The full specification of this function is available separately. It
+ * takes the string name of a GL or GLX entry point and returns a pointer
+ * to a function implementing that entry point. It is functionally
+ * identical to the wglGetProcAddress query defined by the Windows OpenGL
+ * library, except that the function pointers returned are context
+ * independent, unlike the WGL query."
+ *
+ * From the EGL 1.4 spec:
+ *
+ * "Client API function pointers returned by eglGetProcAddress are
+ * independent of the display and the currently bound client API context,
+ * and may be used by any client API context which supports the extension.
+ *
+ * eglGetProcAddress may be queried for all of the following functions:
+ *
+ * • All EGL and client API extension functions supported by the
+ * implementation (whether those extensions are supported by the current
+ * client API context or not). This includes any mandatory OpenGL ES
+ * extensions.
+ *
+ * eglGetProcAddress may not be queried for core (non-extension) functions
+ * in EGL or client APIs 20 .
+ *
+ * For functions that are queryable with eglGetProcAddress,
+ * implementations may choose to also export those functions statically
+ * from the object libraries im- plementing those functions. However,
+ * portable clients cannot rely on this behavior.
+ *
+ * From the GLX 1.4 spec:
+ *
+ * "glXGetProcAddress may be queried for all of the following functions:
+ *
+ * • All GL and GLX extension functions supported by the implementation
+ * (whether those extensions are supported by the current context or
+ * not).
+ *
+ * • All core (non-extension) functions in GL and GLX from version 1.0 up
+ * to and including the versions of those specifications supported by
+ * the implementation, as determined by glGetString(GL VERSION) and
+ * glXQueryVersion queries."
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#include <err.h>
+#include <pthread.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "dispatch_common.h"
+
+#if defined(__APPLE__)
+#define GLX_LIB "/opt/X11/lib/libGL.1.dylib"
+#define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
+#define GLES1_LIB "libGLESv1_CM.so"
+#define GLES2_LIB "libGLESv2.so"
+#elif defined(__ANDROID__)
+#define GLX_LIB "libGLESv2.so"
+#define EGL_LIB "libEGL.so"
+#define GLES1_LIB "libGLESv1_CM.so"
+#define GLES2_LIB "libGLESv2.so"
+#elif defined(_WIN32)
+#define EGL_LIB "libEGL.dll"
+#define GLES1_LIB "libGLES_CM.dll"
+#define GLES2_LIB "libGLESv2.dll"
+#define OPENGL_LIB "OPENGL32"
+#else
+#define GLVND_GLX_LIB "libGLX.so.1"
+#define GLX_LIB "libGL.so.1"
+#define EGL_LIB "libEGL.so.1"
+#define GLES1_LIB "libGLESv1_CM.so.1"
+#define GLES2_LIB "libGLESv2.so.2"
+#define OPENGL_LIB "libOpenGL.so.0"
+#endif
+
+#ifdef __GNUC__
+#define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
+#define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
+#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
+#define CONSTRUCT(_func) \
+ static void _func(void); \
+ static int _func ## _wrapper(void) { _func(); return 0; } \
+ __pragma(section(".CRT$XCU",read)) \
+ __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
+
+#define DESTRUCT(_func) \
+ static void _func(void); \
+ static int _func ## _constructor(void) { atexit (_func); return 0; } \
+ __pragma(section(".CRT$XCU",read)) \
+ __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
+
+#else
+#error "You will need constructor support for your compiler"
+#endif
+
+struct api {
+#ifndef _WIN32
+ /*
+ * Locking for making sure we don't double-dlopen().
+ */
+ pthread_mutex_t mutex;
+#endif
+
+ /*
+ * dlopen() return value for the GLX API. This is libGLX.so.1 if the
+ * runtime is glvnd-enabled, else libGL.so.1
+ */
+ void *glx_handle;
+
+ /*
+ * dlopen() return value for the desktop GL library.
+ *
+ * On Windows this is OPENGL32. On OSX this is classic libGL. On Linux
+ * this is either libOpenGL (if the runtime is glvnd-enabled) or
+ * classic libGL.so.1
+ */
+ void *gl_handle;
+
+ /* dlopen() return value for libEGL.so.1 */
+ void *egl_handle;
+
+ /* dlopen() return value for libGLESv1_CM.so.1 */
+ void *gles1_handle;
+
+ /* dlopen() return value for libGLESv2.so.2 */
+ void *gles2_handle;
+
+ /*
+ * This value gets incremented when any thread is in
+ * glBegin()/glEnd() called through epoxy.
+ *
+ * We're not guaranteed to be called through our wrapper, so the
+ * conservative paths also try to handle the failure cases they'll
+ * see if begin_count didn't reflect reality. It's also a bit of
+ * a bug that the conservative paths might return success because
+ * some other thread was in epoxy glBegin/glEnd while our thread
+ * is trying to resolve, but given that it's basically just for
+ * informative error messages, we shouldn't need to care.
+ */
+ long begin_count;
+};
+
+static struct api api = {
+#ifndef _WIN32
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
+#else
+ 0,
+#endif
+};
+
+static bool library_initialized;
+
+static bool epoxy_current_context_is_glx(void);
+
+#if PLATFORM_HAS_EGL
+static EGLenum
+epoxy_egl_get_current_gl_context_api(void);
+#endif
+
+CONSTRUCT (library_init)
+
+static void
+library_init(void)
+{
+ library_initialized = true;
+}
+
+static bool
+get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool load)
+{
+ if (*handle)
+ return true;
+
+ if (!library_initialized) {
+ fputs("Attempting to dlopen() while in the dynamic linker.\n", stderr);
+ abort();
+ }
+
+#ifdef _WIN32
+ *handle = LoadLibraryA(lib_name);
+#else
+ pthread_mutex_lock(&api.mutex);
+ if (!*handle) {
+ int flags = RTLD_LAZY | RTLD_LOCAL;
+ if (!load)
+ flags |= RTLD_NOLOAD;
+
+ *handle = dlopen(lib_name, flags);
+ if (!*handle) {
+ if (exit_on_fail) {
+ fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
+ abort();
+ } else {
+ (void)dlerror();
+ }
+ }
+ }
+ pthread_mutex_unlock(&api.mutex);
+#endif
+
+ return *handle != NULL;
+}
+
+static void *
+do_dlsym(void **handle, const char *name, bool exit_on_fail)
+{
+ void *result;
+ const char *error = "";
+
+#ifdef _WIN32
+ result = GetProcAddress(*handle, name);
+#else
+ result = dlsym(*handle, name);
+ if (!result)
+ error = dlerror();
+#endif
+ if (!result && exit_on_fail) {
+ fprintf(stderr, "%s() not found: %s\n", name, error);
+ abort();
+ }
+
+ return result;
+}
+
+/**
+ * @brief Checks whether we're using OpenGL or OpenGL ES
+ *
+ * @return `true` if we're using OpenGL
+ */
+bool
+epoxy_is_desktop_gl(void)
+{
+ const char *es_prefix = "OpenGL ES";
+ const char *version;
+
+#if PLATFORM_HAS_EGL
+ /* PowerVR's OpenGL ES implementation (and perhaps other) don't
+ * comply with the standard, which states that
+ * "glGetString(GL_VERSION)" should return a string starting with
+ * "OpenGL ES". Therefore, to distinguish desktop OpenGL from
+ * OpenGL ES, we must also check the context type through EGL (we
+ * can do that as PowerVR is only usable through EGL).
+ */
+ if (!epoxy_current_context_is_glx()) {
+ switch (epoxy_egl_get_current_gl_context_api()) {
+ case EGL_OPENGL_API: return true;
+ case EGL_OPENGL_ES_API: return false;
+ case EGL_NONE:
+ default: break;
+ }
+ }
+#endif
+
+ if (api.begin_count)
+ return true;
+
+ version = (const char *)glGetString(GL_VERSION);
+
+ /* If we didn't get a version back, there are only two things that
+ * could have happened: either malloc failure (which basically
+ * doesn't exist), or we were called within a glBegin()/glEnd().
+ * Assume the second, which only exists for desktop GL.
+ */
+ if (!version)
+ return true;
+
+ return strncmp(es_prefix, version, strlen(es_prefix));
+}
+
+static int
+epoxy_internal_gl_version(GLenum version_string, int error_version)
+{
+ const char *version = (const char *)glGetString(version_string);
+ GLint major, minor, factor;
+ int scanf_count;
+
+ if (!version)
+ return error_version;
+
+ /* skip to version number */
+ while (!isdigit(*version) && *version != '\0')
+ version++;
+
+ /* Interpret version number */
+ scanf_count = sscanf(version, "%i.%i", &major, &minor);
+ if (scanf_count != 2) {
+ fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
+ version);
+ abort();
+ }
+
+ if (minor >= 10)
+ factor = 100;
+ else
+ factor = 10;
+
+ return factor * major + minor;
+}
+
+/**
+ * @brief Returns the version of OpenGL we are using
+ *
+ * The version is encoded as:
+ *
+ * ```
+ *
+ * version = major * 10 + minor
+ *
+ * ```
+ *
+ * So it can be easily used for version comparisons.
+ *
+ * @return The encoded version of OpenGL we are using
+ */
+int
+epoxy_gl_version(void)
+{
+ return epoxy_internal_gl_version(GL_VERSION, 0);
+}
+
+int
+epoxy_conservative_gl_version(void)
+{
+ if (api.begin_count)
+ return 100;
+
+ return epoxy_internal_gl_version(GL_VERSION, 100);
+}
+
+/**
+ * @brief Returns the version of the GL Shading Language we are using
+ *
+ * The version is encoded as:
+ *
+ * ```
+ *
+ * version = major * 100 + minor
+ *
+ * ```
+ *
+ * So it can be easily used for version comparisons.
+ *
+ * @return The encoded version of the GL Shading Language we are using
+ */
+int
+epoxy_glsl_version(void)
+{
+ if (epoxy_gl_version() >= 20 ||
+ epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
+ return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0);
+
+ return 0;
+}
+
+/**
+ * @brief Checks for the presence of an extension in an OpenGL extension string
+ *
+ * @param extension_list The string containing the list of extensions to check
+ * @param ext The name of the GL extension
+ * @return `true` if the extension is available'
+ *
+ * @note If you are looking to check whether a normal GL, EGL or GLX extension
+ * is supported by the client, this probably isn't the function you want.
+ *
+ * Some parts of the spec for OpenGL and friends will return an OpenGL formatted
+ * extension string that is separate from the usual extension strings for the
+ * spec. This function provides easy parsing of those strings.
+ *
+ * @see epoxy_has_gl_extension()
+ * @see epoxy_has_egl_extension()
+ * @see epoxy_has_glx_extension()
+ */
+bool
+epoxy_extension_in_string(const char *extension_list, const char *ext)
+{
+ const char *ptr = extension_list;
+ int len;
+
+ if (!ext)
+ return false;
+
+ len = strlen(ext);
+
+ if (extension_list == NULL || *extension_list == '\0')
+ return false;
+
+ /* Make sure that don't just find an extension with our name as a prefix. */
+ while (true) {
+ ptr = strstr(ptr, ext);
+ if (!ptr)
+ return false;
+
+ if (ptr[len] == ' ' || ptr[len] == 0)
+ return true;
+ ptr += len;
+ }
+}
+
+static bool
+epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
+{
+ if (epoxy_gl_version() < 30) {
+ const char *exts = (const char *)glGetString(GL_EXTENSIONS);
+ if (!exts)
+ return invalid_op_mode;
+ return epoxy_extension_in_string(exts, ext);
+ } else {
+ int num_extensions;
+ int i;
+
+ glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
+ if (num_extensions == 0)
+ return invalid_op_mode;
+
+ for (i = 0; i < num_extensions; i++) {
+ const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
+ if (!gl_ext)
+ return false;
+ if (strcmp(ext, gl_ext) == 0)
+ return true;
+ }
+
+ return false;
+ }
+}
+
+bool
+epoxy_load_glx(bool exit_if_fails, bool load)
+{
+#if PLATFORM_HAS_GLX
+# ifdef GLVND_GLX_LIB
+ /* prefer the glvnd library if it exists */
+ if (!api.glx_handle)
+ get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
+# endif
+ if (!api.glx_handle)
+ get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
+#endif
+ return api.glx_handle != NULL;
+}
+
+void *
+epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
+{
+#if PLATFORM_HAS_GLX
+ if (epoxy_load_glx(exit_if_fails, exit_if_fails))
+ return do_dlsym(&api.glx_handle, name, exit_if_fails);
+#endif
+ return NULL;
+}
+
+/**
+ * Tests whether the currently bound context is EGL or GLX, trying to
+ * avoid loading libraries unless necessary.
+ */
+static bool
+epoxy_current_context_is_glx(void)
+{
+#if !PLATFORM_HAS_GLX
+ return false;
+#else
+ void *sym;
+
+ sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
+ if (sym) {
+ if (glXGetCurrentContext())
+ return true;
+ } else {
+ (void)dlerror();
+ }
+
+#if PLATFORM_HAS_EGL
+ sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
+ if (sym) {
+ if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
+ return false;
+ } else {
+ (void)dlerror();
+ }
+#endif /* PLATFORM_HAS_EGL */
+
+ return false;
+#endif /* PLATFORM_HAS_GLX */
+}
+
+/**
+ * @brief Returns true if the given GL extension is supported in the current context.
+ *
+ * @param ext The name of the GL extension
+ * @return `true` if the extension is available
+ *
+ * @note that this function can't be called from within `glBegin()` and `glEnd()`.
+ *
+ * @see epoxy_has_egl_extension()
+ * @see epoxy_has_glx_extension()
+ */
+bool
+epoxy_has_gl_extension(const char *ext)
+{
+ return epoxy_internal_has_gl_extension(ext, false);
+}
+
+bool
+epoxy_conservative_has_gl_extension(const char *ext)
+{
+ if (api.begin_count)
+ return true;
+
+ return epoxy_internal_has_gl_extension(ext, true);
+}
+
+bool
+epoxy_load_egl(bool exit_if_fails, bool load)
+{
+#if PLATFORM_HAS_EGL
+ return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
+#else
+ return false;
+#endif
+}
+
+void *
+epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
+{
+#if PLATFORM_HAS_EGL
+ if (epoxy_load_egl(exit_if_fails, exit_if_fails))
+ return do_dlsym(&api.egl_handle, name, exit_if_fails);
+#endif
+ return NULL;
+}
+
+void *
+epoxy_egl_dlsym(const char *name)
+{
+ return epoxy_conservative_egl_dlsym(name, true);
+}
+
+void *
+epoxy_glx_dlsym(const char *name)
+{
+ return epoxy_conservative_glx_dlsym(name, true);
+}
+
+static void
+epoxy_load_gl(void)
+{
+ if (api.gl_handle)
+ return;
+
+#if defined(_WIN32) || defined(__APPLE__)
+ get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
+#else
+
+#if defined(OPENGL_LIB)
+ if (!api.gl_handle)
+ get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
+#endif
+
+ get_dlopen_handle(&api.glx_handle, GLX_LIB, true, true);
+ api.gl_handle = api.glx_handle;
+#endif
+}
+
+void *
+epoxy_gl_dlsym(const char *name)
+{
+ epoxy_load_gl();
+
+ return do_dlsym(&api.gl_handle, name, true);
+}
+
+void *
+epoxy_gles1_dlsym(const char *name)
+{
+ if (epoxy_current_context_is_glx()) {
+ return epoxy_get_proc_address(name);
+ } else {
+ get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
+ return do_dlsym(&api.gles1_handle, name, true);
+ }
+}
+
+void *
+epoxy_gles2_dlsym(const char *name)
+{
+ if (epoxy_current_context_is_glx()) {
+ return epoxy_get_proc_address(name);
+ } else {
+ get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
+ return do_dlsym(&api.gles2_handle, name, true);
+ }
+}
+
+/**
+ * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
+ * functions.
+ *
+ * Mesa interpreted GLES as intending that the GLES3 functions were
+ * available only through eglGetProcAddress() and not dlsym(), while
+ * ARM's Mali drivers interpreted GLES as intending that GLES3
+ * functions were available only through dlsym() and not
+ * eglGetProcAddress(). Thanks, Khronos.
+ */
+void *
+epoxy_gles3_dlsym(const char *name)
+{
+ if (epoxy_current_context_is_glx()) {
+ return epoxy_get_proc_address(name);
+ } else {
+ if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
+ void *func = do_dlsym(&api.gles2_handle, name, false);
+
+ if (func)
+ return func;
+ }
+
+ return epoxy_get_proc_address(name);
+ }
+}
+
+/**
+ * Performs either the dlsym or glXGetProcAddress()-equivalent for
+ * core functions in desktop GL.
+ */
+void *
+epoxy_get_core_proc_address(const char *name, int core_version)
+{
+#ifdef _WIN32
+ int core_symbol_support = 11;
+#elif defined(__ANDROID__)
+ /**
+ * All symbols must be resolved through eglGetProcAddress
+ * on Android
+ */
+ int core_symbol_support = 0;
+#else
+ int core_symbol_support = 12;
+#endif
+
+ if (core_version <= core_symbol_support) {
+ return epoxy_gl_dlsym(name);
+ } else {
+ return epoxy_get_proc_address(name);
+ }
+}
+
+#if PLATFORM_HAS_EGL
+static EGLenum
+epoxy_egl_get_current_gl_context_api(void)
+{
+ EGLint curapi;
+
+ if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
+ EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
+ (void)eglGetError();
+ return EGL_NONE;
+ }
+
+ return (EGLenum) curapi;
+}
+#endif /* PLATFORM_HAS_EGL */
+
+/**
+ * Performs the dlsym() for the core GL 1.0 functions that we use for
+ * determining version and extension support for deciding on dlsym
+ * versus glXGetProcAddress() for all other functions.
+ *
+ * This needs to succeed on implementations without GLX (since
+ * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
+ * at call time we don't know for sure what API they're trying to use
+ * without inspecting contexts ourselves).
+ */
+void *
+epoxy_get_bootstrap_proc_address(const char *name)
+{
+ /* If we already have a library that links to libglapi loaded,
+ * use that.
+ */
+#if PLATFORM_HAS_GLX
+ if (api.glx_handle && glXGetCurrentContext())
+ return epoxy_gl_dlsym(name);
+#endif
+
+ /* If epoxy hasn't loaded any API-specific library yet, try to
+ * figure out what API the context is using and use that library,
+ * since future calls will also use that API (this prevents a
+ * non-X11 ES2 context from loading a bunch of X11 junk).
+ */
+#if PLATFORM_HAS_EGL
+ get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
+ if (api.egl_handle) {
+ int version = 0;
+ switch (epoxy_egl_get_current_gl_context_api()) {
+ case EGL_OPENGL_API:
+ return epoxy_gl_dlsym(name);
+ case EGL_OPENGL_ES_API:
+ if (eglQueryContext(eglGetCurrentDisplay(),
+ eglGetCurrentContext(),
+ EGL_CONTEXT_CLIENT_VERSION,
+ &version)) {
+ if (version >= 2)
+ return epoxy_gles2_dlsym(name);
+ else
+ return epoxy_gles1_dlsym(name);
+ }
+ }
+ }
+#endif /* PLATFORM_HAS_EGL */
+
+ /* Fall back to GLX */
+ return epoxy_gl_dlsym(name);
+}
+
+void *
+epoxy_get_proc_address(const char *name)
+{
+#if PLATFORM_HAS_EGL
+ GLenum egl_api = EGL_NONE;
+
+ if (!epoxy_current_context_is_glx())
+ egl_api = epoxy_egl_get_current_gl_context_api();
+
+ switch (egl_api) {
+ case EGL_OPENGL_API:
+ case EGL_OPENGL_ES_API:
+ return eglGetProcAddress(name);
+ case EGL_NONE:
+ break;
+ }
+#endif
+
+#if defined(_WIN32)
+ return wglGetProcAddress(name);
+#elif defined(__APPLE__)
+ return epoxy_gl_dlsym(name);
+#elif PLATFORM_HAS_GLX
+ if (epoxy_current_context_is_glx())
+ return glXGetProcAddressARB((const GLubyte *)name);
+ assert(0 && "Couldn't find current GLX or EGL context.\n");
+#endif
+
+ return NULL;
+}
+
+WRAPPER_VISIBILITY (void)
+WRAPPER(epoxy_glBegin)(GLenum primtype)
+{
+#ifdef _WIN32
+ InterlockedIncrement(&api.begin_count);
+#else
+ pthread_mutex_lock(&api.mutex);
+ api.begin_count++;
+ pthread_mutex_unlock(&api.mutex);
+#endif
+
+ epoxy_glBegin_unwrapped(primtype);
+}
+
+WRAPPER_VISIBILITY (void)
+WRAPPER(epoxy_glEnd)(void)
+{
+ epoxy_glEnd_unwrapped();
+
+#ifdef _WIN32
+ InterlockedDecrement(&api.begin_count);
+#else
+ pthread_mutex_lock(&api.mutex);
+ api.begin_count--;
+ pthread_mutex_unlock(&api.mutex);
+#endif
+}
+
+PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
+PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
+
+epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
+
+/**
+ * Sets the function that will be called every time Epoxy fails to
+ * resolve a symbol.
+ *
+ * @param handler The new handler function
+ * @return The previous handler function
+ */
+epoxy_resolver_failure_handler_t
+epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
+{
+#ifdef _WIN32
+ return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
+ handler);
+#else
+ epoxy_resolver_failure_handler_t old;
+ pthread_mutex_lock(&api.mutex);
+ old = epoxy_resolver_failure_handler;
+ epoxy_resolver_failure_handler = handler;
+ pthread_mutex_unlock(&api.mutex);
+ return old;
+#endif
+}
diff --git a/src/dispatch_common.h b/src/dispatch_common.h
new file mode 100644
index 0000000..a361ccc
--- /dev/null
+++ b/src/dispatch_common.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef _WIN32
+#define PLATFORM_HAS_EGL ENABLE_EGL
+#define PLATFORM_HAS_GLX ENABLE_GLX
+#define PLATFORM_HAS_WGL 1
+#elif defined(__APPLE__)
+#define PLATFORM_HAS_EGL 0
+#define PLATFORM_HAS_GLX ENABLE_GLX
+#define PLATFORM_HAS_WGL 0
+#elif defined(ANDROID)
+#define PLATFORM_HAS_EGL ENABLE_EGL
+#define PLATFORM_HAS_GLX 0
+#define PLATFORM_HAS_WGL 0
+#else
+#define PLATFORM_HAS_EGL ENABLE_EGL
+#define PLATFORM_HAS_GLX ENABLE_GLX
+#define PLATFORM_HAS_WGL 0
+#endif
+
+#include "epoxy/gl.h"
+#if PLATFORM_HAS_GLX
+#include "epoxy/glx.h"
+#endif
+#if PLATFORM_HAS_EGL
+# if !ENABLE_X11
+/* Mesa uses this symbol to avoid including X11 headers when including
+ * EGL.h; since X11 was explicitly disabled at configuration time, we
+ * should do the same
+ */
+# define MESA_EGL_NO_X11_HEADERS 1
+# endif
+#include "epoxy/egl.h"
+#endif
+#if PLATFORM_HAS_WGL
+#include "epoxy/wgl.h"
+#endif
+
+#if defined(__GNUC__)
+#define PACKED __attribute__((__packed__))
+#define ENDPACKED
+#elif defined (_MSC_VER)
+#define PACKED __pragma(pack(push,1))
+#define ENDPACKED __pragma(pack(pop))
+#else
+#define PACKED
+#define ENDPACKED
+#endif
+
+/* On win32, we're going to need to keep a per-thread dispatch table,
+ * since the function pointers depend on the device and pixel format
+ * of the current context.
+ */
+#if defined(_WIN32)
+#define USING_DISPATCH_TABLE 1
+#else
+#define USING_DISPATCH_TABLE 0
+#endif
+
+#define UNWRAPPED_PROTO(x) (GLAPIENTRY *x)
+#define WRAPPER_VISIBILITY(type) static type GLAPIENTRY
+#define WRAPPER(x) x ## _wrapped
+
+#define GEN_GLOBAL_REWRITE_PTR(name, args, passthrough) \
+ static void EPOXY_CALLSPEC \
+ name##_global_rewrite_ptr args \
+ { \
+ if (name == (void *)name##_global_rewrite_ptr) \
+ name = (void *)name##_resolver(); \
+ name passthrough; \
+ }
+
+#define GEN_GLOBAL_REWRITE_PTR_RET(ret, name, args, passthrough) \
+ static ret EPOXY_CALLSPEC \
+ name##_global_rewrite_ptr args \
+ { \
+ if (name == (void *)name##_global_rewrite_ptr) \
+ name = (void *)name##_resolver(); \
+ return name passthrough; \
+ }
+
+#if USING_DISPATCH_TABLE
+#define GEN_DISPATCH_TABLE_REWRITE_PTR(name, args, passthrough) \
+ static void EPOXY_CALLSPEC \
+ name##_dispatch_table_rewrite_ptr args \
+ { \
+ struct dispatch_table *dispatch_table = get_dispatch_table(); \
+ \
+ dispatch_table->name = (void *)name##_resolver(); \
+ dispatch_table->name passthrough; \
+ }
+
+#define GEN_DISPATCH_TABLE_REWRITE_PTR_RET(ret, name, args, passthrough) \
+ static ret EPOXY_CALLSPEC \
+ name##_dispatch_table_rewrite_ptr args \
+ { \
+ struct dispatch_table *dispatch_table = get_dispatch_table(); \
+ \
+ dispatch_table->name = (void *)name##_resolver(); \
+ return dispatch_table->name passthrough; \
+ }
+
+#define GEN_DISPATCH_TABLE_THUNK(name, args, passthrough) \
+ static void EPOXY_CALLSPEC \
+ name##_dispatch_table_thunk args \
+ { \
+ get_dispatch_table()->name passthrough; \
+ }
+
+#define GEN_DISPATCH_TABLE_THUNK_RET(ret, name, args, passthrough) \
+ static ret EPOXY_CALLSPEC \
+ name##_dispatch_table_thunk args \
+ { \
+ return get_dispatch_table()->name passthrough; \
+ }
+
+#else
+#define GEN_DISPATCH_TABLE_REWRITE_PTR(name, args, passthrough)
+#define GEN_DISPATCH_TABLE_REWRITE_PTR_RET(ret, name, args, passthrough)
+#define GEN_DISPATCH_TABLE_THUNK(name, args, passthrough)
+#define GEN_DISPATCH_TABLE_THUNK_RET(ret, name, args, passthrough)
+#endif
+
+#define GEN_THUNKS(name, args, passthrough) \
+ GEN_GLOBAL_REWRITE_PTR(name, args, passthrough) \
+ GEN_DISPATCH_TABLE_REWRITE_PTR(name, args, passthrough) \
+ GEN_DISPATCH_TABLE_THUNK(name, args, passthrough)
+
+#define GEN_THUNKS_RET(ret, name, args, passthrough) \
+ GEN_GLOBAL_REWRITE_PTR_RET(ret, name, args, passthrough) \
+ GEN_DISPATCH_TABLE_REWRITE_PTR_RET(ret, name, args, passthrough) \
+ GEN_DISPATCH_TABLE_THUNK_RET(ret, name, args, passthrough)
+
+void *epoxy_egl_dlsym(const char *name);
+void *epoxy_glx_dlsym(const char *name);
+void *epoxy_gl_dlsym(const char *name);
+void *epoxy_gles1_dlsym(const char *name);
+void *epoxy_gles2_dlsym(const char *name);
+void *epoxy_gles3_dlsym(const char *name);
+void *epoxy_get_proc_address(const char *name);
+void *epoxy_get_core_proc_address(const char *name, int core_version);
+void *epoxy_get_bootstrap_proc_address(const char *name);
+
+int epoxy_conservative_gl_version(void);
+bool epoxy_conservative_has_gl_extension(const char *name);
+int epoxy_conservative_glx_version(void);
+bool epoxy_conservative_has_glx_extension(const char *name);
+int epoxy_conservative_egl_version(void);
+bool epoxy_conservative_has_egl_extension(const char *name);
+bool epoxy_conservative_has_wgl_extension(const char *name);
+void *epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails);
+void *epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails);
+
+bool epoxy_load_glx(bool exit_if_fails, bool load);
+bool epoxy_load_egl(bool exit_if_fails, bool load);
+
+#define glBegin_unwrapped epoxy_glBegin_unwrapped
+#define glEnd_unwrapped epoxy_glEnd_unwrapped
+extern void UNWRAPPED_PROTO(glBegin_unwrapped)(GLenum primtype);
+extern void UNWRAPPED_PROTO(glEnd_unwrapped)(void);
+
+extern epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
+
+#if USING_DISPATCH_TABLE
+void gl_init_dispatch_table(void);
+void gl_switch_to_dispatch_table(void);
+void wgl_init_dispatch_table(void);
+void wgl_switch_to_dispatch_table(void);
+extern uint32_t gl_tls_index, gl_tls_size;
+extern uint32_t wgl_tls_index, wgl_tls_size;
+
+#define wglMakeCurrent_unwrapped epoxy_wglMakeCurrent_unwrapped
+#define wglMakeContextCurrentARB_unwrapped epoxy_wglMakeContextCurrentARB_unwrapped
+#define wglMakeContextCurrentEXT_unwrapped epoxy_wglMakeContextCurrentEXT_unwrapped
+#define wglMakeAssociatedContextCurrentAMD_unwrapped epoxy_wglMakeAssociatedContextCurrentAMD_unwrapped
+extern BOOL UNWRAPPED_PROTO(wglMakeCurrent_unwrapped)(HDC hdc, HGLRC hglrc);
+extern BOOL UNWRAPPED_PROTO(wglMakeContextCurrentARB_unwrapped)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
+extern BOOL UNWRAPPED_PROTO(wglMakeContextCurrentEXT_unwrapped)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
+extern BOOL UNWRAPPED_PROTO(wglMakeAssociatedContextCurrentAMD_unwrapped)(HGLRC hglrc);
+#endif /* _WIN32_ */
diff --git a/src/dispatch_egl.c b/src/dispatch_egl.c
new file mode 100644
index 0000000..3f0c789
--- /dev/null
+++ b/src/dispatch_egl.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dispatch_common.h"
+
+int
+epoxy_conservative_egl_version(void)
+{
+ EGLDisplay dpy = eglGetCurrentDisplay();
+
+ if (!dpy)
+ return 14;
+
+ return epoxy_egl_version(dpy);
+}
+
+/**
+ * @brief Returns the version of OpenGL we are using
+ *
+ * The version is encoded as:
+ *
+ * ```
+ *
+ * version = major * 10 + minor
+ *
+ * ```
+ *
+ * So it can be easily used for version comparisons.
+ *
+ * @param The EGL display
+ *
+ * @return The encoded version of EGL we are using
+ *
+ * @see epoxy_gl_version()
+ */
+int
+epoxy_egl_version(EGLDisplay dpy)
+{
+ int major, minor;
+ const char *version_string;
+ int ret;
+
+ version_string = eglQueryString(dpy, EGL_VERSION);
+ if (!version_string)
+ return 0;
+
+ ret = sscanf(version_string, "%d.%d", &major, &minor);
+ assert(ret == 2);
+ return major * 10 + minor;
+}
+
+bool
+epoxy_conservative_has_egl_extension(const char *ext)
+{
+ return epoxy_has_egl_extension(eglGetCurrentDisplay(), ext);
+}
+
+/**
+ * @brief Returns true if the given EGL extension is supported in the current context.
+ *
+ * @param dpy The EGL display
+ * @param extension The name of the EGL extension
+ *
+ * @return `true` if the extension is available
+ *
+ * @see epoxy_has_gl_extension()
+ * @see epoxy_has_glx_extension()
+ */
+bool
+epoxy_has_egl_extension(EGLDisplay dpy, const char *ext)
+{
+ return epoxy_extension_in_string(eglQueryString(dpy, EGL_EXTENSIONS), ext) || epoxy_extension_in_string(eglQueryString(NULL, EGL_EXTENSIONS), ext);
+}
+
+/**
+ * @brief Checks whether EGL is available.
+ *
+ * @return `true` if EGL is available
+ *
+ * @newin{1,4}
+ */
+bool
+epoxy_has_egl(void)
+{
+#if !PLATFORM_HAS_EGL
+ return false;
+#else
+ if (epoxy_load_egl(false, true)) {
+ EGLDisplay* (* pf_eglGetCurrentDisplay) (void);
+
+ pf_eglGetCurrentDisplay = epoxy_conservative_egl_dlsym("eglGetCurrentDisplay", false);
+ if (pf_eglGetCurrentDisplay)
+ return true;
+ }
+
+ return false;
+#endif /* PLATFORM_HAS_EGL */
+}
diff --git a/src/dispatch_glx.c b/src/dispatch_glx.c
new file mode 100644
index 0000000..e395564
--- /dev/null
+++ b/src/dispatch_glx.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dispatch_common.h"
+
+/**
+ * If we can determine the GLX version from the current context, then
+ * return that, otherwise return a version that will just send us on
+ * to dlsym() or get_proc_address().
+ */
+int
+epoxy_conservative_glx_version(void)
+{
+ Display *dpy = glXGetCurrentDisplay();
+ GLXContext ctx = glXGetCurrentContext();
+ int screen;
+
+ if (!dpy || !ctx)
+ return 14;
+
+ glXQueryContext(dpy, ctx, GLX_SCREEN, &screen);
+
+ return epoxy_glx_version(dpy, screen);
+}
+
+
+/**
+ * @brief Returns the version of GLX we are using
+ *
+ * The version is encoded as:
+ *
+ * ```
+ *
+ * version = major * 10 + minor
+ *
+ * ```
+ *
+ * So it can be easily used for version comparisons.
+ *
+ * @param dpy The X11 display
+ * @param screen The X11 screen
+ *
+ * @return The encoded version of GLX we are using
+ *
+ * @see epoxy_gl_version()
+ */
+int
+epoxy_glx_version(Display *dpy, int screen)
+{
+ int server_major, server_minor;
+ int client_major, client_minor;
+ int server, client;
+ const char *version_string;
+ int ret;
+
+ version_string = glXQueryServerString(dpy, screen, GLX_VERSION);
+ if (!version_string)
+ return 0;
+
+ ret = sscanf(version_string, "%d.%d", &server_major, &server_minor);
+ assert(ret == 2);
+ server = server_major * 10 + server_minor;
+
+ version_string = glXGetClientString(dpy, GLX_VERSION);
+ if (!version_string)
+ return 0;
+
+ ret = sscanf(version_string, "%d.%d", &client_major, &client_minor);
+ assert(ret == 2);
+ client = client_major * 10 + client_minor;
+
+ if (client < server)
+ return client;
+ else
+ return server;
+}
+
+/**
+ * If we can determine the GLX extension support from the current
+ * context, then return that, otherwise give the answer that will just
+ * send us on to get_proc_address().
+ */
+bool
+epoxy_conservative_has_glx_extension(const char *ext)
+{
+ Display *dpy = glXGetCurrentDisplay();
+ GLXContext ctx = glXGetCurrentContext();
+ int screen;
+
+ if (!dpy || !ctx)
+ return true;
+
+ glXQueryContext(dpy, ctx, GLX_SCREEN, &screen);
+
+ return epoxy_has_glx_extension(dpy, screen, ext);
+}
+
+/**
+ * @brief Returns true if the given GLX extension is supported in the current context.
+ *
+ * @param dpy The X11 display
+ * @param screen The X11 screen
+ * @param extension The name of the GLX extension
+ *
+ * @return `true` if the extension is available
+ *
+ * @see epoxy_has_gl_extension()
+ * @see epoxy_has_egl_extension()
+ */
+bool
+epoxy_has_glx_extension(Display *dpy, int screen, const char *ext)
+{
+ /* No, you can't just use glXGetClientString or
+ * glXGetServerString() here. Those each tell you about one half
+ * of what's needed for an extension to be supported, and
+ * glXQueryExtensionsString() is what gives you the intersection
+ * of the two.
+ */
+ return epoxy_extension_in_string(glXQueryExtensionsString(dpy, screen), ext);
+}
+
+/**
+ * @brief Checks whether GLX is available.
+ *
+ * @param dpy The X11 display
+ *
+ * @return `true` if GLX is available
+ *
+ * @newin{1,4}
+ */
+bool
+epoxy_has_glx(Display *dpy)
+{
+#if !PLATFORM_HAS_GLX
+ return false;
+#else
+ if (epoxy_load_glx(false, true)) {
+ Bool (* pf_glXQueryExtension) (Display *, int *, int *);
+ int error_base, event_base;
+
+ pf_glXQueryExtension = epoxy_conservative_glx_dlsym("glXQueryExtension", false);
+ if (pf_glXQueryExtension && pf_glXQueryExtension(dpy, &error_base, &event_base))
+ return true;
+ }
+
+ return false;
+#endif /* !PLATFORM_HAS_GLX */
+}
diff --git a/src/dispatch_wgl.c b/src/dispatch_wgl.c
new file mode 100644
index 0000000..7baf130
--- /dev/null
+++ b/src/dispatch_wgl.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dispatch_common.h"
+
+static bool first_context_current = false;
+static bool already_switched_to_dispatch_table = false;
+
+/**
+ * If we can determine the WGL extension support from the current
+ * context, then return that, otherwise give the answer that will just
+ * send us on to get_proc_address().
+ */
+bool
+epoxy_conservative_has_wgl_extension(const char *ext)
+{
+ HDC hdc = wglGetCurrentDC();
+
+ if (!hdc)
+ return true;
+
+ return epoxy_has_wgl_extension(hdc, ext);
+}
+
+bool
+epoxy_has_wgl_extension(HDC hdc, const char *ext)
+ {
+ PFNWGLGETEXTENSIONSSTRINGARBPROC getext;
+
+ getext = (void *)wglGetProcAddress("wglGetExtensionsStringARB");
+ if (!getext) {
+ fputs("Implementation unexpectedly missing "
+ "WGL_ARB_extensions_string. Probably a libepoxy bug.\n",
+ stderr);
+ return false;
+ }
+
+ return epoxy_extension_in_string(getext(hdc), ext);
+}
+
+/**
+ * Does the work necessary to update the win32 per-thread dispatch
+ * tables when wglMakeCurrent() is called.
+ *
+ * Right now, we use global function pointers until the second
+ * MakeCurrent occurs, at which point we switch to dispatch tables.
+ * This could be improved in the future to track a resolved dispatch
+ * table per context and reuse it when the context is made current
+ * again.
+ */
+void
+epoxy_handle_external_wglMakeCurrent(void)
+{
+ if (!first_context_current) {
+ first_context_current = true;
+ } else {
+ if (!already_switched_to_dispatch_table) {
+ already_switched_to_dispatch_table = true;
+ gl_switch_to_dispatch_table();
+ wgl_switch_to_dispatch_table();
+ }
+
+ gl_init_dispatch_table();
+ wgl_init_dispatch_table();
+ }
+}
+
+/**
+ * This global symbol is apparently looked up by Windows when loading
+ * a DLL, but it doesn't declare the prototype.
+ */
+BOOL WINAPI
+DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved);
+
+BOOL WINAPI
+DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
+{
+ void *data;
+
+ switch (reason) {
+ case DLL_PROCESS_ATTACH:
+ gl_tls_index = TlsAlloc();
+ if (gl_tls_index == TLS_OUT_OF_INDEXES)
+ return FALSE;
+ wgl_tls_index = TlsAlloc();
+ if (wgl_tls_index == TLS_OUT_OF_INDEXES)
+ return FALSE;
+
+ first_context_current = false;
+
+ /* FALLTHROUGH */
+
+ case DLL_THREAD_ATTACH:
+ data = LocalAlloc(LPTR, gl_tls_size);
+ TlsSetValue(gl_tls_index, data);
+
+ data = LocalAlloc(LPTR, wgl_tls_size);
+ TlsSetValue(wgl_tls_index, data);
+
+ break;
+
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ data = TlsGetValue(gl_tls_index);
+ LocalFree(data);
+
+ data = TlsGetValue(wgl_tls_index);
+ LocalFree(data);
+
+ if (reason == DLL_PROCESS_DETACH) {
+ TlsFree(gl_tls_index);
+ TlsFree(wgl_tls_index);
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+WRAPPER_VISIBILITY (BOOL)
+WRAPPER(epoxy_wglMakeCurrent)(HDC hdc, HGLRC hglrc)
+{
+ BOOL ret = epoxy_wglMakeCurrent_unwrapped(hdc, hglrc);
+
+ epoxy_handle_external_wglMakeCurrent();
+
+ return ret;
+}
+
+
+WRAPPER_VISIBILITY (BOOL)
+WRAPPER(epoxy_wglMakeContextCurrentARB)(HDC hDrawDC,
+ HDC hReadDC,
+ HGLRC hglrc)
+{
+ BOOL ret = epoxy_wglMakeContextCurrentARB_unwrapped(hDrawDC, hReadDC,
+ hglrc);
+
+ epoxy_handle_external_wglMakeCurrent();
+
+ return ret;
+}
+
+
+WRAPPER_VISIBILITY (BOOL)
+WRAPPER(epoxy_wglMakeContextCurrentEXT)(HDC hDrawDC,
+ HDC hReadDC,
+ HGLRC hglrc)
+{
+ BOOL ret = epoxy_wglMakeContextCurrentEXT_unwrapped(hDrawDC, hReadDC,
+ hglrc);
+
+ epoxy_handle_external_wglMakeCurrent();
+
+ return ret;
+}
+
+
+WRAPPER_VISIBILITY (BOOL)
+WRAPPER(epoxy_wglMakeAssociatedContextCurrentAMD)(HGLRC hglrc)
+{
+ BOOL ret = epoxy_wglMakeAssociatedContextCurrentAMD_unwrapped(hglrc);
+
+ epoxy_handle_external_wglMakeCurrent();
+
+ return ret;
+}
+
+PFNWGLMAKECURRENTPROC epoxy_wglMakeCurrent = epoxy_wglMakeCurrent_wrapped;
+PFNWGLMAKECONTEXTCURRENTEXTPROC epoxy_wglMakeContextCurrentEXT = epoxy_wglMakeContextCurrentEXT_wrapped;
+PFNWGLMAKECONTEXTCURRENTARBPROC epoxy_wglMakeContextCurrentARB = epoxy_wglMakeContextCurrentARB_wrapped;
+PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC epoxy_wglMakeAssociatedContextCurrentEXT = epoxy_wglMakeAssociatedContextCurrentAMD_wrapped;
diff --git a/src/gen_dispatch.py b/src/gen_dispatch.py
new file mode 100755
index 0000000..f4d0f31
--- /dev/null
+++ b/src/gen_dispatch.py
@@ -0,0 +1,914 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2013 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import sys
+import argparse
+import xml.etree.ElementTree as ET
+import re
+import os
+
+class GLProvider(object):
+ def __init__(self, condition, condition_name, loader, name):
+ # C code for determining if this function is available.
+ # (e.g. epoxy_is_desktop_gl() && epoxy_gl_version() >= 20
+ self.condition = condition
+
+ # A string (possibly with spaces) describing the condition.
+ self.condition_name = condition_name
+
+ # The loader for getting the symbol -- either dlsym or
+ # getprocaddress. This is a python format string to generate
+ # C code, given self.name.
+ self.loader = loader
+
+ # The name of the function to be loaded (possibly an
+ # ARB/EXT/whatever-decorated variant).
+ self.name = name
+
+ # This is the C enum name we'll use for referring to this provider.
+ self.enum = condition_name
+ self.enum = self.enum.replace(' ', '_')
+ self.enum = self.enum.replace('\\"', '')
+ self.enum = self.enum.replace('.', '_')
+ self.enum = "PROVIDER_" + self.enum
+
+class GLFunction(object):
+ def __init__(self, ret_type, name):
+ self.name = name
+ self.ptr_type = 'PFN' + name.upper() + 'PROC'
+ self.ret_type = ret_type
+ self.providers = {}
+ self.args = []
+
+ # These are functions with hand-written wrapper code in
+ # dispatch_common.c. Their dispatch entries are replaced with
+ # non-public symbols with a "_unwrapped" suffix.
+ wrapped_functions = {
+ 'glBegin',
+ 'glEnd',
+ 'wglMakeCurrent',
+ 'wglMakeContextCurrentEXT',
+ 'wglMakeContextCurrentARB',
+ 'wglMakeAssociatedContextCurrentAMD',
+ }
+
+ if name in wrapped_functions:
+ self.wrapped_name = name + '_unwrapped'
+ self.public = ''
+ else:
+ self.wrapped_name = name
+ self.public = 'EPOXY_PUBLIC '
+
+ # This is the string of C code for passing through the
+ # arguments to the function.
+ self.args_list = ''
+
+ # This is the string of C code for declaring the arguments
+ # list.
+ self.args_decl = 'void'
+
+ # This is the string name of the function that this is an
+ # alias of, or self.name. This initially comes from the
+ # registry, and may get updated if it turns out our alias is
+ # itself an alias (for example glFramebufferTextureEXT ->
+ # glFramebufferTextureARB -> glFramebufferTexture)
+ self.alias_name = name
+
+ # After alias resolution, this is the function that this is an
+ # alias of.
+ self.alias_func = None
+
+ # For the root of an alias tree, this lists the functions that
+ # are marked as aliases of it, so that it can write a resolver
+ # for all of them.
+ self.alias_exts = []
+
+ def add_arg(self, arg_type, arg_name):
+ # Reword glDepthRange() arguments to avoid clashing with the
+ # "near" and "far" keywords on win32.
+ if arg_name == "near":
+ arg_name = "hither"
+ elif arg_name == "far":
+ arg_name = "yon"
+
+ # Mac screwed up GLhandleARB and made it a void * instead of
+ # uint32_t, despite it being specced as only necessarily 32
+ # bits wide, causing portability problems all over. There are
+ # prototype conflicts between things like
+ # glAttachShader(GLuint program, GLuint shader) and
+ # glAttachObjectARB(GLhandleARB container, GLhandleARB obj),
+ # even though they are marked as aliases in the XML (and being
+ # aliases in Mesa).
+ #
+ # We retain those aliases. In the x86_64 ABI, the first 6
+ # args are stored in 64-bit registers, so the calls end up
+ # being the same despite the different types. We just need to
+ # add a cast to uintptr_t to shut up the compiler.
+ if arg_type == 'GLhandleARB':
+ assert len(self.args) < 6
+ arg_list_name = '(uintptr_t)' + arg_name
+ else:
+ arg_list_name = arg_name
+
+ self.args.append((arg_type, arg_name))
+ if self.args_decl == 'void':
+ self.args_list = arg_list_name
+ self.args_decl = arg_type + ' ' + arg_name
+ else:
+ self.args_list += ', ' + arg_list_name
+ self.args_decl += ', ' + arg_type + ' ' + arg_name
+
+ def add_provider(self, condition, loader, condition_name):
+ self.providers[condition_name] = GLProvider(condition, condition_name,
+ loader, self.name)
+
+ def add_alias(self, ext):
+ assert self.alias_func is None
+
+ self.alias_exts.append(ext)
+ ext.alias_func = self
+
+class Generator(object):
+ def __init__(self, target):
+ self.target = target
+ self.enums = {}
+ self.functions = {}
+ self.sorted_functions = []
+ self.enum_string_offset = {}
+ self.max_enum_name_len = 1
+ self.entrypoint_string_offset = {}
+ self.copyright_comment = None
+ self.typedefs = ''
+ self.out_file = None
+
+ # GL versions named in the registry, which we should generate
+ # #defines for.
+ self.supported_versions = set()
+
+ # Extensions named in the registry, which we should generate
+ # #defines for.
+ self.supported_extensions = set()
+
+ # Dictionary mapping human-readable names of providers to a C
+ # enum token that will be used to reference those names, to
+ # reduce generated binary size.
+ self.provider_enum = {}
+
+ # Dictionary mapping human-readable names of providers to C
+ # code to detect if it's present.
+ self.provider_condition = {}
+
+ # Dictionary mapping human-readable names of providers to
+ # format strings for fetching the function pointer when
+ # provided the name of the symbol to be requested.
+ self.provider_loader = {}
+
+ def all_text_until_element_name(self, element, element_name):
+ text = ''
+
+ if element.text is not None:
+ text += element.text
+
+ for child in element:
+ if child.tag == element_name:
+ break
+ if child.text:
+ text += child.text
+ if child.tail:
+ text += child.tail
+ return text
+
+ def out(self, text):
+ self.out_file.write(text)
+
+ def outln(self, text):
+ self.out_file.write(text + '\n')
+
+ def parse_typedefs(self, reg):
+ for t in reg.findall('types/type'):
+ if 'name' in t.attrib and t.attrib['name'] not in {'GLhandleARB'}:
+ continue
+
+ # The gles1/gles2-specific types are redundant
+ # declarations, and the different types used for them (int
+ # vs int32_t) caused problems on win32 builds.
+ api = t.get('api')
+ if api:
+ continue
+
+ if t.text is not None:
+ self.typedefs += t.text
+
+ for child in t:
+ if child.tag == 'apientry':
+ self.typedefs += 'APIENTRY'
+ if child.text:
+ self.typedefs += child.text
+ if child.tail:
+ self.typedefs += child.tail
+ self.typedefs += '\n'
+
+ def parse_enums(self, reg):
+ for enum in reg.findall('enums/enum'):
+ name = enum.get('name')
+
+ # wgl.xml's 0xwhatever definitions end up colliding with
+ # wingdi.h's decimal definitions of these.
+ if name in ['WGL_SWAP_OVERLAY', 'WGL_SWAP_UNDERLAY', 'WGL_SWAP_MAIN_PLANE']:
+ continue
+
+ self.max_enum_name_len = max(self.max_enum_name_len, len(name))
+ self.enums[name] = enum.get('value')
+
+ def get_function_return_type(self, proto):
+ # Everything up to the start of the name element is the return type.
+ return self.all_text_until_element_name(proto, 'name').strip()
+
+ def parse_function_definitions(self, reg):
+ for command in reg.findall('commands/command'):
+ proto = command.find('proto')
+ name = proto.find('name').text
+ ret_type = self.get_function_return_type(proto)
+
+ func = GLFunction(ret_type, name)
+
+ for arg in command.findall('param'):
+ func.add_arg(self.all_text_until_element_name(arg, 'name').strip(),
+ arg.find('name').text)
+
+ alias = command.find('alias')
+ if alias is not None:
+ # Note that some alias references appear before the
+ # target command is defined (glAttachObjectARB() ->
+ # glAttachShader(), for example).
+ func.alias_name = alias.get('name')
+
+ self.functions[name] = func
+
+ def drop_weird_glx_functions(self):
+ # Drop a few ancient SGIX GLX extensions that use types not defined
+ # anywhere in Xlib. In glxext.h, they're protected by #ifdefs for the
+ # headers that defined them.
+ weird_functions = [name for name, func in self.functions.items()
+ if 'VLServer' in func.args_decl
+ or 'DMparams' in func.args_decl]
+
+ for name in weird_functions:
+ del self.functions[name]
+
+ def resolve_aliases(self):
+ for func in self.functions.values():
+ # Find the root of the alias tree, and add ourselves to it.
+ if func.alias_name != func.name:
+ alias_func = func
+ while alias_func.alias_name != alias_func.name:
+ alias_func = self.functions[alias_func.alias_name]
+ func.alias_name = alias_func.name
+ func.alias_func = alias_func
+ alias_func.alias_exts.append(func)
+
+ def prepare_provider_enum(self):
+ self.provider_enum = {}
+
+ # We assume that for any given provider, all functions using
+ # it will have the same loader. This lets us generate a
+ # general C function for detecting conditions and calling the
+ # dlsym/getprocaddress, and have our many resolver stubs just
+ # call it with a table of values.
+ for func in self.functions.values():
+ for provider in func.providers.values():
+ if provider.condition_name in self.provider_enum:
+ assert self.provider_condition[provider.condition_name] == provider.condition
+ assert self.provider_loader[provider.condition_name] == provider.loader
+ continue
+
+ self.provider_enum[provider.condition_name] = provider.enum
+ self.provider_condition[provider.condition_name] = provider.condition
+ self.provider_loader[provider.condition_name] = provider.loader
+
+ def sort_functions(self):
+ self.sorted_functions = sorted(self.functions.values(), key=lambda func: func.name)
+
+ def process_require_statements(self, feature, condition, loader, human_name):
+ for command in feature.findall('require/command'):
+ name = command.get('name')
+
+ # wgl.xml describes 6 functions in WGL 1.0 that are in
+ # gdi32.dll instead of opengl32.dll, and we would need to
+ # change up our symbol loading to support that. Just
+ # don't wrap those functions.
+ if self.target == 'wgl' and 'wgl' not in name:
+ del self.functions[name]
+ continue
+
+ func = self.functions[name]
+ func.add_provider(condition, loader, human_name)
+
+ def parse_function_providers(self, reg):
+ for feature in reg.findall('feature'):
+ api = feature.get('api') # string gl, gles1, gles2, glx
+ m = re.match(r'([0-9])\.([0-9])', feature.get('number'))
+ version = int(m.group(1)) * 10 + int(m.group(2))
+
+ self.supported_versions.add(feature.get('name'))
+
+ if api == 'gl':
+ human_name = 'Desktop OpenGL {0}'.format(feature.get('number'))
+ condition = 'epoxy_is_desktop_gl()'
+
+ loader = 'epoxy_get_core_proc_address({0}, {1})'.format('{0}', version)
+ if version >= 11:
+ condition += ' && epoxy_conservative_gl_version() >= {0}'.format(version)
+ elif api == 'gles2':
+ human_name = 'OpenGL ES {0}'.format(feature.get('number'))
+ condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= {0}'.format(version)
+
+ if version <= 20:
+ loader = 'epoxy_gles2_dlsym({0})'
+ else:
+ loader = 'epoxy_gles3_dlsym({0})'
+ elif api == 'gles1':
+ human_name = 'OpenGL ES 1.0'
+ condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= 10 && epoxy_gl_version() < 20'
+ loader = 'epoxy_gles1_dlsym({0})'
+ elif api == 'glx':
+ human_name = 'GLX {0}'.format(version)
+ # We could just always use GPA for loading everything
+ # but glXGetProcAddress(), but dlsym() is a more
+ # efficient lookup.
+ if version > 13:
+ condition = 'epoxy_conservative_glx_version() >= {0}'.format(version)
+ loader = 'glXGetProcAddress((const GLubyte *){0})'
+ else:
+ condition = 'true'
+ loader = 'epoxy_glx_dlsym({0})'
+ elif api == 'egl':
+ human_name = 'EGL {0}'.format(version)
+ if version > 10:
+ condition = 'epoxy_conservative_egl_version() >= {0}'.format(version)
+ else:
+ condition = 'true'
+ # All EGL core entrypoints must be dlsym()ed out --
+ # eglGetProcAdddress() will return NULL.
+ loader = 'epoxy_egl_dlsym({0})'
+ elif api == 'wgl':
+ human_name = 'WGL {0}'.format(version)
+ condition = 'true'
+ loader = 'epoxy_gl_dlsym({0})'
+ elif api == 'glsc2':
+ continue
+ else:
+ sys.exit('unknown API: "{0}"'.format(api))
+
+ self.process_require_statements(feature, condition, loader, human_name)
+
+ for extension in reg.findall('extensions/extension'):
+ extname = extension.get('name')
+ cond_extname = "enum_string[enum_string_offsets[i]]"
+
+ self.supported_extensions.add(extname)
+
+ # 'supported' is a set of strings like gl, gles1, gles2,
+ # or glx, which are separated by '|'
+ apis = extension.get('supported').split('|')
+ if 'glx' in apis:
+ condition = 'epoxy_conservative_has_glx_extension(provider_name)'
+ loader = 'glXGetProcAddress((const GLubyte *){0})'
+ self.process_require_statements(extension, condition, loader, extname)
+ if 'egl' in apis:
+ condition = 'epoxy_conservative_has_egl_extension(provider_name)'
+ loader = 'eglGetProcAddress({0})'
+ self.process_require_statements(extension, condition, loader, extname)
+ if 'wgl' in apis:
+ condition = 'epoxy_conservative_has_wgl_extension(provider_name)'
+ loader = 'wglGetProcAddress({0})'
+ self.process_require_statements(extension, condition, loader, extname)
+ if {'gl', 'gles1', 'gles2'}.intersection(apis):
+ condition = 'epoxy_conservative_has_gl_extension(provider_name)'
+ loader = 'epoxy_get_proc_address({0})'
+ self.process_require_statements(extension, condition, loader, extname)
+
+ def fixup_bootstrap_function(self, name, loader):
+ # We handle glGetString(), glGetIntegerv(), and
+ # glXGetProcAddressARB() specially, because we need to use
+ # them in the process of deciding on loaders for resolving,
+ # and the naive code generation would result in their
+ # resolvers calling their own resolvers.
+ if name not in self.functions:
+ return
+
+ func = self.functions[name]
+ func.providers = {}
+ func.add_provider('true', loader, 'always present')
+
+ def parse(self, xml_file):
+ reg = ET.parse(xml_file)
+ comment = reg.find('comment')
+ if comment is not None:
+ self.copyright_comment = comment.text
+ else:
+ self.copyright_comment = ''
+ self.parse_typedefs(reg)
+ self.parse_enums(reg)
+ self.parse_function_definitions(reg)
+ self.parse_function_providers(reg)
+
+ def write_copyright_comment_body(self):
+ for line in self.copyright_comment.splitlines():
+ if '-----' in line:
+ break
+ self.outln(' * ' + line)
+
+ def write_enums(self):
+ for name in sorted(self.supported_versions):
+ self.outln('#define {0} 1'.format(name))
+ self.outln('')
+
+ for name in sorted(self.supported_extensions):
+ self.outln('#define {0} 1'.format(name))
+ self.outln('')
+
+ # We want to sort by enum number (which puts a bunch of things
+ # in a logical order), then by name after that, so we do those
+ # sorts in reverse. This is still way uglier than doing some
+ # sort based on what version/extensions things are introduced
+ # in, but we haven't paid any attention to those attributes
+ # for enums yet.
+ sorted_by_name = sorted(self.enums.keys())
+ sorted_by_number = sorted(sorted_by_name, key=lambda name: self.enums[name])
+ for name in sorted_by_number:
+ self.outln('#define ' + name.ljust(self.max_enum_name_len + 3) + self.enums[name] + '')
+
+ def write_function_ptr_typedefs(self):
+ for func in self.sorted_functions:
+ self.outln('typedef {0} (GLAPIENTRY *{1})({2});'.format(func.ret_type,
+ func.ptr_type,
+ func.args_decl))
+
+ def write_header_header(self, out_file):
+ self.out_file = open(out_file, 'w')
+
+ self.outln('/* GL dispatch header.')
+ self.outln(' * This is code-generated from the GL API XML files from Khronos.')
+ self.write_copyright_comment_body()
+ self.outln(' */')
+ self.outln('')
+
+ self.outln('#pragma once')
+
+ self.outln('#include <inttypes.h>')
+ self.outln('#include <stddef.h>')
+ self.outln('')
+
+ def write_header(self, out_file):
+ self.write_header_header(out_file)
+
+ self.outln('#include "epoxy/common.h"')
+
+ if self.target != "gl":
+ self.outln('#include "epoxy/gl.h"')
+ if self.target == "egl":
+ self.outln('#include "EGL/eglplatform.h"')
+ # Account for older eglplatform.h, which doesn't define
+ # the EGL_CAST macro.
+ self.outln('#ifndef EGL_CAST')
+ self.outln('#if defined(__cplusplus)')
+ self.outln('#define EGL_CAST(type, value) (static_cast<type>(value))')
+ self.outln('#else')
+ self.outln('#define EGL_CAST(type, value) ((type) (value))')
+ self.outln('#endif')
+ self.outln('#endif')
+ else:
+ # Add some ridiculous inttypes.h redefinitions that are
+ # from khrplatform.h and not included in the XML. We
+ # don't directly include khrplatform.h because it's not
+ # present on many systems, and coming up with #ifdefs to
+ # decide when it's not present would be hard.
+ self.outln('#define __khrplatform_h_ 1')
+ self.outln('typedef int8_t khronos_int8_t;')
+ self.outln('typedef int16_t khronos_int16_t;')
+ self.outln('typedef int32_t khronos_int32_t;')
+ self.outln('typedef int64_t khronos_int64_t;')
+ self.outln('typedef uint8_t khronos_uint8_t;')
+ self.outln('typedef uint16_t khronos_uint16_t;')
+ self.outln('typedef uint32_t khronos_uint32_t;')
+ self.outln('typedef uint64_t khronos_uint64_t;')
+ self.outln('typedef float khronos_float_t;')
+ self.outln('typedef long khronos_intptr_t;')
+ self.outln('typedef long khronos_ssize_t;')
+ self.outln('typedef unsigned long khronos_usize_t;')
+ self.outln('typedef uint64_t khronos_utime_nanoseconds_t;')
+ self.outln('typedef int64_t khronos_stime_nanoseconds_t;')
+ self.outln('#define KHRONOS_MAX_ENUM 0x7FFFFFFF')
+ self.outln('typedef enum {')
+ self.outln(' KHRONOS_FALSE = 0,')
+ self.outln(' KHRONOS_TRUE = 1,')
+ self.outln(' KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM')
+ self.outln('} khronos_boolean_enum_t;')
+ self.outln('typedef uintptr_t khronos_uintptr_t;')
+
+ if self.target == "glx":
+ self.outln('#include <X11/Xlib.h>')
+ self.outln('#include <X11/Xutil.h>')
+
+ self.out(self.typedefs)
+ self.outln('')
+ self.write_enums()
+ self.outln('')
+ self.write_function_ptr_typedefs()
+
+ for func in self.sorted_functions:
+ self.outln('EPOXY_PUBLIC {0} (EPOXY_CALLSPEC *epoxy_{1})({2});'.format(func.ret_type,
+ func.name,
+ func.args_decl))
+ self.outln('')
+
+ for func in self.sorted_functions:
+ self.outln('#define {0} epoxy_{0}'.format(func.name))
+
+ def write_function_ptr_resolver(self, func):
+ self.outln('static {0}'.format(func.ptr_type))
+ self.outln('epoxy_{0}_resolver(void)'.format(func.wrapped_name))
+ self.outln('{')
+
+ providers = []
+ # Make a local list of all the providers for this alias group
+ alias_root = func
+ if func.alias_func:
+ alias_root = func.alias_func
+ for provider in alias_root.providers.values():
+ providers.append(provider)
+ for alias_func in alias_root.alias_exts:
+ for provider in alias_func.providers.values():
+ providers.append(provider)
+
+ # Add some partial aliases of a few functions. These are ones
+ # that aren't quite aliases, because of some trivial behavior
+ # difference (like whether to produce an error for a
+ # non-Genned name), but where we'd like to fall back to the
+ # similar function if the proper one isn't present.
+ half_aliases = {
+ 'glBindVertexArray' : 'glBindVertexArrayAPPLE',
+ 'glBindVertexArrayAPPLE' : 'glBindVertexArray',
+ 'glBindFramebuffer' : 'glBindFramebufferEXT',
+ 'glBindFramebufferEXT' : 'glBindFramebuffer',
+ 'glBindRenderbuffer' : 'glBindRenderbufferEXT',
+ 'glBindRenderbufferEXT' : 'glBindRenderbuffer',
+ }
+ if func.name in half_aliases:
+ alias_func = self.functions[half_aliases[func.name]]
+ for provider in alias_func.providers.values():
+ providers.append(provider)
+
+ def provider_sort(provider):
+ return (provider.name != func.name, provider.name, provider.enum)
+ providers.sort(key=provider_sort)
+
+ if len(providers) != 1:
+ self.outln(' static const enum {0}_provider providers[] = {{'.format(self.target))
+ for provider in providers:
+ self.outln(' {0},'.format(provider.enum))
+ self.outln(' {0}_provider_terminator'.format(self.target))
+ self.outln(' };')
+
+ self.outln(' static const uint32_t entrypoints[] = {')
+ if len(providers) > 1:
+ for provider in providers:
+ self.outln(' {0} /* "{1}" */,'.format(self.entrypoint_string_offset[provider.name], provider.name))
+ else:
+ self.outln(' 0 /* None */,')
+ self.outln(' };')
+
+ self.outln(' return {0}_provider_resolver(entrypoint_strings + {1} /* "{2}" */,'.format(self.target,
+ self.entrypoint_string_offset[func.name],
+ func.name))
+ self.outln(' providers, entrypoints);')
+ else:
+ assert providers[0].name == func.name
+ self.outln(' return {0}_single_resolver({1}, {2} /* {3} */);'.format(self.target,
+ providers[0].enum,
+ self.entrypoint_string_offset[func.name],
+ func.name))
+ self.outln('}')
+ self.outln('')
+
+ def write_thunks(self, func):
+ # Writes out the function that's initially plugged into the
+ # global function pointer, which resolves, updates the global
+ # function pointer, and calls down to it.
+ #
+ # It also writes out the actual initialized global function
+ # pointer.
+ if func.ret_type == 'void':
+ self.outln('GEN_THUNKS({0}, ({1}), ({2}))'.format(func.wrapped_name,
+ func.args_decl,
+ func.args_list))
+ else:
+ self.outln('GEN_THUNKS_RET({0}, {1}, ({2}), ({3}))'.format(func.ret_type,
+ func.wrapped_name,
+ func.args_decl,
+ func.args_list))
+
+ def write_function_pointer(self, func):
+ self.outln('{0} epoxy_{1} = epoxy_{1}_global_rewrite_ptr;'.format(func.ptr_type, func.wrapped_name))
+ self.outln('')
+
+ def write_provider_enums(self):
+ # Writes the enum declaration for the list of providers
+ # supported by gl_provider_resolver()
+
+ self.outln('')
+ self.outln('enum {0}_provider {{'.format(self.target))
+
+ sorted_providers = sorted(self.provider_enum.keys())
+
+ # We always put a 0 enum first so that we can have a
+ # terminator in our arrays
+ self.outln(' {0}_provider_terminator = 0,'.format(self.target))
+
+ for human_name in sorted_providers:
+ enum = self.provider_enum[human_name]
+ self.outln(' {0},'.format(enum))
+ self.outln('} PACKED;')
+ self.outln('ENDPACKED')
+ self.outln('')
+
+ def write_provider_enum_strings(self):
+ # Writes the mapping from enums to the strings describing them
+ # for epoxy_print_failure_reasons().
+
+ sorted_providers = sorted(self.provider_enum.keys())
+
+ offset = 0
+ self.outln('static const char *enum_string =')
+ for human_name in sorted_providers:
+ self.outln(' "{0}\\0"'.format(human_name))
+ self.enum_string_offset[human_name] = offset
+ offset += len(human_name.replace('\\', '')) + 1
+ self.outln(' ;')
+ self.outln('')
+ # We're using uint16_t for the offsets.
+ assert offset < 65536
+
+ self.outln('static const uint16_t enum_string_offsets[] = {')
+ self.outln(' -1, /* {0}_provider_terminator, unused */'.format(self.target))
+ for human_name in sorted_providers:
+ enum = self.provider_enum[human_name]
+ self.outln(' {1}, /* {0} */'.format(human_name, self.enum_string_offset[human_name]))
+ self.outln('};')
+ self.outln('')
+
+ def write_entrypoint_strings(self):
+ self.outln('static const char entrypoint_strings[] = {')
+ offset = 0
+ for func in self.sorted_functions:
+ if func.name not in self.entrypoint_string_offset:
+ self.entrypoint_string_offset[func.name] = offset
+ offset += len(func.name) + 1
+ for c in func.name:
+ self.outln(" '{0}',".format(c))
+ self.outln(' 0, // {0}'.format(func.name))
+ self.outln(' 0 };')
+ # We're using uint16_t for the offsets.
+ #assert(offset < 65536)
+ self.outln('')
+
+ def write_provider_resolver(self):
+ self.outln('static void *{0}_provider_resolver(const char *name,'.format(self.target))
+ self.outln(' const enum {0}_provider *providers,'.format(self.target))
+ self.outln(' const uint32_t *entrypoints)')
+ self.outln('{')
+ self.outln(' int i;')
+
+ self.outln(' for (i = 0; providers[i] != {0}_provider_terminator; i++) {{'.format(self.target))
+ self.outln(' const char *provider_name = enum_string + enum_string_offsets[providers[i]];')
+ self.outln(' switch (providers[i]) {')
+ self.outln('')
+
+ for human_name in sorted(self.provider_enum.keys()):
+ enum = self.provider_enum[human_name]
+ self.outln(' case {0}:'.format(enum))
+ self.outln(' if ({0})'.format(self.provider_condition[human_name]))
+ self.outln(' return {0};'.format(self.provider_loader[human_name]).format("entrypoint_strings + entrypoints[i]"))
+ self.outln(' break;')
+
+ self.outln(' case {0}_provider_terminator:'.format(self.target))
+ self.outln(' abort(); /* Not reached */')
+ self.outln(' }')
+ self.outln(' }')
+ self.outln('')
+
+ self.outln(' if (epoxy_resolver_failure_handler)')
+ self.outln(' return epoxy_resolver_failure_handler(name);')
+ self.outln('')
+
+ # If the function isn't provided by any known extension, print
+ # something useful for the poor application developer before
+ # aborting. (In non-epoxy GL usage, the app developer would
+ # call into some blank stub function and segfault).
+ self.outln(' fprintf(stderr, "No provider of %s found. Requires one of:\\n", name);')
+ self.outln(' for (i = 0; providers[i] != {0}_provider_terminator; i++) {{'.format(self.target))
+ self.outln(' fprintf(stderr, " %s\\n", enum_string + enum_string_offsets[providers[i]]);')
+ self.outln(' }')
+ self.outln(' if (providers[0] == {0}_provider_terminator) {{'.format(self.target))
+ self.outln(' fprintf(stderr, " No known providers. This is likely a bug "')
+ self.outln(' "in libepoxy code generation\\n");')
+ self.outln(' }')
+ self.outln(' abort();')
+
+ self.outln('}')
+ self.outln('')
+
+ single_resolver_proto = '{0}_single_resolver(enum {0}_provider provider, uint32_t entrypoint_offset)'.format(self.target)
+ self.outln('EPOXY_NOINLINE static void *')
+ self.outln('{0};'.format(single_resolver_proto))
+ self.outln('')
+ self.outln('static void *')
+ self.outln('{0}'.format(single_resolver_proto))
+ self.outln('{')
+ self.outln(' enum {0}_provider providers[] = {{'.format(self.target))
+ self.outln(' provider,')
+ self.outln(' {0}_provider_terminator'.format(self.target))
+ self.outln(' };')
+ self.outln(' return {0}_provider_resolver(entrypoint_strings + entrypoint_offset,'.format(self.target))
+ self.outln(' providers, &entrypoint_offset);')
+ self.outln('}')
+ self.outln('')
+
+ def write_source(self, f):
+ self.out_file = open(f, 'w')
+
+ self.outln('/* GL dispatch code.')
+ self.outln(' * This is code-generated from the GL API XML files from Khronos.')
+ self.write_copyright_comment_body()
+ self.outln(' */')
+ self.outln('')
+ self.outln('#include "config.h"')
+ self.outln('')
+ self.outln('#include <stdlib.h>')
+ self.outln('#include <string.h>')
+ self.outln('#include <stdio.h>')
+ self.outln('')
+ self.outln('#include "dispatch_common.h"')
+ self.outln('#include "epoxy/{0}.h"'.format(self.target))
+ self.outln('')
+ self.outln('#ifdef __GNUC__')
+ self.outln('#define EPOXY_NOINLINE __attribute__((noinline))')
+ self.outln('#elif defined (_MSC_VER)')
+ self.outln('#define EPOXY_NOINLINE __declspec(noinline)')
+ self.outln('#endif')
+
+ self.outln('struct dispatch_table {')
+ for func in self.sorted_functions:
+ self.outln(' {0} epoxy_{1};'.format(func.ptr_type, func.wrapped_name))
+ self.outln('};')
+ self.outln('')
+
+ # Early declaration, so we can declare the real thing at the
+ # bottom. (I want the function_ptr_resolver as the first
+ # per-GL-call code, since it's the most interesting to see
+ # when you search for the implementation of a call)
+ self.outln('#if USING_DISPATCH_TABLE')
+ self.outln('static inline struct dispatch_table *')
+ self.outln('get_dispatch_table(void);')
+ self.outln('')
+ self.outln('#endif')
+
+ self.write_provider_enums()
+ self.write_provider_enum_strings()
+ self.write_entrypoint_strings()
+ self.write_provider_resolver()
+
+ for func in self.sorted_functions:
+ self.write_function_ptr_resolver(func)
+
+ for func in self.sorted_functions:
+ self.write_thunks(func)
+ self.outln('')
+
+ self.outln('#if USING_DISPATCH_TABLE')
+
+ self.outln('static struct dispatch_table resolver_table = {')
+ for func in self.sorted_functions:
+ self.outln(' epoxy_{0}_dispatch_table_rewrite_ptr, /* {0} */'.format(func.wrapped_name))
+ self.outln('};')
+ self.outln('')
+
+ self.outln('uint32_t {0}_tls_index;'.format(self.target))
+ self.outln('uint32_t {0}_tls_size = sizeof(struct dispatch_table);'.format(self.target))
+ self.outln('')
+
+ self.outln('static inline struct dispatch_table *')
+ self.outln('get_dispatch_table(void)')
+ self.outln('{')
+ self.outln(' return TlsGetValue({0}_tls_index);'.format(self.target))
+ self.outln('}')
+ self.outln('')
+
+ self.outln('void')
+ self.outln('{0}_init_dispatch_table(void)'.format(self.target))
+ self.outln('{')
+ self.outln(' struct dispatch_table *dispatch_table = get_dispatch_table();')
+ self.outln(' memcpy(dispatch_table, &resolver_table, sizeof(resolver_table));')
+ self.outln('}')
+ self.outln('')
+
+ self.outln('void')
+ self.outln('{0}_switch_to_dispatch_table(void)'.format(self.target))
+ self.outln('{')
+
+ for func in self.sorted_functions:
+ self.outln(' epoxy_{0} = epoxy_{0}_dispatch_table_thunk;'.format(func.wrapped_name))
+
+ self.outln('}')
+ self.outln('')
+
+ self.outln('#endif /* !USING_DISPATCH_TABLE */')
+
+ for func in self.sorted_functions:
+ self.write_function_pointer(func)
+
+argparser = argparse.ArgumentParser(description='Generate GL dispatch wrappers.')
+argparser.add_argument('files', metavar='file.xml', nargs='+', help='GL API XML files to be parsed')
+argparser.add_argument('--outputdir', metavar='dir', required=False, help='Destination directory for files (default to current dir)')
+argparser.add_argument('--includedir', metavar='dir', required=False, help='Destination directory for headers')
+argparser.add_argument('--srcdir', metavar='dir', required=False, help='Destination directory for source')
+argparser.add_argument('--source', dest='source', action='store_true', required=False, help='Generate the source file')
+argparser.add_argument('--no-source', dest='source', action='store_false', required=False, help='Do not generate the source file')
+argparser.add_argument('--header', dest='header', action='store_true', required=False, help='Generate the header file')
+argparser.add_argument('--no-header', dest='header', action='store_false', required=False, help='Do not generate the header file')
+args = argparser.parse_args()
+
+if args.outputdir:
+ outputdir = args.outputdir
+else:
+ outputdir = os.getcwd()
+
+if args.includedir:
+ includedir = args.includedir
+else:
+ includedir = outputdir
+
+if args.srcdir:
+ srcdir = args.srcdir
+else:
+ srcdir = outputdir
+
+build_source = args.source
+build_header = args.header
+
+if not build_source and not build_header:
+ build_source = True
+ build_header = True
+
+for f in args.files:
+ name = os.path.basename(f).split('.xml')[0]
+ generator = Generator(name)
+ generator.parse(f)
+
+ generator.drop_weird_glx_functions()
+
+ # This is an ANSI vs Unicode function, handled specially by
+ # include/epoxy/wgl.h
+ if 'wglUseFontBitmaps' in generator.functions:
+ del generator.functions['wglUseFontBitmaps']
+
+ generator.sort_functions()
+ generator.resolve_aliases()
+ generator.fixup_bootstrap_function('glGetString',
+ 'epoxy_get_bootstrap_proc_address({0})')
+ generator.fixup_bootstrap_function('glGetIntegerv',
+ 'epoxy_get_bootstrap_proc_address({0})')
+
+ # While this is technically exposed as a GLX extension, it's
+ # required to be present as a public symbol by the Linux OpenGL
+ # ABI.
+ generator.fixup_bootstrap_function('glXGetProcAddress',
+ 'epoxy_glx_dlsym({0})')
+
+ generator.prepare_provider_enum()
+
+ if build_header:
+ generator.write_header(os.path.join(includedir, name + '_generated.h'))
+ if build_source:
+ generator.write_source(os.path.join(srcdir, name + '_generated_dispatch.c'))
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..fe092d1
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,112 @@
+# Configuration file
+configure_file(output: 'config.h', configuration: conf)
+
+# List of generated sources:
+# - name of the generated file
+# - registry source file
+# - additional sources
+generated_sources = [
+ [ 'gl_generated_dispatch.c', gl_registry, [ 'dispatch_common.c', 'dispatch_common.h' ] ]
+]
+
+if build_egl
+ generated_sources += [ [ 'egl_generated_dispatch.c', egl_registry, 'dispatch_egl.c' ] ]
+endif
+
+if build_glx
+ generated_sources += [ [ 'glx_generated_dispatch.c', glx_registry, 'dispatch_glx.c' ] ]
+endif
+
+if build_wgl
+ generated_sources += [ [ 'wgl_generated_dispatch.c', wgl_registry, 'dispatch_wgl.c' ] ]
+endif
+
+gen_sources = [ ]
+sources = [ ]
+
+foreach g: generated_sources
+ gen_source = g[0]
+ registry = g[1]
+ source = g[2]
+
+ generated = custom_target(gen_source,
+ input: registry,
+ output: [ gen_source ],
+ command: [
+ python,
+ gen_dispatch_py,
+ '--source',
+ '--no-header',
+ '--outputdir=@OUTDIR@',
+ '@INPUT@',
+ ])
+
+ gen_sources += [ generated ]
+ sources += [ source ]
+endforeach
+
+epoxy_sources = sources + gen_sources
+
+common_ldflags = []
+
+if host_system == 'linux' and cc.get_id() == 'gcc'
+ common_ldflags += cc.get_supported_link_arguments([ '-Wl,-Bsymbolic-functions', '-Wl,-z,relro' ])
+endif
+
+# Maintain compatibility with autotools; see: https://github.com/anholt/libepoxy/issues/108
+if host_system == 'darwin'
+ common_ldflags += [ '-compatibility_version 1', '-current_version 1.0', ]
+endif
+
+epoxy_deps = [ dl_dep, ]
+if host_system == 'windows'
+ epoxy_deps += [ opengl32_dep, gdi32_dep ]
+endif
+
+libepoxy = library(
+ 'epoxy',
+ sources: epoxy_sources + epoxy_headers,
+ version: '0.0.0',
+ install: true,
+ dependencies: epoxy_deps,
+ include_directories: libepoxy_inc,
+ c_args: common_cflags + visibility_cflags,
+ link_args: common_ldflags,
+)
+
+libepoxy_dep = declare_dependency(
+ link_with: libepoxy,
+ include_directories: libepoxy_inc,
+ dependencies: epoxy_deps,
+ sources: epoxy_headers,
+)
+
+epoxy_has_glx = build_glx ? '1' : '0'
+epoxy_has_egl = build_egl ? '1' : '0'
+epoxy_has_wgl = build_wgl ? '1' : '0'
+
+# We don't want to add these dependencies to the library, as they are
+# not needed when building Epoxy; we do want to add them to the generated
+# pkg-config file, for consumers of Epoxy
+gl_reqs = []
+if gl_dep.found() and gl_dep.type_name() == 'pkgconfig'
+ gl_reqs += 'gl'
+endif
+if build_egl and egl_dep.found() and egl_dep.type_name() == 'pkgconfig'
+ gl_reqs += 'egl'
+endif
+
+pkg = import('pkgconfig')
+pkg.generate(
+ libraries: libepoxy,
+ name: 'epoxy',
+ description: 'GL dispatch library',
+ version: meson.project_version(),
+ variables: [
+ 'epoxy_has_glx=@0@'.format(epoxy_has_glx),
+ 'epoxy_has_egl=@0@'.format(epoxy_has_egl),
+ 'epoxy_has_wgl=@0@'.format(epoxy_has_wgl),
+ ],
+ filebase: 'epoxy',
+ requires_private: ' '.join(gl_reqs),
+)
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..78919f3
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,24 @@
+egl_and_glx_different_pointers_egl
+egl_and_glx_different_pointers_egl_glx
+egl_and_glx_different_pointers_glx
+egl_has_extension_nocontext
+egl_gl
+egl_gles1_without_glx
+egl_gles2_without_glx
+glx_alias_prefer_same_name
+glx_beginend
+glx_gles2
+glx_glxgetprocaddress_nocontext
+glx_has_extension_nocontext
+glx_public_api
+glx_public_api_core
+glx_shared_znow
+glx_static
+headerguards
+khronos_typedefs
+miscdefines
+wgl_core_and_exts
+wgl_usefontbitmaps
+wgl_usefontbitmaps_unicode
+*.log
+*.trs
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..fc3ffcd
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,192 @@
+# Copyright © 2013 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+EPOXY = $(builddir)/../src/libepoxy.la
+
+check_LTLIBRARIES = \
+ $(EGL_UTIL_LIB) \
+ $(GLX_UTIL_LIB) \
+ $(WGL_UTIL_LIB) \
+ $()
+
+libegl_common_la_SOURCES = \
+ egl_common.c \
+ egl_common.h
+ $()
+
+libglx_common_la_SOURCES = \
+ glx_common.c \
+ glx_common.h
+ $()
+
+libwgl_common_la_SOURCES = \
+ wgl_common.c \
+ wgl_common.h
+ $()
+libwgl_common_la_LIBADD = $(EPOXY)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ $(X11_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $()
+
+AM_CFLAGS = $(CWARNFLAGS)
+
+TESTS = \
+ $(EGL_TESTS) \
+ $(GLX_TESTS) \
+ $(EGL_AND_GLX_TESTS) \
+ $(WGL_TESTS) \
+ gl_version$(EXEEXT) \
+ headerguards$(EXEEXT) \
+ miscdefines$(EXEEXT) \
+ khronos_typedefs$(EXEEXT) \
+ $()
+
+check_BINARIES = $(EGL_AND_GLX_BIN)
+
+XFAIL_TESTS = \
+ $()
+
+check_PROGRAMS = $(TESTS)
+
+if BUILD_EGL
+EGL_TESTS = \
+ $()
+
+if HAVE_X11
+EGL_TESTS += \
+ egl_has_extension_nocontext \
+ egl_epoxy_api \
+ egl_gles2_without_glx \
+ $()
+
+if HAS_GLES1
+EGL_TESTS += egl_gles1_without_glx
+endif
+
+EGL_UTIL_LIB = libegl_common.la
+endif
+endif
+
+if BUILD_GLX
+if HAS_ZNOW
+GLX_SHARED_ZNOW = glx_shared_znow
+endif
+
+if BUILD_EGL
+if BUILD_GLX
+if HAVE_DLVSYM
+EGL_AND_GLX_TESTS = \
+ egl_gl \
+ $()
+endif
+endif
+endif
+
+if HAVE_DLVSYM
+GLX_DLVSYM_TESTS = \
+ glx_alias_prefer_same_name \
+ glx_gles2 \
+ $()
+endif
+
+GLX_TESTS = \
+ glx_beginend \
+ glx_public_api \
+ glx_public_api_core \
+ glx_glxgetprocaddress_nocontext \
+ glx_has_extension_nocontext \
+ glx_static \
+ $(GLX_SHARED_ZNOW) \
+ $(GLX_DLVSYM_TESTS) \
+ $()
+
+GLX_UTIL_LIB = libglx_common.la
+endif
+
+if BUILD_WGL
+WGL_TESTS = \
+ wgl_core_and_exts$(EXEEXT) \
+ wgl_per_context_funcptrs$(EXEEXT) \
+ wgl_usefontbitmaps$(EXEEXT) \
+ wgl_usefontbitmaps_unicode$(EXEEXT) \
+ $()
+
+WGL_UTIL_LIB = libwgl_common.la
+endif
+
+egl_has_extension_nocontext_LDADD = $(EPOXY) libegl_common.la $(X11_LIBS)
+
+egl_epoxy_api_LDADD = $(EPOXY) libegl_common.la $(X11_LIBS)
+
+egl_gl_LDADD = $(EPOXY) $(DLOPEN_LIBS) libegl_common.la $(X11_LIBS)
+
+egl_gles1_without_glx_CPPFLAGS = $(AM_CPPFLAGS) -DGLES_VERSION=1
+egl_gles1_without_glx_SOURCES = egl_without_glx.c
+egl_gles1_without_glx_LDADD = $(EPOXY) $(DLOPEN_LIBS) libegl_common.la $(X11_LIBS)
+
+egl_gles2_without_glx_CPPFLAGS = $(AM_CPPFLAGS) -DGLES_VERSION=2
+egl_gles2_without_glx_SOURCES = egl_without_glx.c
+egl_gles2_without_glx_LDADD = $(EPOXY) $(DLOPEN_LIBS) libegl_common.la $(X11_LIBS)
+
+glx_alias_prefer_same_name_SOURCES = glx_alias_prefer_same_name.c dlwrap.c dlwrap.h
+glx_alias_prefer_same_name_LDFLAGS = -rdynamic
+glx_alias_prefer_same_name_LDADD = $(EPOXY) libglx_common.la $(X11_LIBS) $(DLOPEN_LIBS)
+
+glx_beginend_LDADD = $(EPOXY) libglx_common.la $(GL_LIBS) $(X11_LIBS)
+
+glx_gles2_SOURCES = glx_gles2.c dlwrap.c dlwrap.h
+glx_gles2_LDFLAGS = -rdynamic
+glx_gles2_LDADD = $(EPOXY) libglx_common.la $(X11_LIBS) $(DLOPEN_LIBS)
+
+glx_public_api_LDADD = $(EPOXY) libglx_common.la $(X11_LIBS)
+
+glx_public_api_core_LDADD = $(EPOXY) libglx_common.la $(X11_LIBS)
+
+glx_glxgetprocaddress_nocontext_LDADD = $(EPOXY) libglx_common.la $(X11_LIBS)
+
+glx_has_extension_nocontext_LDADD = $(EPOXY) libglx_common.la $(X11_LIBS)
+
+glx_static_CFLAGS = -DNEEDS_TO_BE_STATIC
+glx_static_LDADD = $(DLOPEN_LIBS) $(EPOXY) libglx_common.la $(X11_LIBS)
+glx_static_LDFLAGS = -static
+
+glx_shared_znow_SOURCES = glx_static.c
+glx_shared_znow_LDADD = $(DLOPEN_LIBS) $(EPOXY) libglx_common.la $(X11_LIBS)
+glx_shared_znow_LDFLAGS = -Wl,-z,now
+
+khronos_typedefs_SOURCES = \
+ khronos_typedefs.c \
+ khronos_typedefs.h \
+ khronos_typedefs_nonepoxy.c \
+ $()
+
+wgl_core_and_exts_LDADD = $(EPOXY) libwgl_common.la -lgdi32
+
+wgl_per_context_funcptrs_LDADD = $(EPOXY) libwgl_common.la -lgdi32
+
+wgl_usefontbitmaps_LDADD = $(EPOXY) libwgl_common.la -lgdi32
+wgl_usefontbitmaps_unicode_SOURCES = wgl_usefontbitmaps.c
+wgl_usefontbitmaps_unicode_LDADD = $(EPOXY) libwgl_common.la -lgdi32
+wgl_usefontbitmaps_unicode_CPPFLAGS = $(AM_CPPFLAGS) -DUNICODE
diff --git a/test/cgl_core.c b/test/cgl_core.c
new file mode 100644
index 0000000..9b56acf
--- /dev/null
+++ b/test/cgl_core.c
@@ -0,0 +1,54 @@
+/* This is a copy of the test used by HomeBrew's libepoxy recipe,
+ * originally written by Mikko Lehtonen.
+ *
+ * The Homebrew recipe is released under the BSD 2-Clause license.
+ *
+ * Copyright (c) 2009-present, Homebrew contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <epoxy/gl.h>
+#include <Carbon/Carbon.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/CGLTypes.h>
+#include <OpenGL/CGLCurrent.h>
+#include <OpenGL/CGLContext.h>
+
+int
+main (void)
+{
+ CGLPixelFormatAttribute attribs[] = {0};
+ CGLPixelFormatObj pix;
+ CGLContextObj ctx;
+ int npix;
+
+ CGLChoosePixelFormat(attribs, &pix, &npix);
+ CGLCreateContext(pix, (void *) 0, &ctx);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ CGLReleaseContext(ctx);
+ CGLReleasePixelFormat(pix);
+
+ return 0;
+}
diff --git a/test/cgl_epoxy_api.c b/test/cgl_epoxy_api.c
new file mode 100644
index 0000000..e83222c
--- /dev/null
+++ b/test/cgl_epoxy_api.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 Emmanuele Bassi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file cgl_epoxy_api.c
+ *
+ * Tests the Epoxy API using the CoreGraphics OpenGL framework.
+ */
+
+#include <epoxy/gl.h>
+#include <Carbon/Carbon.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/CGLTypes.h>
+#include <OpenGL/CGLCurrent.h>
+#include <OpenGL/CGLContext.h>
+
+int
+main (void)
+{
+ CGLPixelFormatAttribute attribs[] = {0};
+ CGLPixelFormatObj pix;
+ CGLContextObj ctx;
+ const char *string;
+ bool pass = true;
+ int npix;
+ GLint shader;
+
+ CGLChoosePixelFormat(attribs, &pix, &npix);
+ CGLCreateContext(pix, (void *) 0, &ctx);
+ CGLSetCurrentContext(ctx);
+
+ if (!epoxy_is_desktop_gl()) {
+ fputs("Claimed not to be desktop\n", stderr);
+ pass = false;
+ }
+
+ if (epoxy_gl_version() < 20) {
+ fprintf(stderr, "Claimed to be GL version %d\n",
+ epoxy_gl_version());
+ pass = false;
+ }
+
+ if (epoxy_glsl_version() < 100) {
+ fprintf(stderr, "Claimed to have GLSL version %d\n",
+ epoxy_glsl_version());
+ pass = false;
+ }
+
+ string = (const char *)glGetString(GL_VERSION);
+ printf("GL version: %s - Epoxy: %d\n", string, epoxy_gl_version());
+
+ string = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
+ printf("GLSL version: %s - Epoxy: %d\n", string, epoxy_glsl_version());
+
+ shader = glCreateShader(GL_FRAGMENT_SHADER);
+ pass = glIsShader(shader);
+
+ CGLSetCurrentContext(NULL);
+ CGLReleaseContext(ctx);
+ CGLReleasePixelFormat(pix);
+
+ return pass != true;
+}
diff --git a/test/dlwrap.c b/test/dlwrap.c
new file mode 100644
index 0000000..c0c24c2
--- /dev/null
+++ b/test/dlwrap.c
@@ -0,0 +1,325 @@
+/* Copyright © 2013, Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/** @file dlwrap.c
+ *
+ * Implements a wrapper for dlopen() and dlsym() so that epoxy will
+ * end up finding symbols from the testcases named
+ * "override_EGL_eglWhatever()" or "override_GLES2_glWhatever()" or
+ * "override_GL_glWhatever()" when it tries to dlopen() and dlsym()
+ * the real GL or EGL functions in question.
+ *
+ * This lets us simulate some target systems in the test suite, or
+ * just stub out GL functions so we can be sure of what's being
+ * called.
+ */
+
+/* dladdr is a glibc extension */
+#define _GNU_SOURCE
+#include <dlfcn.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dlwrap.h"
+
+#define STRNCMP_LITERAL(var, literal) \
+ strncmp ((var), (literal), sizeof (literal) - 1)
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+void *libfips_handle;
+
+typedef void *(*fips_dlopen_t)(const char *filename, int flag);
+typedef void *(*fips_dlsym_t)(void *handle, const char *symbol);
+
+void *override_EGL_eglGetProcAddress(const char *name);
+void *override_GL_glXGetProcAddress(const char *name);
+void *override_GL_glXGetProcAddressARB(const char *name);
+void __dlclose(void *handle);
+
+static struct libwrap {
+ const char *filename;
+ const char *symbol_prefix;
+ void *handle;
+} wrapped_libs[] = {
+ { "libGL.so", "GL", NULL },
+ { "libEGL.so", "EGL", NULL },
+ { "libGLESv2.so", "GLES2", NULL },
+ { "libOpenGL.so", "GL", NULL},
+};
+
+/* Match 'filename' against an internal list of libraries for which
+ * libfips has wrappers.
+ *
+ * Returns true and sets *index_ret if a match is found.
+ * Returns false if no match is found. */
+static struct libwrap *
+find_wrapped_library(const char *filename)
+{
+ unsigned i;
+
+ if (!filename)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(wrapped_libs); i++) {
+ if (strncmp(wrapped_libs[i].filename, filename,
+ strlen(wrapped_libs[i].filename)) == 0) {
+ return &wrapped_libs[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Many (most?) OpenGL programs dlopen libGL.so.1 rather than linking
+ * against it directly, which means they would not be seeing our
+ * wrapped GL symbols via LD_PRELOAD. So we catch the dlopen in a
+ * wrapper here and redirect it to our library.
+ */
+void *
+dlopen(const char *filename, int flag)
+{
+ void *ret;
+ struct libwrap *wrap;
+
+ /* Before deciding whether to redirect this dlopen to our own
+ * library, we call the real dlopen. This assures that any
+ * expected side-effects from loading the intended library are
+ * resolved. Below, we may still return a handle pointing to
+ * our own library, and not what is opened here. */
+ ret = dlwrap_real_dlopen(filename, flag);
+
+ /* If filename is not a wrapped library, just return real dlopen */
+ wrap = find_wrapped_library(filename);
+ if (!wrap)
+ return ret;
+
+ wrap->handle = ret;
+
+ /* We use wrapped_libs as our handles to libraries. */
+ return wrap;
+}
+
+/**
+ * Wraps dlclose to hide our faked handles from it.
+ */
+void
+__dlclose(void *handle)
+{
+ struct libwrap *wrap = handle;
+
+ if (wrap < wrapped_libs ||
+ wrap >= wrapped_libs + ARRAY_SIZE(wrapped_libs)) {
+ void (*real_dlclose)(void *handle) = dlwrap_real_dlsym(RTLD_NEXT, "__dlclose");
+ real_dlclose(handle);
+ }
+}
+
+void *
+dlwrap_real_dlopen(const char *filename, int flag)
+{
+ static fips_dlopen_t real_dlopen = NULL;
+
+ if (!real_dlopen) {
+ real_dlopen = (fips_dlopen_t) dlwrap_real_dlsym(RTLD_NEXT, "dlopen");
+ if (!real_dlopen) {
+ fputs("Error: Failed to find symbol for dlopen.\n", stderr);
+ exit(1);
+ }
+ }
+
+ return real_dlopen(filename, flag);
+}
+
+/**
+ * Return the dlsym() on the application's namespace for
+ * "override_<prefix>_<name>"
+ */
+static void *
+wrapped_dlsym(const char *prefix, const char *name)
+{
+ char *wrap_name;
+ void *symbol;
+
+ if (asprintf(&wrap_name, "override_%s_%s", prefix, name) < 0) {
+ fputs("Error: Failed to allocate memory.\n", stderr);
+ abort();
+ }
+
+ symbol = dlwrap_real_dlsym(RTLD_DEFAULT, wrap_name);
+ free(wrap_name);
+ return symbol;
+}
+
+/* Since we redirect dlopens of libGL.so and libEGL.so to libfips we
+ * need to ensure that dlysm succeeds for all functions that might be
+ * defined in the real, underlying libGL library. But we're far too
+ * lazy to implement wrappers for function that would simply
+ * pass-through, so instead we also wrap dlysm and arrange for it to
+ * pass things through with RTLD_next if libfips does not have the
+ * function desired. */
+void *
+dlsym(void *handle, const char *name)
+{
+ struct libwrap *wrap = handle;
+
+ /* Make sure that handle is actually one of our wrapped libs. */
+ if (wrap < wrapped_libs ||
+ wrap >= wrapped_libs + ARRAY_SIZE(wrapped_libs)) {
+ wrap = NULL;
+ }
+
+ /* Failing that, anything specifically requested from the
+ * libfips library should be redirected to a real GL
+ * library. */
+
+ if (wrap) {
+ void *symbol = wrapped_dlsym(wrap->symbol_prefix, name);
+ if (symbol)
+ return symbol;
+ else
+ return dlwrap_real_dlsym(wrap->handle, name);
+ }
+
+ /* And anything else is some unrelated dlsym. Just pass it
+ * through. (This also covers the cases of lookups with
+ * special handles such as RTLD_DEFAULT or RTLD_NEXT.)
+ */
+ return dlwrap_real_dlsym(handle, name);
+}
+
+void *
+dlwrap_real_dlsym(void *handle, const char *name)
+{
+ static fips_dlsym_t real_dlsym = NULL;
+
+ if (!real_dlsym) {
+ /* FIXME: This brute-force, hard-coded searching for a versioned
+ * symbol is really ugly. The only reason I'm doing this is because
+ * I need some way to lookup the "dlsym" function in libdl, but
+ * I can't use 'dlsym' to do it. So dlvsym works, but forces me
+ * to guess what the right version is.
+ *
+ * Potential fixes here:
+ *
+ * 1. Use libelf to actually inspect libdl.so and
+ * find the right version, (finding the right
+ * libdl.so can be made easier with
+ * dl_iterate_phdr).
+ *
+ * 2. Use libelf to find the offset of the 'dlsym'
+ * symbol within libdl.so, (and then add this to
+ * the base address at which libdl.so is loaded
+ * as reported by dl_iterate_phdr).
+ *
+ * In the meantime, I'll just keep augmenting this
+ * hard-coded version list as people report bugs. */
+ const char *version[] = {
+ "GLIBC_2.17",
+ "GLIBC_2.4",
+ "GLIBC_2.3",
+ "GLIBC_2.2.5",
+ "GLIBC_2.2",
+ "GLIBC_2.0",
+ "FBSD_1.0"
+ };
+ int num_versions = sizeof(version) / sizeof(version[0]);
+ int i;
+ for (i = 0; i < num_versions; i++) {
+ real_dlsym = (fips_dlsym_t) dlvsym(RTLD_NEXT, "dlsym", version[i]);
+ if (real_dlsym)
+ break;
+ }
+ if (i == num_versions) {
+ fputs("Internal error: Failed to find real dlsym\n", stderr);
+ fputs("This may be a simple matter of fips not knowing about the version of GLIBC that\n"
+ "your program is using. Current known versions are:\n\n\t",
+ stderr);
+ for (i = 0; i < num_versions; i++)
+ fprintf(stderr, "%s ", version[i]);
+ fputs("\n\nYou can inspect your version by first finding libdl.so.2:\n"
+ "\n"
+ "\tldd <your-program> | grep libdl.so\n"
+ "\n"
+ "And then inspecting the version attached to the dlsym symbol:\n"
+ "\n"
+ "\treadelf -s /path/to/libdl.so.2 | grep dlsym\n"
+ "\n"
+ "And finally, adding the version to dlwrap.c:dlwrap_real_dlsym.\n",
+ stderr);
+
+ exit(1);
+ }
+ }
+
+ return real_dlsym(handle, name);
+}
+
+void *
+override_GL_glXGetProcAddress(const char *name)
+{
+ void *symbol;
+
+ symbol = wrapped_dlsym("GL", name);
+ if (symbol)
+ return symbol;
+
+ return DEFER_TO_GL("libGL.so.1", override_GL_glXGetProcAddress,
+ "glXGetProcAddress", (name));
+}
+
+void *
+override_GL_glXGetProcAddressARB(const char *name)
+{
+ void *symbol;
+
+ symbol = wrapped_dlsym("GL", name);
+ if (symbol)
+ return symbol;
+
+ return DEFER_TO_GL("libGL.so.1", override_GL_glXGetProcAddressARB,
+ "glXGetProcAddressARB", (name));
+}
+
+void *
+override_EGL_eglGetProcAddress(const char *name)
+{
+ void *symbol;
+
+ if (!STRNCMP_LITERAL(name, "gl")) {
+ symbol = wrapped_dlsym("GLES2", name);
+ if (symbol)
+ return symbol;
+ }
+
+ if (!STRNCMP_LITERAL(name, "egl")) {
+ symbol = wrapped_dlsym("EGL", name);
+ if (symbol)
+ return symbol;
+ }
+
+ return DEFER_TO_GL("libEGL.so.1", override_EGL_eglGetProcAddress,
+ "eglGetProcAddress", (name));
+}
diff --git a/test/dlwrap.h b/test/dlwrap.h
new file mode 100644
index 0000000..39ec9ec
--- /dev/null
+++ b/test/dlwrap.h
@@ -0,0 +1,67 @@
+/* Copyright © 2013, Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef DLWRAP_H
+#define DLWRAP_H
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+
+/* Call the *real* dlopen. We have our own wrapper for dlopen that, of
+ * necessity must use claim the symbol 'dlopen'. So whenever anything
+ * internal needs to call the real, underlying dlopen function, the
+ * thing to call is dlwrap_real_dlopen.
+ */
+void *
+dlwrap_real_dlopen(const char *filename, int flag);
+
+/* Perform a dlopen on the libfips library itself.
+ *
+ * Many places in fips need to lookup symbols within the libfips
+ * library itself, (and not in any other library). This function
+ * provides a reliable way to get a handle for performing such
+ * lookups.
+ *
+ * The returned handle can be passed to dlwrap_real_dlsym for the
+ * lookups. */
+void *
+dlwrap_dlopen_libfips(void);
+
+/* Call the *real* dlsym. We have our own wrapper for dlsym that, of
+ * necessity must use claim the symbol 'dlsym'. So whenever anything
+ * internal needs to call the real, underlying dlysm function, the
+ * thing to call is dlwrap_real_dlsym.
+ */
+void *
+dlwrap_real_dlsym(void *handle, const char *symbol);
+
+#define DEFER_TO_GL(library, func, name, args) \
+({ \
+ void *lib = dlwrap_real_dlopen(library, RTLD_LAZY | RTLD_LOCAL); \
+ typeof(&func) real_func = dlwrap_real_dlsym(lib, name); \
+ /* gcc extension -- func's return value is the return value of \
+ * the statement. \
+ */ \
+ real_func args; \
+})
+
+#endif
+
diff --git a/test/egl_common.c b/test/egl_common.c
new file mode 100644
index 0000000..c407912
--- /dev/null
+++ b/test/egl_common.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <err.h>
+#include <epoxy/egl.h>
+#include <X11/Xlib.h>
+#include "egl_common.h"
+
+/**
+ * Do whatever it takes to get us an EGL display for the system.
+ *
+ * This needs to be ported to other window systems.
+ */
+EGLDisplay *
+get_egl_display_or_skip(void)
+{
+ Display *dpy = XOpenDisplay(NULL);
+ EGLint major, minor;
+ EGLDisplay *edpy;
+ bool ok;
+
+ if (!dpy)
+ errx(77, "couldn't open display\n");
+
+ edpy = eglGetDisplay(dpy);
+ if (!edpy)
+ errx(1, "Couldn't get EGL display for X11 Display.\n");
+
+ ok = eglInitialize(edpy, &major, &minor);
+ if (!ok)
+ errx(1, "eglInitialize() failed\n");
+
+ return edpy;
+}
diff --git a/test/egl_common.h b/test/egl_common.h
new file mode 100644
index 0000000..1c5963b
--- /dev/null
+++ b/test/egl_common.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+EGLDisplay *
+get_egl_display_or_skip(void);
diff --git a/test/egl_epoxy_api.c b/test/egl_epoxy_api.c
new file mode 100644
index 0000000..252b535
--- /dev/null
+++ b/test/egl_epoxy_api.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2018 Emmanuele Bassi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file epoxy_api.c
+ *
+ * Tests the Epoxy API using EGL.
+ */
+
+#ifdef __sun
+#define __EXTENSIONS__
+#else
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/egl.h"
+
+#include "egl_common.h"
+
+static bool
+make_egl_current_and_test(EGLDisplay *dpy, EGLContext ctx)
+{
+ const char *string;
+ GLuint shader;
+ bool pass = true;
+
+ eglMakeCurrent(dpy, NULL, NULL, ctx);
+
+ if (!epoxy_is_desktop_gl()) {
+ fputs("Claimed to be desktop\n", stderr);
+ pass = false;
+ }
+
+ if (epoxy_gl_version() < 20) {
+ fprintf(stderr, "Claimed to be GL version %d\n",
+ epoxy_gl_version());
+ pass = false;
+ }
+
+ if (epoxy_glsl_version() < 100) {
+ fprintf(stderr, "Claimed to have GLSL version %d\n",
+ epoxy_glsl_version());
+ pass = false;
+ }
+
+ string = (const char *)glGetString(GL_VERSION);
+ printf("GL version: %s - Epoxy: %d\n", string, epoxy_gl_version());
+
+ string = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
+ printf("GLSL version: %s - Epoxy: %d\n", string, epoxy_glsl_version());
+
+ shader = glCreateShader(GL_FRAGMENT_SHADER);
+ pass = glIsShader(shader);
+
+ return pass;
+}
+
+static void
+init_egl(EGLDisplay *dpy, EGLContext *out_ctx)
+{
+ static const EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_NONE
+ };
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+ EGLContext ctx;
+ EGLConfig cfg;
+ EGLint count;
+
+ if (!epoxy_has_egl_extension(dpy, "EGL_KHR_surfaceless_context"))
+ errx(77, "Test requires EGL_KHR_surfaceless_context");
+
+ if (!eglBindAPI(EGL_OPENGL_API))
+ errx(77, "Couldn't initialize EGL with desktop GL\n");
+
+ if (!eglChooseConfig(dpy, config_attribs, &cfg, 1, &count))
+ errx(77, "Couldn't get an EGLConfig\n");
+
+ ctx = eglCreateContext(dpy, cfg, NULL, context_attribs);
+ if (!ctx)
+ errx(77, "Couldn't create a GL context\n");
+
+ *out_ctx = ctx;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ EGLContext egl_ctx;
+ EGLDisplay *dpy = get_egl_display_or_skip();
+ const char *extensions = eglQueryString(dpy, EGL_EXTENSIONS);
+ char *first_space;
+ char *an_extension;
+
+ /* We don't have any extensions guaranteed by the ABI, so for the
+ * touch test we just check if the first one is reported to be there.
+ */
+ first_space = strstr(extensions, " ");
+ if (first_space) {
+ an_extension = strndup(extensions, first_space - extensions);
+ } else {
+ an_extension = strdup(extensions);
+ }
+
+ if (!epoxy_extension_in_string(extensions, an_extension))
+ errx(1, "Implementation reported absence of %s", an_extension);
+
+ free(an_extension);
+
+ init_egl(dpy, &egl_ctx);
+ pass = make_egl_current_and_test(dpy, egl_ctx);
+
+ return pass != true;
+}
diff --git a/test/egl_gl.c b/test/egl_gl.c
new file mode 100644
index 0000000..1acc19e
--- /dev/null
+++ b/test/egl_gl.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file egl_gl.c
+ *
+ * Tests that epoxy works with EGL using desktop OpenGL.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include <dlfcn.h>
+#include "epoxy/gl.h"
+#include "epoxy/egl.h"
+#include "epoxy/glx.h"
+
+#include "egl_common.h"
+#include "glx_common.h"
+#include "dlwrap.h"
+
+static bool
+make_egl_current_and_test(EGLDisplay *dpy, EGLContext ctx)
+{
+ const char *string;
+ GLuint shader;
+ bool pass = true;
+
+ eglMakeCurrent(dpy, NULL, NULL, ctx);
+
+ if (!epoxy_is_desktop_gl()) {
+ fputs("Claimed to be desktop\n", stderr);
+ pass = false;
+ }
+
+ if (epoxy_gl_version() < 20) {
+ fprintf(stderr, "Claimed to be GL version %d\n",
+ epoxy_gl_version());
+ pass = false;
+ }
+
+ string = (const char *)glGetString(GL_VERSION);
+ printf("GL version: %s\n", string);
+
+ shader = glCreateShader(GL_FRAGMENT_SHADER);
+ pass = glIsShader(shader);
+
+ return pass;
+}
+
+static void
+init_egl(EGLDisplay **out_dpy, EGLContext *out_ctx)
+{
+ EGLDisplay *dpy = get_egl_display_or_skip();
+ static const EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_NONE
+ };
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+ EGLContext ctx;
+ EGLConfig cfg;
+ EGLint count;
+
+ if (!epoxy_has_egl_extension(dpy, "EGL_KHR_surfaceless_context"))
+ errx(77, "Test requires EGL_KHR_surfaceless_context");
+
+ if (!eglBindAPI(EGL_OPENGL_API))
+ errx(77, "Couldn't initialize EGL with desktop GL\n");
+
+ if (!eglChooseConfig(dpy, config_attribs, &cfg, 1, &count))
+ errx(77, "Couldn't get an EGLConfig\n");
+
+ ctx = eglCreateContext(dpy, cfg, NULL, context_attribs);
+ if (!ctx)
+ errx(77, "Couldn't create a GL context\n");
+
+ *out_dpy = dpy;
+ *out_ctx = ctx;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+ EGLDisplay *egl_dpy;
+ EGLContext egl_ctx;
+
+ /* Force epoxy to have loaded both EGL and GLX libs already -- we
+ * can't assume anything about symbol resolution based on having
+ * EGL or GLX loaded.
+ */
+ (void)glXGetCurrentContext();
+ (void)eglGetCurrentContext();
+
+ init_egl(&egl_dpy, &egl_ctx);
+ pass = make_egl_current_and_test(egl_dpy, egl_ctx) && pass;
+
+ return pass != true;
+}
diff --git a/test/egl_has_extension_nocontext.c b/test/egl_has_extension_nocontext.c
new file mode 100644
index 0000000..4fa5f60
--- /dev/null
+++ b/test/egl_has_extension_nocontext.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file egl_has_extension_nocontext.c
+ *
+ * Catches a bug in early development where eglGetProcAddress() with
+ * no context bound would fail out in dispatch.
+ */
+
+#ifdef __sun
+#define __EXTENSIONS__
+#else
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/egl.h"
+
+#include "egl_common.h"
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ EGLDisplay *dpy = get_egl_display_or_skip();
+ const char *extensions = eglQueryString(dpy, EGL_EXTENSIONS);
+ char *first_space;
+ char *an_extension;
+
+ /* We don't have any extensions guaranteed by the ABI, so for the
+ * touch test we just check if the first one is reported to be there.
+ */
+ first_space = strstr(extensions, " ");
+ if (first_space) {
+ an_extension = strndup(extensions, first_space - extensions);
+ } else {
+ an_extension = strdup(extensions);
+ }
+
+ if (!epoxy_has_egl_extension(dpy, an_extension))
+ errx(1, "Implementation reported absence of %s", an_extension);
+
+ free(an_extension);
+
+ if (epoxy_has_egl_extension(dpy, "GLX_ARB_ham_sandwich"))
+ errx(1, "Implementation reported presence of GLX_ARB_ham_sandwich");
+
+ return pass != true;
+}
diff --git a/test/egl_without_glx.c b/test/egl_without_glx.c
new file mode 100644
index 0000000..195ef41
--- /dev/null
+++ b/test/egl_without_glx.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file egl_without_glx.c
+ *
+ * Tries to test operation of the library on a GL stack with EGL and
+ * GLES but no GLX or desktop GL (such as Arm's Mali GLES3 drivers).
+ * This test is varied by the GLES_VERSION defined at compile time to
+ * test either a GLES1-only or a GLES2-only system.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include <dlfcn.h>
+#include "epoxy/gl.h"
+#include "epoxy/egl.h"
+
+#include "egl_common.h"
+
+/**
+ * Wraps the system dlopen(), which libepoxy will end up calling when
+ * it tries to dlopen() the API libraries, and errors out the
+ * libraries we're trying to simulate not being installed on the
+ * system.
+ */
+void *
+dlopen(const char *filename, int flag)
+{
+ void * (*dlopen_unwrapped)(const char *filename, int flag);
+
+ if (filename) {
+ if (!strcmp(filename, "libGL.so.1"))
+ return NULL;
+#if GLES_VERSION == 2
+ if (!strcmp(filename, "libGLESv1_CM.so.1"))
+ return NULL;
+#else
+ if (!strcmp(filename, "libGLESv2.so.2"))
+ return NULL;
+#endif
+ }
+
+ dlopen_unwrapped = dlsym(RTLD_NEXT, "dlopen");
+ assert(dlopen_unwrapped);
+
+ return dlopen_unwrapped(filename, flag);
+}
+
+
+static EGLenum last_api;
+static EGLenum extra_error = EGL_SUCCESS;
+
+/**
+ * Override of the real libEGL's eglBindAPI to simulate the target
+ * system's eglBindAPI.
+ */
+static EGLBoolean
+override_eglBindAPI(EGLenum api)
+{
+ void *egl = dlopen("libEGL.so.1", RTLD_LAZY | RTLD_LOCAL);
+ EGLBoolean (*real_eglBindAPI)(EGLenum api) = dlsym(egl, "eglBindAPI");
+
+ last_api = api;
+
+ if (api == EGL_OPENGL_API) {
+ extra_error = EGL_BAD_PARAMETER;
+ return EGL_FALSE;
+ }
+
+ assert(real_eglBindAPI);
+ return real_eglBindAPI(api);
+}
+
+/**
+ * Override of the real libEGL's eglGetError() to feed back the error
+ * that might have been generated by override_eglBindAPI().
+ */
+static EGLint
+override_eglGetError(void)
+{
+ void *egl = dlopen("libEGL.so.1", RTLD_LAZY | RTLD_LOCAL);
+ EGLint (*real_eglGetError)(void) = dlsym(egl, "eglGetError");
+
+ if (extra_error != EGL_SUCCESS) {
+ EGLenum error = extra_error;
+ extra_error = EGL_SUCCESS;
+ return error;
+ }
+
+ assert(real_eglGetError);
+ return real_eglGetError();
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+ EGLDisplay *dpy = get_egl_display_or_skip();
+ EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
+ EGL_NONE
+ };
+ EGLConfig cfg;
+ EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_NONE
+ };
+ EGLint count;
+ EGLContext ctx;
+ const unsigned char *string;
+
+ epoxy_eglBindAPI = override_eglBindAPI;
+ epoxy_eglGetError = override_eglGetError;
+
+ if (!epoxy_has_egl_extension(dpy, "EGL_KHR_surfaceless_context"))
+ errx(77, "Test requires EGL_KHR_surfaceless_context");
+
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ if (!eglChooseConfig(dpy, config_attribs, &cfg, 1, &count))
+ errx(77, "Couldn't get an EGLConfig\n");
+
+ ctx = eglCreateContext(dpy, cfg, NULL, context_attribs);
+ if (!ctx)
+ errx(77, "Couldn't create a GLES%d context\n", GLES_VERSION);
+
+ eglMakeCurrent(dpy, NULL, NULL, ctx);
+
+ string = glGetString(GL_VERSION);
+ printf("GL_VERSION: %s\n", string);
+
+ assert(eglGetError() == EGL_SUCCESS);
+
+ return pass != true;
+}
diff --git a/test/gl_version.c b/test/gl_version.c
new file mode 100644
index 0000000..9ab0080
--- /dev/null
+++ b/test/gl_version.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2018 Broadcom
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "epoxy/gl.h"
+
+GLenum mock_enum;
+const char *mock_gl_version;
+const char *mock_glsl_version;
+
+static const GLubyte *override_glGetString(GLenum name)
+{
+ switch (name) {
+ case GL_VERSION:
+ return (GLubyte *)mock_gl_version;
+ case GL_SHADING_LANGUAGE_VERSION:
+ return (GLubyte *)mock_glsl_version;
+ default:
+ assert(!"unexpected glGetString() enum");
+ return 0;
+ }
+}
+
+static bool
+test_version(const char *gl_string, int gl_version,
+ const char *glsl_string, int glsl_version)
+{
+ int epoxy_version;
+
+ mock_gl_version = gl_string;
+ mock_glsl_version = glsl_string;
+
+ epoxy_version = epoxy_gl_version();
+ if (epoxy_version != gl_version) {
+ fprintf(stderr,
+ "glGetString(GL_VERSION) = \"%s\" returned epoxy_gl_version() "
+ "%d instead of %d\n", gl_string, epoxy_version, gl_version);
+ return false;
+ }
+
+
+ epoxy_version = epoxy_glsl_version();
+ if (epoxy_version != glsl_version) {
+ fprintf(stderr,
+ "glGetString() = \"%s\" returned epoxy_glsl_version() "
+ "%d instead of %d\n", glsl_string, epoxy_version, glsl_version);
+ return false;
+ }
+
+ return true;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ epoxy_glGetString = override_glGetString;
+
+ pass = pass && test_version("3.0 Mesa 13.0.6", 30,
+ "1.30", 130);
+ pass = pass && test_version("OpenGL ES 3.2 Mesa 18.3.0-devel", 32,
+ "OpenGL ES GLSL ES 3.20", 320);
+ pass = pass && test_version("4.5.0 NVIDIA 384.130", 45,
+ "4.50", 450);
+
+ return pass != true;
+}
diff --git a/test/glx_alias_prefer_same_name.c b/test/glx_alias_prefer_same_name.c
new file mode 100644
index 0000000..cfc1344
--- /dev/null
+++ b/test/glx_alias_prefer_same_name.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file glx_gles2.c
+ *
+ * Catches a bug where a GLES2 context using
+ * GLX_EXT_create_context_es2_profile would try to find the symbols in
+ * libGLESv2.so.2 instead of libGL.so.1.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+
+static int last_call;
+
+#define CORE_FUNC_VAL 100
+#define EXT_FUNC_VAL 101
+
+void
+override_GL_glBindTexture(GLenum target);
+void
+override_GL_glBindTextureEXT(GLenum target);
+
+void
+override_GL_glBindTexture(GLenum target)
+{
+ last_call = CORE_FUNC_VAL;
+}
+
+void
+override_GL_glBindTextureEXT(GLenum target)
+{
+ last_call = EXT_FUNC_VAL;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ dpy = get_display_or_skip();
+ make_glx_context_current_or_skip(dpy);
+
+ if (!epoxy_has_gl_extension("GL_EXT_texture_object"))
+ errx(77, "Test requires GL_EXT_texture_object");
+
+ glBindTexture(GL_TEXTURE_2D, 1);
+ pass = pass && last_call == CORE_FUNC_VAL;
+ glBindTextureEXT(GL_TEXTURE_2D, 1);
+ pass = pass && last_call == EXT_FUNC_VAL;
+
+ return pass != true;
+}
diff --git a/test/glx_beginend.c b/test/glx_beginend.c
new file mode 100644
index 0000000..c68f408
--- /dev/null
+++ b/test/glx_beginend.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+static bool has_argb2101010;
+
+static bool
+test_with_epoxy(void)
+{
+ glBegin(GL_TRIANGLES);
+ {
+ /* Hit a base entrypoint that won't call gl_version() */
+ glVertex2f(0, 0);
+
+ /* Hit an entrypoint that will call probably call gl_version() */
+ glMultiTexCoord4f(GL_TEXTURE0, 0.0, 0.0, 0.0, 0.0);
+
+ /* Hit an entrypoint that will probably call
+ * epoxy_conservative_has_extension();
+ */
+ if (has_argb2101010) {
+ glTexCoordP4ui(GL_UNSIGNED_INT_2_10_10_10_REV, 0);
+ }
+ }
+ glEnd();
+
+ /* No error should have been generated in the process. */
+ return glGetError() == 0;
+}
+
+
+
+#undef glBegin
+#undef glEnd
+extern void glBegin(GLenum primtype);
+extern void glEnd(void);
+
+static bool
+test_without_epoxy(void)
+{
+ glBegin(GL_TRIANGLES);
+ {
+ /* Hit a base entrypoint that won't call gl_version() */
+ glVertex4f(0, 0, 0, 0);
+
+ /* Hit an entrypoint that will call probably call gl_version() */
+ glMultiTexCoord3f(GL_TEXTURE0, 0.0, 0.0, 0.0);
+
+ /* Hit an entrypoint that will probably call
+ * epoxy_conservative_has_extension();
+ */
+ if (has_argb2101010) {
+ glTexCoordP3ui(GL_UNSIGNED_INT_2_10_10_10_REV, 0);
+ }
+ }
+ glEnd();
+
+ /* We can't make any assertions about error presence this time
+ * around. This test is just trying to catch segfaults.
+ */
+ return true;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ dpy = get_display_or_skip();
+ make_glx_context_current_or_skip(dpy);
+
+ has_argb2101010 =
+ epoxy_has_gl_extension("GL_ARB_vertex_type_2_10_10_10_rev");
+
+ pass = pass && test_with_epoxy();
+ pass = pass && test_without_epoxy();
+
+ return pass != true;
+}
diff --git a/test/glx_common.c b/test/glx_common.c
new file mode 100644
index 0000000..7f2fbe6
--- /dev/null
+++ b/test/glx_common.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2009, 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include "glx_common.h"
+
+Display *
+get_display_or_skip(void)
+{
+ Display *dpy = XOpenDisplay(NULL);
+
+ if (!dpy) {
+ fputs("couldn't open display\n", stderr);
+ exit(77);
+ }
+
+ return dpy;
+}
+
+XVisualInfo *
+get_glx_visual(Display *dpy)
+{
+ XVisualInfo *visinfo;
+ int attrib[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+ int screen = DefaultScreen(dpy);
+
+ visinfo = glXChooseVisual(dpy, screen, attrib);
+ if (visinfo == NULL) {
+ fputs("Couldn't get an RGBA, double-buffered visual\n", stderr);
+ exit(1);
+ }
+
+ return visinfo;
+}
+
+Window
+get_glx_window(Display *dpy, XVisualInfo *visinfo, bool map)
+{
+ XSetWindowAttributes window_attr;
+ unsigned long mask;
+ int screen = DefaultScreen(dpy);
+ Window root_win = RootWindow(dpy, screen);
+ Window win;
+
+ window_attr.background_pixel = 0;
+ window_attr.border_pixel = 0;
+ window_attr.colormap = XCreateColormap(dpy, root_win,
+ visinfo->visual, AllocNone);
+ window_attr.event_mask = StructureNotifyMask | ExposureMask |
+ KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+ win = XCreateWindow(dpy, root_win, 0, 0,
+ 10, 10, /* width, height */
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &window_attr);
+
+ return win;
+}
+
+void
+make_glx_context_current_or_skip(Display *dpy)
+{
+ GLXContext ctx;
+ XVisualInfo *visinfo = get_glx_visual(dpy);
+ Window win = get_glx_window(dpy, visinfo, false);
+
+ ctx = glXCreateContext(dpy, visinfo, False, True);
+ if (ctx == None) {
+ fputs("glXCreateContext failed\n", stderr);
+ exit(1);
+ }
+
+ glXMakeCurrent(dpy, win, ctx);
+}
+
+GLXFBConfig
+get_fbconfig_for_visinfo(Display *dpy, XVisualInfo *visinfo)
+{
+ int i, nconfigs;
+ GLXFBConfig ret = None, *configs;
+
+ configs = glXGetFBConfigs(dpy, visinfo->screen, &nconfigs);
+ if (!configs)
+ return None;
+
+ for (i = 0; i < nconfigs; i++) {
+ int v;
+
+ if (glXGetFBConfigAttrib(dpy, configs[i], GLX_VISUAL_ID, &v))
+ continue;
+
+ if (v == visinfo->visualid) {
+ ret = configs[i];
+ break;
+ }
+ }
+
+ XFree(configs);
+ return ret;
+}
diff --git a/test/glx_common.h b/test/glx_common.h
new file mode 100644
index 0000000..8b6c263
--- /dev/null
+++ b/test/glx_common.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "epoxy/glx.h"
+
+Display *
+get_display_or_skip(void);
+
+void
+make_glx_context_current_or_skip(Display *dpy);
+
+GLXFBConfig
+get_fbconfig_for_visinfo(Display *dpy, XVisualInfo *visinfo);
+
+XVisualInfo *
+get_glx_visual(Display *dpy);
+
+Window
+get_glx_window(Display *dpy, XVisualInfo *visinfo, bool map);
diff --git a/test/glx_gles2.c b/test/glx_gles2.c
new file mode 100644
index 0000000..969d26b
--- /dev/null
+++ b/test/glx_gles2.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file glx_gles2.c
+ *
+ * Catches a bug where a GLES2 context using
+ * GLX_EXT_create_context_es2_profile would try to find the symbols in
+ * libGLESv2.so.2 instead of libGL.so.1.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+
+GLuint
+override_GLES2_glCreateShader(GLenum target);
+
+GLuint
+override_GLES2_glCreateShader(GLenum target)
+{
+ return 0;
+}
+
+void
+override_GLES2_glGenQueries(GLsizei n, GLuint *ids);
+
+void
+override_GLES2_glGenQueries(GLsizei n, GLuint *ids)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ ids[i] = 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+ XVisualInfo *vis;
+ Window win;
+ GLXContext ctx;
+ GLXFBConfig config;
+ int context_attribs[] = {
+ GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ 0
+ };
+ GLuint shader;
+
+ dpy = get_display_or_skip();
+
+ if (!epoxy_has_glx_extension(dpy, 0, "GLX_EXT_create_context_es2_profile"))
+ errx(77, "Test requires GLX_EXT_create_context_es2_profile");
+
+ vis = get_glx_visual(dpy);
+ config = get_fbconfig_for_visinfo(dpy, vis);
+ win = get_glx_window(dpy, vis, false);
+
+ ctx = glXCreateContextAttribsARB(dpy, config, NULL, true,
+ context_attribs);
+
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (epoxy_is_desktop_gl()) {
+ errx(1, "GLES2 context creation made a desktop context\n");
+ }
+
+ if (epoxy_gl_version() < 20) {
+ errx(1, "GLES2 context creation made a version %f context\n",
+ epoxy_gl_version() / 10.0f);
+ }
+
+ /* Test using an entrypoint that's in GLES2, but not the desktop GL ABI. */
+ shader = glCreateShader(GL_FRAGMENT_SHADER);
+ if (shader == 0)
+ errx(1, "glCreateShader() failed\n");
+ glDeleteShader(shader);
+
+ if (epoxy_gl_version() >= 30) {
+ GLuint q = 0;
+
+ glGenQueries(1, &q);
+ if (!q)
+ errx(1, "glGenQueries() failed\n");
+ glDeleteQueries(1, &q);
+ }
+
+ return pass != true;
+}
diff --git a/test/glx_glxgetprocaddress_nocontext.c b/test/glx_glxgetprocaddress_nocontext.c
new file mode 100644
index 0000000..2182215
--- /dev/null
+++ b/test/glx_glxgetprocaddress_nocontext.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file glx_glxgetprocaddress_nocontext.c
+ *
+ * Catches a bug in early development where glXGetProcAddress() with
+ * no context bound would fail out in dispatch.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+ void *func;
+
+ dpy = get_display_or_skip();
+ if (epoxy_glx_version(dpy, 0) < 14)
+ errx(77, "GLX version 1.4 required for glXGetProcAddress().\n");
+
+ func = glXGetProcAddress((const GLubyte *)"glGetString");
+ if (!func)
+ errx(1, "glXGetProcAddress() returned NULL\n");
+
+ return pass != true;
+}
diff --git a/test/glx_has_extension_nocontext.c b/test/glx_has_extension_nocontext.c
new file mode 100644
index 0000000..2f87ac3
--- /dev/null
+++ b/test/glx_has_extension_nocontext.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file glx_has_extension_nocontext.c
+ *
+ * Catches a bug in early development where glXGetProcAddress() with
+ * no context bound would fail out in dispatch.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ dpy = get_display_or_skip();
+
+ if (!epoxy_has_glx_extension(dpy, 0, "GLX_ARB_get_proc_address"))
+ errx(1, "Implementation reported absence of GLX_ARB_get_proc_address");
+
+ if (epoxy_has_glx_extension(dpy, 0, "GLX_ARB_ham_sandwich"))
+ errx(1, "Implementation reported presence of GLX_ARB_ham_sandwich");
+
+ return pass != true;
+}
diff --git a/test/glx_public_api.c b/test/glx_public_api.c
new file mode 100644
index 0000000..aecdd2a
--- /dev/null
+++ b/test/glx_public_api.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+
+static bool
+test_gl_version(void)
+{
+ int version = epoxy_gl_version();
+ if (version < 12) {
+ fprintf(stderr,
+ "Reported GL version %d, should be at least 12\n",
+ version);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+test_glx_version(void)
+{
+ int version = epoxy_glx_version(dpy, 0);
+ const char *version_string;
+ int ret;
+ int server_major, server_minor;
+ int client_major, client_minor;
+ int server, client, expected;
+
+ if (version < 13) {
+ fprintf(stderr,
+ "Reported GLX version %d, should be at least 13 "
+ "according to Linux GL ABI\n",
+ version);
+ return false;
+ }
+
+ version_string = glXQueryServerString(dpy, 0, GLX_VERSION);
+ ret = sscanf(version_string, "%d.%d", &server_major, &server_minor);
+ assert(ret == 2);
+ server = server_major * 10 + server_minor;
+
+ version_string = glXGetClientString(dpy, GLX_VERSION);
+ ret = sscanf(version_string, "%d.%d", &client_major, &client_minor);
+ assert(ret == 2);
+ client = client_major * 10 + client_minor;
+
+ if (client < server)
+ expected = client;
+ else
+ expected = server;
+
+ if (version != expected) {
+ fprintf(stderr,
+ "Reported GLX version %d, should be %d (%s)\n",
+ version, expected, version_string);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+test_glx_extension_supported(void)
+{
+ if (!epoxy_has_glx_extension(dpy, 0, "GLX_ARB_get_proc_address")) {
+ fputs("Incorrectly reported no support for GLX_ARB_get_proc_address "
+ "(should always be present in Linux ABI)\n",
+ stderr);
+ return false;
+ }
+
+ if (epoxy_has_glx_extension(dpy, 0, "GLX_EXT_ham_sandwich")) {
+ fputs("Incorrectly reported support for GLX_EXT_ham_sandwich\n",
+ stderr);
+ return false;
+ }
+
+ return true;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+
+ dpy = get_display_or_skip();
+ make_glx_context_current_or_skip(dpy);
+
+ pass = test_gl_version() && pass;
+ pass = test_glx_version() && pass;
+ pass = test_glx_extension_supported() && pass;
+
+ return pass != true;
+}
diff --git a/test/glx_public_api_core.c b/test/glx_public_api_core.c
new file mode 100644
index 0000000..f5a4f04
--- /dev/null
+++ b/test/glx_public_api_core.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <err.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+
+#include "glx_common.h"
+
+static Display *dpy;
+
+static bool
+test_has_extensions(void)
+{
+ int num_extensions;
+
+ glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
+
+ for (int i = 0; i < num_extensions; i++) {
+ char *ext = (char *)glGetStringi(GL_EXTENSIONS, i);
+
+ if (!epoxy_has_gl_extension(ext)) {
+ fprintf(stderr, "GL implementation reported support for %s, "
+ "but epoxy didn't\n", ext);
+ return false;
+ }
+ }
+
+ if (epoxy_has_gl_extension("GL_ARB_ham_sandwich")) {
+ fputs("epoxy implementation reported support for "
+ "GL_ARB_ham_sandwich, but it shouldn't\n",
+ stderr);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+test_gl_version(void)
+{
+ int gl_version, epoxy_version;
+ int major, minor;
+
+ glGetIntegerv(GL_MAJOR_VERSION, &major);
+ glGetIntegerv(GL_MINOR_VERSION, &minor);
+ gl_version = major * 10 + minor;
+
+ if (gl_version < 32) {
+ fprintf(stderr,
+ "Implementation reported GL version %d, should be at least 32\n",
+ gl_version);
+ return false;
+ }
+
+ epoxy_version = epoxy_gl_version();
+ if (epoxy_version != gl_version) {
+ fprintf(stderr,
+ "Epoxy reported GL version %d, should be %d\n",
+ epoxy_version, gl_version);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+test_glx_version(void)
+{
+ int version = epoxy_glx_version(dpy, 0);
+ const char *version_string;
+ int ret;
+ int server_major, server_minor;
+ int client_major, client_minor;
+ int server, client, expected;
+
+ if (version < 13) {
+ fprintf(stderr,
+ "Reported GLX version %d, should be at least 13 "
+ "according to Linux GL ABI\n",
+ version);
+ return false;
+ }
+
+ version_string = glXQueryServerString(dpy, 0, GLX_VERSION);
+ ret = sscanf(version_string, "%d.%d", &server_major, &server_minor);
+ assert(ret == 2);
+ server = server_major * 10 + server_minor;
+
+ version_string = glXGetClientString(dpy, GLX_VERSION);
+ ret = sscanf(version_string, "%d.%d", &client_major, &client_minor);
+ assert(ret == 2);
+ client = client_major * 10 + client_minor;
+
+ if (client < server)
+ expected = client;
+ else
+ expected = server;
+
+ if (version != expected) {
+ fprintf(stderr,
+ "Reported GLX version %d, should be %d (%s)\n",
+ version, expected, version_string);
+ return false;
+ }
+
+ return true;
+}
+
+static int
+error_handler(Display *d, XErrorEvent *ev)
+{
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+ XVisualInfo *visinfo;
+ Window win;
+ GLXFBConfig config;
+ static const int attribs[] = {
+ GLX_CONTEXT_PROFILE_MASK_ARB,
+ GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+ GLX_CONTEXT_MAJOR_VERSION_ARB,
+ 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB,
+ 2,
+ None
+ };
+ GLXContext ctx;
+ int (*old_handler)(Display *, XErrorEvent *);
+
+ dpy = get_display_or_skip();
+
+ if (!epoxy_has_glx_extension(dpy, 0, "GLX_ARB_create_context_profile"))
+ errx(77, "Test requires GLX_ARB_create_context_profile");
+
+ visinfo = get_glx_visual(dpy);
+ win = get_glx_window(dpy, visinfo, false);
+ config = get_fbconfig_for_visinfo(dpy, visinfo);
+
+ old_handler = XSetErrorHandler(error_handler);
+ ctx = glXCreateContextAttribsARB(dpy, config, NULL, True, attribs);
+ if (ctx == None)
+ errx(77, "glXCreateContext failed");
+ XSetErrorHandler(old_handler);
+
+ glXMakeCurrent(dpy, win, ctx);
+
+ pass = test_gl_version() && pass;
+ pass = test_glx_version() && pass;
+ pass = test_has_extensions() && pass;
+
+ return pass != true;
+}
diff --git a/test/glx_static.c b/test/glx_static.c
new file mode 100644
index 0000000..1466f55
--- /dev/null
+++ b/test/glx_static.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file glx_static.c
+ *
+ * Simple touch-test of using epoxy when linked statically. On Linux,
+ * the ifunc support we'd like to use has some significant behavior
+ * changes depending on whether it's a static build or shared library
+ * build.
+ *
+ * Note that if configured without --enable-static, this test will end
+ * up dynamically linked anyway, defeating the test.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "epoxy/gl.h"
+#include "epoxy/glx.h"
+#include <X11/Xlib.h>
+#include <dlfcn.h>
+
+#include "glx_common.h"
+
+int
+main(int argc, char **argv)
+{
+ bool pass = true;
+ int val;
+
+#if NEEDS_TO_BE_STATIC
+ if (dlsym(NULL, "epoxy_glCompileShader")) {
+ fputs("glx_static requires epoxy built with --enable-static\n", stderr);
+ return 77;
+ }
+#endif
+
+ Display *dpy = get_display_or_skip();
+ make_glx_context_current_or_skip(dpy);
+
+ glEnable(GL_LIGHTING);
+ val = 0;
+ glGetIntegerv(GL_LIGHTING, &val);
+ if (!val) {
+ fputs("Enabling GL_LIGHTING didn't stick.\n", stderr);
+ pass = false;
+ }
+
+ return pass != true;
+}
diff --git a/test/headerguards.c b/test/headerguards.c
new file mode 100644
index 0000000..c5e5e69
--- /dev/null
+++ b/test/headerguards.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <epoxy/gl.h>
+
+#ifdef BUILD_EGL
+#include <epoxy/egl.h>
+#include <epoxy/egl.h>
+#endif
+
+#ifdef BUILD_GLX
+#include <epoxy/glx.h>
+#include <epoxy/glx.h>
+#endif
+
+#ifdef BUILD_EGL
+#include <EGL/egl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <EGL/eglext.h>
+#endif
+
+#ifdef BUILD_GLX
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#else
+#include <GL/gl.h>
+#include <GL/glext.h>
+#endif
+#include <GL/glx.h>
+#include <GL/glxext.h>
+#endif
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
diff --git a/test/khronos_typedefs.c b/test/khronos_typedefs.c
new file mode 100644
index 0000000..f28fb67
--- /dev/null
+++ b/test/khronos_typedefs.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "khronos_typedefs.h"
+#include "epoxy/gl.h"
+
+#define COMPARE_SIZE(type) \
+ do { \
+ if (sizeof(type) != system_sizes[type ## _slot]) { \
+ fprintf(stderr, "system %s is size %d, epoxy is %d\n", \
+ #type, \
+ (int)system_sizes[type ## _slot], \
+ (int)sizeof(type)); \
+ error = true; \
+ } \
+} while (0)
+
+int
+main(int argc, char **argv)
+{
+ uint32_t system_sizes[khronos_typedef_count];
+ bool error = false;
+
+ get_system_typedef_sizes(system_sizes);
+
+ COMPARE_SIZE(khronos_int8_t);
+ COMPARE_SIZE(khronos_uint8_t);
+ COMPARE_SIZE(khronos_int16_t);
+ COMPARE_SIZE(khronos_uint16_t);
+ COMPARE_SIZE(khronos_int32_t);
+ COMPARE_SIZE(khronos_uint32_t);
+ COMPARE_SIZE(khronos_int64_t);
+ COMPARE_SIZE(khronos_uint64_t);
+ COMPARE_SIZE(khronos_intptr_t);
+ COMPARE_SIZE(khronos_uintptr_t);
+ COMPARE_SIZE(khronos_ssize_t);
+ COMPARE_SIZE(khronos_usize_t);
+ COMPARE_SIZE(khronos_float_t);
+ COMPARE_SIZE(khronos_utime_nanoseconds_t);
+ COMPARE_SIZE(khronos_stime_nanoseconds_t);
+ COMPARE_SIZE(khronos_boolean_enum_t);
+
+ return error;
+}
diff --git a/test/khronos_typedefs.h b/test/khronos_typedefs.h
new file mode 100644
index 0000000..bcb4dab
--- /dev/null
+++ b/test/khronos_typedefs.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+enum typedef_slot {
+ khronos_int8_t_slot,
+ khronos_uint8_t_slot,
+ khronos_int16_t_slot,
+ khronos_uint16_t_slot,
+ khronos_int32_t_slot,
+ khronos_uint32_t_slot,
+ khronos_int64_t_slot,
+ khronos_uint64_t_slot,
+ khronos_intptr_t_slot,
+ khronos_uintptr_t_slot,
+ khronos_ssize_t_slot,
+ khronos_usize_t_slot,
+ khronos_float_t_slot,
+ /* khrplatform.h claims it defines khronos_time_ns_t, but it doesn't. */
+ khronos_utime_nanoseconds_t_slot,
+ khronos_stime_nanoseconds_t_slot,
+ khronos_boolean_enum_t_slot,
+ khronos_typedef_count
+};
+
+void get_system_typedef_sizes(uint32_t *sizes);
diff --git a/test/khronos_typedefs_nonepoxy.c b/test/khronos_typedefs_nonepoxy.c
new file mode 100644
index 0000000..d249545
--- /dev/null
+++ b/test/khronos_typedefs_nonepoxy.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "khronos_typedefs.h"
+
+#ifdef HAVE_KHRPLATFORM_H
+
+#include <KHR/khrplatform.h>
+
+#define GET_SIZE(type) sizes[type ## _slot] = sizeof(type)
+
+void
+get_system_typedef_sizes(uint32_t *sizes)
+{
+ GET_SIZE(khronos_int8_t);
+ GET_SIZE(khronos_uint8_t);
+ GET_SIZE(khronos_int16_t);
+ GET_SIZE(khronos_uint16_t);
+ GET_SIZE(khronos_int32_t);
+ GET_SIZE(khronos_uint32_t);
+ GET_SIZE(khronos_int64_t);
+ GET_SIZE(khronos_uint64_t);
+ GET_SIZE(khronos_intptr_t);
+ GET_SIZE(khronos_uintptr_t);
+ GET_SIZE(khronos_ssize_t);
+ GET_SIZE(khronos_usize_t);
+ GET_SIZE(khronos_float_t);
+ GET_SIZE(khronos_utime_nanoseconds_t);
+ GET_SIZE(khronos_stime_nanoseconds_t);
+ GET_SIZE(khronos_boolean_enum_t);
+}
+
+#else /* !HAVE_KHRPLATFORM_H */
+
+/* Don't care -- this is a conditional case in test code. */
+#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
+
+void
+get_system_typedef_sizes(uint32_t *sizes)
+{
+ fputs("./configure failed to find khrplatform.h\n", stderr);
+ exit(77);
+}
+
+#endif
diff --git a/test/meson.build b/test/meson.build
new file mode 100644
index 0000000..862d57a
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,184 @@
+dl_dep = cc.find_library('dl', required: false)
+has_dlvsym = cc.has_function('dlvsym', dependencies: dl_dep)
+
+has_gles1 = gles1_dep.found()
+has_gles2 = gles2_dep.found()
+build_x11_tests = enable_x11 and x11_dep.found()
+
+test_cflags = common_cflags
+if not has_dlvsym
+test_cflags += [
+ '-D_XOPEN_SOURCE',
+ '-D_POSIX_C_SOURCE=200809L',
+]
+endif
+
+# Unconditionally built tests
+test('header_guards',
+ executable('header guards', 'headerguards.c',
+ c_args: common_cflags,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc))
+test('misc_defines',
+ executable('misc defines', 'miscdefines.c',
+ c_args: common_cflags,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc))
+test('khronos_typedefs',
+ executable('khronos typedefs', [
+ 'khronos_typedefs.c',
+ 'khronos_typedefs.h',
+ 'khronos_typedefs_nonepoxy.c',
+ ],
+ c_args: common_cflags,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc))
+test('gl_version',
+ executable('gl_version',
+ 'gl_version.c',
+ c_args: common_cflags,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc))
+
+if build_egl and build_x11_tests
+ egl_common_sources = [ 'egl_common.h', 'egl_common.c', ]
+ egl_common_lib = static_library('egl_common',
+ sources: egl_common_sources,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc,
+ c_args: common_cflags,
+ install: false)
+
+ egl_tests = [
+ [ 'egl_has_extension_nocontext', [], [ 'egl_has_extension_nocontext.c' ], true, ],
+ [ 'egl_epoxy_api', [], [ 'egl_epoxy_api.c' ], true ],
+ [ 'egl_gles1_without_glx', [ '-DGLES_VERSION=1', ], [ 'egl_without_glx.c' ], has_gles1, ],
+ [ 'egl_gles2_without_glx', [ '-DGLES_VERSION=2', ], [ 'egl_without_glx.c' ], has_gles2, ],
+ ]
+
+ if build_glx
+ egl_tests += [
+ [ 'egl_gl', [], [ 'egl_gl.c' ], true, ],
+ ]
+ endif
+
+ foreach test: egl_tests
+ test_name = test[0]
+ test_source = test[2]
+ test_args = test[1]
+ test_run = test[3]
+
+ if test_run
+ test_bin = executable(test_name, test_source,
+ c_args: test_cflags + test_args,
+ include_directories: libepoxy_inc,
+ dependencies: [ libepoxy_dep, x11_dep, egl_dep, dl_dep ],
+ link_with: egl_common_lib,
+ link_args: '-rdynamic')
+ test(test_name, test_bin)
+ endif
+ endforeach
+endif
+
+if build_glx and build_x11_tests
+ glx_common_sources = [ 'glx_common.h', 'glx_common.c', ]
+ glx_common_lib = static_library('glx_common',
+ sources: glx_common_sources,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc,
+ c_args: common_cflags,
+ install: false)
+
+ # glx_beginend links directly with the GL library, so we need to check it
+ # separately
+ test('glx_beginend', executable('glx_beginend', 'glx_beginend.c',
+ c_args: test_cflags,
+ include_directories: libepoxy_inc,
+ dependencies: [ libepoxy_dep, x11_dep, gl_dep, dl_dep ],
+ link_with: glx_common_lib))
+
+ glx_tests = [
+ [ 'glx_public_api', [ 'glx_public_api.c' ], [], [], true ],
+ [ 'glx_public_api_core', [ 'glx_public_api_core.c' ], [], [], true ],
+ [ 'glx_glxgetprocaddress_nocontext', [ 'glx_glxgetprocaddress_nocontext.c' ], [], [], true ],
+ [ 'glx_has_extension_nocontext', [ 'glx_has_extension_nocontext.c' ], [], [], true ],
+ [ 'glx_static', [ 'glx_static.c' ], [ '-DNEEDS_TO_BE_STATIC'], [ '-static' ], libtype == 'static' ],
+ [ 'glx_shared_znow', [ 'glx_static.c', ], [], [ '-Wl,-z,now' ], has_znow ],
+ [ 'glx_alias_prefer_same_name', [ 'glx_alias_prefer_same_name.c', 'dlwrap.c', 'dlwrap.h' ], [], [ '-rdynamic' ], has_dlvsym ],
+ [ 'glx_gles2', [ 'glx_gles2.c', 'dlwrap.c', 'dlwrap.h' ], [], [ '-rdynamic' ], has_dlvsym ],
+ ]
+
+ foreach test: glx_tests
+ test_name = test[0]
+ test_source = test[1]
+ test_c_args = test[2]
+ test_link_args = test[3]
+ test_run = test[4]
+
+ if test_run
+ test_bin = executable(test_name, test_source,
+ c_args: test_cflags + test_c_args,
+ include_directories: libepoxy_inc,
+ dependencies: [ libepoxy_dep, x11_dep, dl_dep ],
+ link_with: glx_common_lib,
+ link_args: test_link_args)
+ test(test_name, test_bin)
+ endif
+ endforeach
+endif
+
+# WGL
+if build_wgl
+ wgl_common_sources = [ 'wgl_common.h', 'wgl_common.c', ]
+ wgl_common_lib = static_library('wgl_common',
+ sources: wgl_common_sources,
+ dependencies: libepoxy_dep,
+ include_directories: libepoxy_inc,
+ c_args: common_cflags,
+ install: false)
+
+ wgl_tests = [
+ [ 'wgl_core_and_exts', [ 'wgl_core_and_exts.c' ], [], ],
+ [ 'wgl_per_context_funcptrs', [ 'wgl_per_context_funcptrs.c' ], [], ],
+ [ 'wgl_usefontbitmaps', [ 'wgl_usefontbitmaps.c'], [], ],
+ [ 'wgl_usefontbitmaps_unicode', [ 'wgl_usefontbitmaps.c' ], [ '-DUNICODE' ], ],
+ ]
+
+ foreach test: wgl_tests
+ test_name = test[0]
+ test_source = test[1]
+ test_c_args = test[2]
+
+ test_bin = executable(test_name, test_source,
+ c_args: test_cflags + test_c_args,
+ include_directories: libepoxy_inc,
+ dependencies: [ libepoxy_dep ],
+ link_with: wgl_common_lib)
+
+ test(test_name, test_bin)
+ endforeach
+endif
+
+# Apple
+if host_machine.system().contains('darwin')
+ opengl_dep = dependency('appleframeworks', modules: ['OpenGL', 'Carbon'], required: true)
+
+ cgl_tests = [
+ [ 'cgl_core', [ 'cgl_core.c' ] ],
+ [ 'cgl_epoxy_api', [ 'cgl_epoxy_api.c' ] ],
+ ]
+
+ foreach t: cgl_tests
+ test_name = t[0]
+ test_sources = t[1]
+
+ test(test_name,
+ executable(
+ test_name, test_sources,
+ c_args: test_cflags,
+ include_directories: libepoxy_inc,
+ dependencies: [ libepoxy_dep, opengl_dep ],
+ ),
+ )
+ endforeach
+endif
diff --git a/test/miscdefines.c b/test/miscdefines.c
new file mode 100644
index 0000000..e4bc79a
--- /dev/null
+++ b/test/miscdefines.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <epoxy/gl.h>
+
+#ifdef BUILD_EGL
+#include <epoxy/egl.h>
+#endif
+
+#ifdef BUILD_GLX
+#include <epoxy/glx.h>
+#endif
+
+#if GL_VERSION_3_2 != 1
+#error bad GL_VERSION_3_2
+#endif
+
+#if GL_ARB_ES2_compatibility != 1
+#error bad GL_ARB_ES2_compatibility
+#endif
+
+#ifndef GLAPI
+#error missing GLAPI
+#endif
+
+#ifndef GLAPIENTRY
+#error missing GLAPIENTRY
+#endif
+
+#ifndef GLAPIENTRYP
+#error missing GLAPIENTRYP
+#endif
+
+#ifndef APIENTRY
+#error missing APIENTRY
+#endif
+
+#ifndef APIENTRYP
+#error missing APIENTRYP
+#endif
+
+/* Do we want to export GL_GLEXT_VERSION? */
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
diff --git a/test/wgl_common.c b/test/wgl_common.c
new file mode 100644
index 0000000..e8d9c26
--- /dev/null
+++ b/test/wgl_common.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <epoxy/wgl.h>
+#include "wgl_common.h"
+
+static int (*test_callback)(HDC hdc);
+
+static void
+setup_pixel_format(HDC hdc)
+{
+ PIXELFORMATDESCRIPTOR pfd = {
+ sizeof(PIXELFORMATDESCRIPTOR),
+ 1,
+ PFD_SUPPORT_OPENGL |
+ PFD_DRAW_TO_WINDOW |
+ PFD_DOUBLEBUFFER,
+ PFD_TYPE_RGBA,
+ 32,
+ 0, 0, 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0,
+ 16,
+ 0,
+ 0,
+ PFD_MAIN_PLANE,
+ 0,
+ 0, 0, 0,
+ };
+ int pixel_format;
+
+ pixel_format = ChoosePixelFormat(hdc, &pfd);
+ if (!pixel_format) {
+ fputs("ChoosePixelFormat failed.\n", stderr);
+ exit(1);
+ }
+
+ if (SetPixelFormat(hdc, pixel_format, &pfd) != TRUE) {
+ fputs("SetPixelFormat() failed.\n", stderr);
+ exit(1);
+ }
+}
+
+static LRESULT CALLBACK
+window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ HDC hdc = GetDC(hwnd);
+ int ret;
+
+ switch (message) {
+ case WM_CREATE:
+ setup_pixel_format(hdc);
+ ret = test_callback(hdc);
+ ReleaseDC(hwnd, hdc);
+ exit(ret);
+ return 0;
+ default:
+ return DefWindowProc(hwnd, message, wparam, lparam);
+ }
+}
+
+void
+make_window_and_test(int (*callback)(HDC hdc))
+{
+ const char *class_name = "epoxy";
+ const char *window_name = "epoxy";
+ int width = 150;
+ int height = 150;
+ HWND hwnd;
+ HINSTANCE hcurrentinst = NULL;
+ WNDCLASS window_class;
+ MSG msg;
+
+ test_callback = callback;
+
+ memset(&window_class, 0, sizeof(window_class));
+ window_class.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+ window_class.lpfnWndProc = window_proc;
+ window_class.cbClsExtra = 0;
+ window_class.cbWndExtra = 0;
+ window_class.hInstance = hcurrentinst;
+ window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ window_class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ window_class.lpszMenuName = NULL;
+ window_class.lpszClassName = class_name;
+ if (!RegisterClass(&window_class)) {
+ fputs("Failed to register window class\n", stderr);
+ exit(1);
+ }
+
+ /* create window */
+ hwnd = CreateWindow(class_name, window_name,
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, width, height,
+ NULL, NULL, hcurrentinst, NULL);
+
+ ShowWindow(hwnd, SW_SHOWDEFAULT);
+ UpdateWindow(hwnd);
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
diff --git a/test/wgl_common.h b/test/wgl_common.h
new file mode 100644
index 0000000..8b13d96
--- /dev/null
+++ b/test/wgl_common.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <epoxy/wgl.h>
+
+void
+make_window_and_test(int (*callback)(HDC hdc));
diff --git a/test/wgl_core_and_exts.c b/test/wgl_core_and_exts.c
new file mode 100644
index 0000000..7d22acc
--- /dev/null
+++ b/test/wgl_core_and_exts.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "wgl_common.h"
+#include <epoxy/gl.h>
+
+static int
+test_function(HDC hdc)
+{
+ bool pass = true;
+ int val;
+ HGLRC ctx;
+
+ ctx = wglCreateContext(hdc);
+ if (!ctx) {
+ fputs("Failed to create wgl context\n", stderr);
+ return 1;
+ }
+ if (!wglMakeCurrent(hdc, ctx)) {
+ fputs("Failed to make context current\n", stderr);
+ return 1;
+ }
+
+ /* GL 1.0 APIs are available as symbols in opengl32.dll. */
+ glEnable(GL_LIGHTING);
+ val = 0;
+ glGetIntegerv(GL_LIGHTING, &val);
+ if (!val) {
+ fputs("Enabling GL_LIGHTING didn't stick.\n", stderr);
+ pass = false;
+ }
+
+ if (epoxy_gl_version() >= 15 ||
+ epoxy_has_gl_extension("GL_ARB_vertex_buffer_object")) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 1234);
+
+ val = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &val);
+ if (val != 1234) {
+ printf("GL_ELEMENT_ARRAY_BUFFER_BINDING didn't stick: %d\n", val);
+ pass = false;
+ }
+ }
+
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx);
+
+ return !pass;
+}
+
+int
+main(int argc, char **argv)
+{
+ make_window_and_test(test_function);
+
+ /* UNREACHED */
+ return 1;
+}
diff --git a/test/wgl_per_context_funcptrs.c b/test/wgl_per_context_funcptrs.c
new file mode 100644
index 0000000..2cf0dcb
--- /dev/null
+++ b/test/wgl_per_context_funcptrs.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * @file wgl_per_context_funcptrs.c
+ *
+ * Tests that epoxy works correctly when wglGetProcAddress() returns
+ * different function pointers for different contexts.
+ *
+ * wgl allows that to be the case when the device or pixel format are
+ * different. We don't know if the underlying implementation actually
+ * *will* return different function pointers, so force the issue by
+ * overriding wglGetProcAddress() to return our function pointers with
+ * magic behavior. This way we can test epoxy's implementation
+ * regardless.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "wgl_common.h"
+#include <epoxy/gl.h>
+
+#define CREATESHADER_CTX1_VAL 1001
+#define CREATESHADER_CTX2_VAL 1002
+
+static HGLRC ctx1, ctx2, current_context;
+static bool pass = true;
+
+#define OVERRIDE_API(type) __declspec(dllexport) type __stdcall
+
+OVERRIDE_API (GLuint) override_glCreateShader_ctx1(GLenum target);
+OVERRIDE_API (GLuint) override_glCreateShader_ctx2(GLenum target);
+OVERRIDE_API (PROC) override_wglGetProcAddress(LPCSTR name);
+
+OVERRIDE_API (GLuint)
+override_glCreateShader_ctx1(GLenum target)
+{
+ if (current_context != ctx1) {
+ fputs("ctx1 called while other context current\n", stderr);
+ pass = false;
+ }
+ return CREATESHADER_CTX1_VAL;
+}
+
+OVERRIDE_API (GLuint)
+override_glCreateShader_ctx2(GLenum target)
+{
+ if (current_context != ctx2) {
+ fputs("ctx2 called while other context current\n", stderr);
+ pass = false;
+ }
+ return CREATESHADER_CTX2_VAL;
+}
+
+OVERRIDE_API (PROC)
+override_wglGetProcAddress(LPCSTR name)
+{
+ assert(strcmp(name, "glCreateShader") == 0);
+
+ if (current_context == ctx1) {
+ return (PROC)override_glCreateShader_ctx1;
+ } else {
+ assert(current_context == ctx2);
+ return (PROC)override_glCreateShader_ctx2;
+ }
+}
+
+static void
+test_createshader(HDC hdc, HGLRC ctx)
+{
+ GLuint shader, expected;
+ int ctxnum;
+
+ wglMakeCurrent(hdc, ctx);
+ current_context = ctx;
+
+ /* Install our GPA override so we can force per-context function
+ * pointers.
+ */
+ wglGetProcAddress = override_wglGetProcAddress;
+
+ if (ctx == ctx1) {
+ expected = CREATESHADER_CTX1_VAL;
+ ctxnum = 1;
+ } else {
+ assert(ctx == ctx2);
+ expected = CREATESHADER_CTX2_VAL;
+ ctxnum = 2;
+ }
+
+ shader = glCreateShader(GL_FRAGMENT_SHADER);
+ printf("ctx%d: Returned %d\n", ctxnum, shader);
+ if (shader != expected) {
+ fprintf(stderr, " expected %d\n", expected);
+ pass = false;
+ }
+}
+
+static int
+test_function(HDC hdc)
+{
+ ctx1 = wglCreateContext(hdc);
+ ctx2 = wglCreateContext(hdc);
+ if (!ctx1 || !ctx2) {
+ fputs("Failed to create wgl contexts\n", stderr);
+ return 1;
+ }
+
+ if (!wglMakeCurrent(hdc, ctx1)) {
+ fputs("Failed to make context current\n", stderr);
+ return 1;
+ }
+
+ if (epoxy_gl_version() < 20) {
+ /* We could possibly do a 1.3 entrypoint or something instead. */
+ fputs("Test relies on overriding a GL 2.0 entrypoint\n", stderr);
+ return 77;
+ }
+
+ /* Force resolving epoxy_wglGetProcAddress. */
+ wglGetProcAddress("glCreateShader");
+
+ test_createshader(hdc, ctx1);
+ test_createshader(hdc, ctx1);
+ test_createshader(hdc, ctx2);
+ test_createshader(hdc, ctx2);
+ test_createshader(hdc, ctx1);
+ test_createshader(hdc, ctx2);
+
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx1);
+ wglDeleteContext(ctx2);
+
+ return !pass;
+}
+
+int
+main(int argc, char **argv)
+{
+ make_window_and_test(test_function);
+
+ /* UNREACHED */
+ return 1;
+}
diff --git a/test/wgl_usefontbitmaps.c b/test/wgl_usefontbitmaps.c
new file mode 100644
index 0000000..d54e1ee
--- /dev/null
+++ b/test/wgl_usefontbitmaps.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "wgl_common.h"
+#include <epoxy/gl.h>
+
+static int
+test_function(HDC hdc)
+{
+ bool pass = true;
+ HGLRC ctx;
+ GLuint dlist[2] = {100, 101};
+ const char *string = "some string";
+
+ ctx = wglCreateContext(hdc);
+ if (!ctx) {
+ fputs("Failed to create wgl context\n", stderr);
+ return 1;
+ }
+ if (!wglMakeCurrent(hdc, ctx)) {
+ fputs("Failed to make context current\n", stderr);
+ return 1;
+ }
+
+ /* First, use the #ifdeffed variant of the function */
+ wglUseFontBitmaps(hdc, 0, 255, dlist[0]);
+ glListBase(dlist[1]);
+ glCallLists(strlen(string), GL_UNSIGNED_BYTE, string);
+
+ /* Now, use the specific version, manually. */
+#ifdef UNICODE
+ wglUseFontBitmapsW(hdc, 0, 255, dlist[0]);
+#else
+ wglUseFontBitmapsA(hdc, 0, 255, dlist[0]);
+#endif
+ glListBase(dlist[1]);
+ glCallLists(strlen(string), GL_UNSIGNED_BYTE, string);
+
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx);
+
+ return !pass;
+}
+
+int
+main(int argc, char **argv)
+{
+ make_window_and_test(test_function);
+
+ /* UNREACHED */
+ return 1;
+}